青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 4,  comments - 27,  trackbacks - 0
    前些天花了很多時(shí)間寫(xiě)這樣一個(gè)軟鍵盤(pán),效果是顯示一個(gè)與鍵盤(pán)外觀相似的視圖,通過(guò)鼠標(biāo)單擊像活動(dòng)窗口發(fā)送虛擬的鍵盤(pán)消息。目標(biāo)是實(shí)現(xiàn)像windows自帶的軟鍵盤(pán)osk相似。
    看似很簡(jiǎn)單的工作,設(shè)計(jì)中卻遇到了很多困難。
    困難一:鍵盤(pán)按鍵分類
        鍵盤(pán)按鍵有很多種分類方法。
        第一種:按顯示分類。按住shift鍵,字母鍵、符號(hào)鍵顯示上面的字符;按下caps lock鍵,字母鍵切換為大寫(xiě)字母。
        第二種:按功能分類。大體有可顯示字符類、控制類。控制類包括shift,ctrl等。
        為了解決可變的顯示問(wèn)題,采用了一個(gè)自我感覺(jué)非常好的解決方案:字符集、鍵集相互獨(dú)立。如此一來(lái),只要總體按照功能分類,通過(guò)特定功能的按鍵控制有效字符集即可,也就是說(shuō),對(duì)普通按鍵來(lái)說(shuō),它只負(fù)責(zé)到指定的字符集中去取對(duì)應(yīng)序號(hào)的字符即可。
//LabelSet.h
#pragma once

//字母標(biāo)簽集合
class LabelSet
{
public:
    LabelSet(LPCSTR
* _pTable,int _n);
    LPCSTR getLabel(
int _id) const;

    
~LabelSet();

protected:
    LabelSet(){}

private:
    LPCSTR
* pTable;
    
int n;
};

//相當(dāng)于單刀雙擲開(kāi)關(guān)組
class LabelSetEx
{
protected:
    
struct Switch
    {
        LabelSet
* s[2];
        
int at;
    };

public:
    LabelSetEx(
int _n);
    
bool addSets(int id,LPCSTR* s1,LPCSTR* s2,int n,int at = 0);
    LPCSTR getLable(
int id,int off) const;
    
void turn(int id);

    
~LabelSetEx();

private:
    
int n;    //開(kāi)關(guān)組總個(gè)數(shù)
    Switch* pGroup;    //開(kāi)關(guān)組
};

//
//LabelSet.cpp
#include "StdAfx.h"
#include 
"LabelSet.h"
#include 
<algorithm>
#include 
<cassert>

using namespace std;

LabelSet::LabelSet( LPCSTR
* _pTable,int _n )
{
    n 
= _n;
    pTable 
= new LPCSTR[n];
    copy(_pTable,_pTable 
+ _n,pTable);
}

LPCSTR LabelSet::getLabel( 
int _id ) const
{
    
return pTable[_id];
}

LabelSet::
~LabelSet()
{
    delete [] pTable;
}

LabelSetEx::LabelSetEx( 
int _n )
{
    n 
= _n;
    pGroup 
= new Switch[n];
    memset(pGroup,
0,n * sizeof(pGroup[0]));
}

