就是输入法输入特殊字符时用的那个小键盘,比如紫光输入法上的小键盘按钮按下之后,就会弹出一个小键盘。本文就说一下如何做到这个功能:
这篇是我参考紫光拼音软键盘编码和一些输入法软键盘编码整理的文档: 软键盘的编码.rar

这个是我最近做的一个软键盘类:软键盘类.rar
下载所有输入法源码参见: http://www.cnblogs.com/realfun/archive/2005/06/26/181302.html

//这是以前写的输入法的小键盘(软键盘)类
//就是输入法输入特殊字符时用的那个小键盘
//比如搜狗输入法上的小键盘按钮按下之后,就会弹出一个小键盘
//
//注意:这是多个文件合在一起了,下载打包好的文件参见相关文章链接:
//    http://www.cnblogs.com/realfun/archive/2005/03/28/127174.html

////////////////////////////////////////////////
//
//      CIMESoftKbd.h

/*
* author : yuchifang(realfun)
* email : realfun at gmail dot com
*/

#ifndef _IME_SOFTKBD_H_
#define _IME_SOFTKBD_H_

#include
#include
#include
#include
using namespace std;

const SOFT_KEY_COUNT = 47;

//表示一个软键盘布局
class CIMESkbTab
{
public:
    CIMESkbTab(const TCHAR keys[], const TCHAR shiftKeys[], LPCTSTR name);
    CIMESkbTab(const CIMESkbTab &skb);
    TCHAR GetChar(int index);
    TCHAR GetShiftChar(int index);
    //转换键盘按键到软键盘字符,不存在则返回0
    TCHAR ConvVKey2SKBChar(UINT vKey, bool bShift);
    //获取tab名称
    void GetName(TCHAR name[]) { _tcscpy(name, this->name); }
private:
    TCHAR tab[SOFT_KEY_COUNT];  //软键盘布局
    TCHAR shiftTab[SOFT_KEY_COUNT];  //Shift后的软键盘布局
    TCHAR name[10];  //软键盘布局名称
};

//该类封装了软键盘操作
class CIMESoftKbd
{
public:
    CIMESoftKbd();

    //显示下一个软键盘布局
    void ShowNext()
    {
        m_tabIndex = (m_tabIndex + 1) % m_tabs.size();
        Show();
    }

    //显示前一个软键盘布局
    void ShowPrev()
    {
        m_tabIndex = (m_tabIndex + m_tabs.size() - 1) % m_tabs.size();
        Show();
    }

    //显示指定位置的软键盘布局
    void ShowAtPos(int index)
    {
        m_tabIndex = abs(index) % m_tabs.size();
        Show();
    }

    //显示并更新软键盘
    void Show();

    //隐藏软键盘
    void Hide();

    //判断软键盘是否打开
    bool IsOpen() { return m_bSkbOpened; }

    //转换键盘按键字符到软键盘字符
    TCHAR GetSkbChar(UINT vk, bool bShift);

    int GetCurrIndex() const { return m_tabIndex; }

private:
    bool m_bSkbOpened;  //软键盘是否打开
    int m_tabIndex;  //当前的软键盘编号
    vector m_tabs; //存储所有软键盘布局信息
    HWND m_hWndSkb;  //软键盘窗口句柄
};

#endif//_IME_SOFTKBD_H_

////////////////////////////////////////////////
//
//      CIMESoftKbd.cpp

/*
* author : yuchifang(realfun)
* email : realfun at gmail dot com
*/

#pragma warning(disable:4786)
#include "CIMEDebug.h"
#include "CIMESoftKbd.h"
#include "CIMEUIStatus.h"
#include "CIMEUtils.h"

//
// CIMESoftKbdTab Implementations
//

CIMESkbTab::CIMESkbTab(const TCHAR keys[], const TCHAR shiftKeys[], LPCTSTR name)
{
    for (int i=0; i<SOFT_KEY_COUNT; i++)
    {
        tab[i] = keys[i];
        shiftTab[i] = shiftKeys[i];
    }

    _tcsncpy(this->name, name, 10);
    this->name[9] = _T('\0');
}