LabelSetEx::
~LabelSetEx()
{
    
while(n--)
    {
        
if(pGroup[n].s[0== pGroup[n].s[1])
            delete pGroup[n].s[
0];
        
else
        {
            delete pGroup[n].s[
0];
            delete pGroup[n].s[
1];
        }
    }
    delete [] pGroup;
}

bool LabelSetEx::addSets( int id,LPCSTR* s1,LPCSTR* s2,int n,int at /*= 0*/ )
{
    assert((at 
& ~1== 0);
    
if(pGroup[id].s[0!= NULL)
        
return false;
    LabelSet
* p = new LabelSet(s1,n);
    pGroup[id].s[
0= p;
    
if(s1 == s2)
        pGroup[id].s[
1= p;
    
else
        pGroup[id].s[
1= new LabelSet(s2,n);
    pGroup[id].at 
= at;
    
return true;
}

LPCSTR LabelSetEx::getLable( 
int id,int off ) const
{
    Switch
* p = pGroup + id;
    
return p->s[p->at]->getLabel(off);
}

void LabelSetEx::turn( int id )
{
    assert((pGroup
->at & ~1== 0);
    pGroup[id].at 
^= 1;
}
        以上取開(kāi)關(guān)的索引id是指字符集的分類id,在config.h文件下定義了這樣的id
#pragma once

//分類id的定義
#define LABEL_SET_ALPHA  0
#define LABEL_SET_SYMBOL 1
#define LABEL_SET_NUMPAD 2
#define LABEL_SET_MAIN   3
#define LABEL_SET_HELP   4

//字母串表
extern LPCSTR AlphaTable1[];    //小寫(xiě)
extern LPCSTR AlphaTable2[];    //大寫(xiě)
extern const int AlphaTableSize;

//符號(hào)串表
extern LPCSTR SymbolTable1[];    //
extern LPCSTR SymbolTable2[];    //
extern const int SymbolTableSize;

//小鍵盤(pán)數(shù)字表
extern LPCSTR NumPadTable1[];    //數(shù)字
extern LPCSTR NumPadTable2[];    //光標(biāo)控制
extern const int NumPadTableSize;

//主鍵盤(pán)單顯
extern LPCSTR MainTable[];
extern const int MainTableSize;

//輔助鍵盤(pán)單顯
extern LPCSTR HelpTable[];
extern const int HelpTableSize;

struct KeyConfig
{
    
short id;        //分類id
    short offset;    //類內(nèi)偏移
    RECT rt;    //位置
    BYTE vk;    //虛擬碼
};

extern KeyConfig kcs[];
extern const int kcSize;
extern const SIZE kbSize;
        第一次這樣寫(xiě)代碼,寫(xiě)完發(fā)現(xiàn)這樣極大地提高了靈活性,只要在配置文件config.cpp中修改,就可以產(chǎn)生很多種不同的界面(雖然仍然是代碼級(jí)別的,畢竟邁出了第一步,今后還會(huì)嘗試改成xml配置)。
        言歸正傳,這樣的設(shè)計(jì)分離了按鍵與顯示,可配置能力大大加強(qiáng)。但仍然存在第二個(gè)大問(wèn)題。
    問(wèn)題二:輸入焦點(diǎn)的確定
        方案一:現(xiàn)在只要在網(wǎng)上搜索“虛擬鍵盤(pán)”,能夠搜到一大溜的源代碼,但只可惜全是同一份拷貝,而且存在一點(diǎn)小錯(cuò)誤。他的解決方案是:利用 PreTranslateMessage,在底層調(diào)用它之前,前臺(tái)窗口仍然沒(méi)有改變,此時(shí)是獲得前一個(gè)前臺(tái)窗口的好時(shí)機(jī),獲得后保存,并將使用 AttachThreadInput將當(dāng)前線程綁定活動(dòng)窗口的消息隊(duì)列,然后在單擊虛擬鍵盤(pán)時(shí)使用SetFocus將保存的窗口設(shè)為焦點(diǎn)(源代碼中同時(shí)使用了SetForgroundWindow和SetFocus,這是失效的原因),然后發(fā)送虛擬按鍵。

        方案二:其實(shí)有更簡(jiǎn)便的方法。設(shè)置主窗口屬性為WM_ES_NOACTIVATE,這樣窗口就不會(huì)成為前臺(tái)窗口,不管如何發(fā)送鍵盤(pán)消息,擁有焦點(diǎn)的窗口總會(huì)收到。但此時(shí)仍然存在問(wèn)題。當(dāng)移動(dòng)窗口時(shí),效果不大順暢,而且沒(méi)辦法響應(yīng)菜單命令,那是因?yàn)樵摯翱谑冀K不是前臺(tái)窗口造成的。解決方法就是在單擊標(biāo)題欄時(shí),成為前臺(tái)窗口,釋放是歸還前臺(tái)。

void CMainFrame::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
    
if(m_hForground == NULL)
    {
        m_hForground 
= ::GetForegroundWindow();
        ModifyStyleEx(WS_EX_NOACTIVATE,
0);
        SetForegroundWindow();
    }
    CFrameWnd::OnNcLButtonDown(nHitTest, point);
}
                但是,如果想當(dāng)然歸還前臺(tái)使用WM_NCLBUTTONUP消息的話,就要讓你失望了,windows似乎有意跟我們開(kāi)玩笑,必須單擊兩次才能響應(yīng)這個(gè)消息。沒(méi)辦法,于是嘗試WM_NCMOUSELEAVE,但效果也不好,最終嘗試WM_NCMOUSEMOVE,很好,這次終于成功了。
void CMainFrame::OnNcMouseMove(UINT nHitTest, CPoint point)
{
    
if(m_hForground != NULL)
    {
        ::SetForegroundWindow(m_hForground);
        ModifyStyleEx(
0,WS_EX_NOACTIVATE);
        m_hForground 
= NULL;
    }
    CFrameWnd::OnNcMouseMove(nHitTest, point);
}
        問(wèn)題到此為止,現(xiàn)在說(shuō)說(shuō)一點(diǎn)小小的發(fā)現(xiàn)。
        原本以為一般的按鍵就兩種狀態(tài),通過(guò)down、up改變,如果用方波描述,down就是下降沿觸發(fā),up是上升沿觸發(fā)。也曾了解,像shift這樣的按鍵會(huì)很復(fù)雜,存在多個(gè)狀態(tài)。后來(lái)測(cè)試發(fā)現(xiàn),shift并非一個(gè)特例,所有的按鍵都有4個(gè)狀態(tài),通過(guò)down、up改變狀態(tài)。只是不同按鍵對(duì)狀態(tài)的關(guān)注點(diǎn)不同。
        可以做這樣一個(gè)測(cè)試,用GetKeyboardState得到各個(gè)虛擬碼對(duì)應(yīng)的按鍵狀態(tài)。最高位為1時(shí)表示鍵被按下,最高位為1時(shí),如果是lock鍵則表示被鎖住,對(duì)于其他鍵,各有各的作用。
        比如一個(gè)鍵,用2位的二進(jìn)制數(shù)表示這些狀態(tài),設(shè)初始狀態(tài)為10,經(jīng)過(guò)down后,變?yōu)?1,經(jīng)過(guò)up后,變?yōu)?1,再經(jīng)過(guò)down后,變?yōu)?0,再經(jīng)過(guò)up后,變?yōu)?0,如此四個(gè)狀態(tài)經(jīng)過(guò)down、up實(shí)現(xiàn)了周期性的狀態(tài)裝換。大體符合這樣的規(guī)律:
            10-(down xor 11)->01->(up xor 10)->11-(down xor 11)->00(up xor 10)->10。
        這樣,如果虛擬得比較徹底,在虛擬鍵盤(pán)內(nèi)部可以輕易地實(shí)現(xiàn)狀態(tài)的記憶,并且可以獲得足夠的信息。對(duì)于顯示、控制都非常方便。

    這只是第一個(gè)版本,還有很多問(wèn)題需要解決。
    待解決問(wèn)題一:xml配置動(dòng)態(tài)配置鍵盤(pán),及動(dòng)態(tài)更換顯示效果。
    待解決問(wèn)題二:同步物理鍵盤(pán)。
    待解決問(wèn)題三:更深層次,防止鍵盤(pán)消息被hook,初步認(rèn)識(shí),似乎可以使用剪貼板。
   【源代碼1.2版本:http://m.shnenglu.com/Files/yefeng/VirtualKeyboard1.2.rar
posted on 2009-10-18 23:19 夜風(fēng) 閱讀(4768) 評(píng)論(6)  編輯 收藏 引用 所屬分類: C/C++技術(shù)windows程序設(shè)計(jì)

FeedBack:
# re: 虛擬鍵盤(pán)(軟鍵盤(pán))設(shè)計(jì)要點(diǎn)
2009-10-18 23:59 | expter
學(xué)習(xí)。。。  回復(fù)  更多評(píng)論
  
# re: 虛擬鍵盤(pán)(軟鍵盤(pán))設(shè)計(jì)要點(diǎn)
2009-10-19 00:11 | OwnWaterloo
1.要搜kbcwait4ibe,不要搜"虛擬鍵盤(pán)"。
2.以下劃線開(kāi)始的標(biāo)識(shí)符是C/C++語(yǔ)言所保留的啊,同學(xué)們……
  回復(fù)  更多評(píng)論
  
# re: 虛擬鍵盤(pán)(軟鍵盤(pán))設(shè)計(jì)要點(diǎn)
2009-10-19 00:20 | 夜風(fēng)
@OwnWaterloo
1.kbcwait4ibe是驅(qū)動(dòng)級(jí)別的哦,正打算開(kāi)始研究驅(qū)動(dòng)呢。。。
2.哦,是的,倒是沒(méi)注意這個(gè)。。。但這命名還真是個(gè)傷腦筋的問(wèn)題呢!  回復(fù)  更多評(píng)論
  
# re: 虛擬鍵盤(pán)(軟鍵盤(pán))設(shè)計(jì)要點(diǎn)
2009-10-19 14:51 | 淘寶皇冠店
學(xué)習(xí)技術(shù)!!  回復(fù)  更多評(píng)論
  
# re: 虛擬鍵盤(pán)(軟鍵盤(pán))設(shè)計(jì)要點(diǎn)
2009-10-19 20:56 | zhaoyg
學(xué)習(xí)  回復(fù)  更多評(píng)論
  
# re: 虛擬鍵盤(pán)(軟鍵盤(pán))設(shè)計(jì)要點(diǎn)
2009-10-22 09:29 | 李佳
寫(xiě)的挺好的 支持原創(chuàng) 樓主費(fèi)心了   回復(fù)  更多評(píng)論
  

只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


<2009年10月>
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

常用鏈接

留言簿(1)

隨筆分類(7)

隨筆檔案(4)

文章分類

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美高清成人| 亚洲无玛一区| 亚洲欧美日韩中文视频| 亚洲国产高清自拍| 91久久精品久久国产性色也91 | 久久国产综合精品| 香蕉久久国产| 久久嫩草精品久久久精品一| 欧美xart系列高清| 欧美视频手机在线| 国产亚洲精品福利| 尤物精品在线| 一区二区三区四区蜜桃| 欧美一区二区三区喷汁尤物| 久久中文字幕一区二区三区| 亚洲人成高清| 亚洲午夜国产一区99re久久 | 亚洲国产精品日韩| 夜夜嗨av色综合久久久综合网| 欧美亚洲在线观看| 欧美精品 国产精品| 国产精品丝袜久久久久久app| 一区视频在线看| 亚洲欧美在线一区| 欧美激情aⅴ一区二区三区| 一本色道久久99精品综合 | 欧美在线中文字幕| 欧美母乳在线| 黄色亚洲大片免费在线观看| 99精品视频免费全部在线| 久久精品一本| 夜夜夜久久久| 欧美二区不卡| 一区二区在线不卡| 香蕉国产精品偷在线观看不卡| 亚洲大片免费看| 久久岛国电影| 国产欧美精品在线| 夜夜嗨av一区二区三区网页| 麻豆精品在线视频| 午夜精品成人在线| 欧美午夜精品一区| 亚洲最新在线视频| 亚洲电影免费| 欧美成人午夜视频| 午夜在线电影亚洲一区| 欧美日韩久久不卡| 亚洲精品一二| 欧美成人午夜| 久久久噜噜噜久久狠狠50岁| 国产热re99久久6国产精品| 亚洲视频一区在线观看| 亚洲国产三级| 欧美激情一区二区三区成人| 亚洲国产你懂的| 欧美激情一区二区三区全黄| 久久综合久久综合九色| 国语自产在线不卡| 久久久美女艺术照精彩视频福利播放| 亚洲欧美日韩一区| 国产自产精品| 免费成人av在线| 亚洲欧美日韩精品久久奇米色影视 | 亚洲福利在线看| 欧美高清视频| 99国产精品99久久久久久| 亚洲国产精品欧美一二99| 欧美精品久久99久久在免费线| 亚洲精品综合精品自拍| 亚洲激情偷拍| 欧美午夜不卡视频| 午夜精品视频一区| 欧美一级久久久久久久大片| 很黄很黄激情成人| 欧美成人免费网站| 欧美黄色小视频| 亚洲中字黄色| 欧美在线观看一区二区| 狠狠色综合色综合网络| 欧美激情精品久久久久| 欧美日韩 国产精品| 亚洲一级在线| 久久精品国产视频| 亚洲美女av黄| 亚洲综合精品四区| 亚洲福利专区| 亚洲先锋成人| 亚洲大胆女人| 一本一本久久a久久精品综合麻豆| 国产精品国产三级国产普通话三级| 亚洲女人av| 久久躁狠狠躁夜夜爽| 一区二区久久久久久| 欧美伊人久久久久久久久影院| 亚洲国产精品专区久久| 中文亚洲免费| 亚洲激情二区| 午夜激情综合网| 在线亚洲观看| 久久天天综合| 亚洲欧美日韩国产中文| 免费成人黄色| 国产日韩精品一区二区浪潮av| 免费久久99精品国产自| 欧美深夜影院| 亚洲国产清纯| 狠狠狠色丁香婷婷综合激情| 亚洲精品乱码| 亚洲国产婷婷| 久久久久久9| 久久国产精品99国产精| 欧美日韩国产精品一区| 欧美a一区二区| 国产亚洲欧美日韩日本| 亚洲丝袜av一区| 日韩亚洲综合在线| 麻豆精品视频在线观看| 久久精品亚洲精品国产欧美kt∨| 欧美日韩一区二区在线| 亚洲经典一区| 亚洲激情社区| 久久久久久亚洲精品杨幂换脸| 欧美一区二区三区四区夜夜大片| 欧美日韩1区2区| 亚洲人体1000| 亚洲精品一区二区三区av| 玖玖玖国产精品| 欧美福利电影网| 亚洲区欧美区| 欧美国产日韩在线| 亚洲福利视频网站| 亚洲国产日韩综合一区| 久久九九热免费视频| 久久久久久网| 一区二区三区在线免费播放| 欧美在线一二三四区| 欧美有码视频| 国内外成人免费视频| 欧美一区二区三区视频| 欧美制服丝袜第一页| 国产九区一区在线| 欧美伊人久久| 欧美激情第3页| 日韩视频二区| 欧美日韩午夜激情| 亚洲网址在线| 久久激情五月激情| 一区二区在线看| 欧美好吊妞视频| 夜夜精品视频一区二区| 欧美一区二区三区日韩视频| 国产亚洲电影| 久久夜色精品国产亚洲aⅴ | 午夜久久tv| 国产一区二区高清视频| 久久久一二三| 亚洲日韩欧美视频一区| 亚洲欧美激情精品一区二区| 国产日韩视频| 免费久久99精品国产自在现线| 亚洲人体偷拍| 午夜一区二区三视频在线观看 | 亚洲国产1区| 欧美日本免费| 欧美一级视频| 91久久夜色精品国产网站| 亚洲欧美一区二区原创| 国产主播在线一区| 欧美日韩dvd在线观看| 午夜欧美大片免费观看| 国产一区视频在线观看免费| 老司机一区二区三区| 夜夜嗨一区二区三区| 开元免费观看欧美电视剧网站| 亚洲美女黄色片| 黄色免费成人| 国产精品二区影院| 麻豆乱码国产一区二区三区| 亚洲一区二区三区在线观看视频| 欧美激情一区二区三区成人| 久久精品综合| 亚洲欧美视频一区| 亚洲乱码精品一二三四区日韩在线| 国产精品美女诱惑| 欧美激情一区二区| 欧美在线关看| 亚洲无线一线二线三线区别av| 亚洲高清毛片| 久久夜色撩人精品| 欧美亚洲在线观看| 一区二区电影免费观看| 狠狠网亚洲精品| 国产日产欧产精品推荐色| 欧美三级特黄| 欧美金8天国| 欧美激情在线有限公司| 噜噜噜久久亚洲精品国产品小说| 亚洲欧美怡红院| 亚洲综合国产| 亚洲欧美成人一区二区三区|