CIMESkbTab::CIMESkbTab(const CIMESkbTab &skb)
{
    for (int i=0; i<SOFT_KEY_COUNT; i++)
    {
        tab[i] = skb.tab[i];
        shiftTab[i] = skb.shiftTab[i];
    }
    _tcscpy(name, skb.name);
}

TCHAR CIMESkbTab::GetChar(int index)
{
    assert(index>=0 && index <SOFT_KEY_COUNT);
    return tab[index];
}

TCHAR CIMESkbTab::GetShiftChar(int index)
{
    assert(index>=0 && index <SOFT_KEY_COUNT);
    return shiftTab[index];
}

TCHAR CIMESkbTab::ConvVKey2SKBChar(UINT vKey, bool bShift)
{
    /*
    vKey的内容分配:
    键盘上的位置 0-9  a-z  ;   =   ,   -   .   /   `   [   \   ]   '
    对应的vKey位置 48-57 65-90 186 187 188 189 190 191 192 219 220 221 222
    */

    int pos = -1;
    if (vKey >= 48 && vKey <=57)
        pos = vKey - 48;
    else if (vKey >= 65 && vKey <=90)
        pos = vKey - 65 + 10; //10为前面10个数字位置
    else if (vKey >= 186 && vKey <=192)
        pos = vKey - 186 + 10 + 26; //26为26字母占的位置
    else if (vKey >= 219 && vKey <= 222)
        pos = vKey - 219 + 10 + 26 + 7; //7为前面七个;=,-./`占的位置

    if (pos == -1) return L'\0';
    TCHAR ch = bShift ? shiftTab[pos] : tab[pos];
    if (ch == L' ')
        return L'\0';
    return ch;
}


//
// CIMESoftKbd Implementations
//

CIMESoftKbd::CIMESoftKbd()
{
    CIMEDebug::DebugLog(L"CIMESoftKbd::CIMESoftKbd()");

    TCHAR tabNames[][10] =
    {
        L"常用符号", L"标点符号", L"特殊符号", L"表格线",
        L"数字序号", L"数学符号", L"单位符号", L"拼音符号",
        L"注音符号", L"日文平假名", L"日文片假名", L"希腊字母",
        L"俄文字母",
    };

    WORD wSoftKBDDatas[][2][SOFT_KEY_COUNT] =
    {
        /*
        {//正常的键盘
        {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z', ';', '=', ',', '-',
        '.', '/', '`', '[', '\\', ']', '\''
        },
        {
        ')', '!', '@', '#', '$', '%', '^', '&', '*', '(',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
        'U', 'V', 'W', 'X', 'Y', 'Z', ':', '+', '<', '_',
        '>', '?', '~', '{', '|', '}', '"'
        }
        },
        */

        {//#常用符号
            {//下档键(没按住shift)
                L'⑽', L'⑴', L'⑵', L'⑶', L'⑷', L'⑸', L'⑹', L'⑺', L'⑻', L'⑼',
                    L'■', L'α', L'∑', L'▲', L'⒊', L'●', L'★', L'【', L'⒏', L'】',
                    L'『', L'‘', L'γ', L'β', L'⒐', L'⒑', L'⒈', L'⒋', L'◆', L'⒌',
                    L'⒎', L'§', L'⒉', L'‰', L'⒍', L'$', L';', L'=', L',', L'-',
                    L'。', L'/', L'`', L'[', L'、', L']', L'’'
            },
            {//下档键(按住shift)
                L'㈩', L'㈠', L'㈡', L'㈢', L'㈣', L'㈤', L'㈥', L'㈦', L'㈧', L'㈨',
                    L'□', L'±', L'∏', L'△', L'Ⅲ', L'○', L'☆', L'〖', L'Ⅷ', L'〗',
                    L'』', L'“', L'÷', L'×', L'Ⅸ', L'Ⅹ', L'Ⅰ', L'Ⅳ', L'◇', L'Ⅴ',
                    L'Ⅶ', L'※', L'Ⅱ', L'℃', L'Ⅵ', L'¥', L':', L'+', L'《', L'_',
                    L'》', L'?', L'~', L'{', L'?', L'}', L'”'
                }
        },
            //下同,略过了
    };

    int size = sizeof(wSoftKBDDatas) / sizeof(TCHAR) / 2 / SOFT_KEY_COUNT;
    for (int i=0; i<size; i++)
        m_tabs.push_back(CIMESkbTab(wSoftKBDDatas[i][0], wSoftKBDDatas[i][1], tabNames[i]));
    m_bSkbOpened = false;
    m_tabIndex = 0;
}

void CIMESoftKbd::Show()
{
    CIMEDebug::DebugLog(L"CIMESoftKbd::Show()");

    if (!m_bSkbOpened)
    {
        m_bSkbOpened = true;
        //显示软键盘
        RECT rc;
        int w;
        int h;
        int cx = GetSystemMetrics(SM_CXSCREEN);
        int cy = GetSystemMetrics(SM_CYSCREEN);
        m_hWndSkb = ImmCreateSoftKeyboard(SOFTKEYBOARD_TYPE_C1, FindWindow(CIMEUIStatus::GetUIClassName(), NULL), 0, 0);
        ImmShowSoftKeyboard(m_hWndSkb, SW_HIDE);
        GetWindowRect(m_hWndSkb, &rc);
        w = rc.right - rc.left;
        h = rc.bottom - rc.top;
        MoveWindow(m_hWndSkb, cx / 2, cy - 2*h, w, h, TRUE);
        ShowWindow(m_hWndSkb, SW_SHOWNOACTIVATE);
    }

    //更新软键盘布局
    SOFTKBDDATA sbd;
    int i;
    for (i=0; i<256; i++)
    {
        sbd.wCode[0][i] = _T(' ');
        sbd.wCode[1][i] = _T(' ');
    }
    CIMESkbTab &skbTab = m_tabs[m_tabIndex];

    /*
    vKey的内容分配:
    键盘上的位置 0-9  a-z  ;   =   ,   -   .   /   `   [   \   ]   '
    对应的vKey位置 48-57 65-90 186 187 188 189 190 191 192 219 220 221 222
    */
    int index2SoftKBDPos[SOFT_KEY_COUNT] =
    {
        48, 49, 50, 51, 52, 53, 54, 55, 56, 57, //'0'-'9'
        65, 66, 67, 68, 69, 70, 71, 72, 73, 74, //'a'-'j'
        75, 76, 77, 78, 79, 80, 81, 82, 83, 84, //'k'-'t'
        85, 86, 87, 88, 89, 90,     //'u'-'z'
        186, 187, 188, 189, 190,    // ; = , - .
        191, 192, 219, 220, 221, 222   // / ` [ \ ] '
    };

    for (i=0; i<SOFT_KEY_COUNT; i++)
    {
        sbd.wCode[0][index2SoftKBDPos[i]] = skbTab.GetChar(i);
        sbd.wCode[1][index2SoftKBDPos[i]] = skbTab.GetShiftChar(i);
    }

    sbd.uCount = 2;
    SendMessage(m_hWndSkb, WM_IME_CONTROL, IMC_SETSOFTKBDDATA, (LPARAM)&sbd);
    CIMEDebug::DebugLog(L"Leaving CIMESoftKbd::Show() safely!");
}

void CIMESoftKbd::Hide()
{
    if (!m_bSkbOpened) return;

    if(m_hWndSkb)
    {
        ImmDestroySoftKeyboard(m_hWndSkb);
    }
    m_bSkbOpened = false;
}

TCHAR CIMESoftKbd::GetSkbChar(UINT vk, bool bShift)
{
    CIMEDebug::DebugLog(L"CIMESoftKbd::GetSkbChar");
    CIMEDebug::DebugLog(vk);

    return m_tabs[m_tabIndex].ConvVKey2SKBChar(vk, bShift);
}

posted on 2005-03-28 13:41  尉迟方  阅读(12834)  评论(24编辑  收藏  举报