软键盘文件目录
文件 | 说明 |
---|---|
softkeywindow.c | 软键盘主窗口文件,包含窗口创建、窗口过程函数等 |
common.c | 窗口通用处理函数文件,包含按键消息处理函数、字符窗体处理函数等 |
resource.c | 图片资源管理文件,包含图片资源的加载和释放等 |
en_kbd.c | 英文键盘文件,不同键盘分别在不同的文件中,例如pinyin_kbd.c、num_kbd.c |
size_*.h | 窗口和按键坐标定义文件 |
softkeyboard.h | 结构体及函数声明文件 |
软键盘实现原理
miniGUI软键盘根本上是由图片和按键坐标配合实现,不同的键盘需配置不同的图片和与之对应窗口坐标。窗口以整张图片作为背景,在点击和移动鼠标时,根据鼠标在窗口的位置与坐标判断执行对应的操作,窗口中的所有按键都是靠坐标来实现的。
软键盘窗口一共分为3个区域,view_window,stroke_window,key_window
- key_window为键盘图片中的按键区域,处理按键的显示刷新
- stroke_window为输入的字符显示区,例如拼音输入,会在此区域显示输入的字母
- view_window为候选词显示区,例如拼音输入,会在此区域显示候选字
符号键盘则没有stroke_window和view_window
_md_key_t结构体
- bound为单个键的坐标,包括按键的具体位置和宽高
- key_char为按键中的字符,功能键则为空
- scan_code为对应的键值,标记该键的具体功能
- style用来区分是字符键还是功能键
- update为按键刷新函数,模拟按钮的点击效果等。
typedef struct _md_key_t {
/* the corrosponding rect of the key pad */
RECT bound;
/* the corresponging character of this key pad
* such as 'a','b' etc
*/
char key_char;
/* the correcponging scancode of this key pad.
* such as SCANCODE_F1~F3,BACKSPACE,ENTER,UP,DOWN,LEFT,RIGHT...
*/
int scan_code;
/* the style of this key pad.
* KEY_CHAR indaces the keypad is a character key pad
* KEY_FUNC indaces the keypad is a functional key pad
*/
int style;
/* private data for method update */
void * data;
/* this function is used to update the rect of key*/
void (*update)(struct _md_key_t * key, HWND hwnd);
} md_key_t;
显示和隐藏
软键盘线程在主窗口创建时创建,加载图片资源后调用CreateMainWindow创建软键盘窗口
- 显示
用户在点击控件时,通过客户区默认鼠标处理函数DefaultMouseMsgHandler接收鼠标左键点击消息,通过判断控件的类型及风格,给软键盘窗口句柄发送MSG_IME_SETSTATUS消息设置软键盘类型,最后显示软键盘。
static GINT DefaultMouseMsgHandler (PMAINWIN pWin, int message, WPARAM flags, int x, int y)
{
pUnderPointer = wndMouseInWhichControl (pWin, x, y, &UndHitCode);
switch (message)
{
case MSG_LBUTTONDOWN:
if (__mg_ime_wnd)
{
if (message == MSG_LBUTTONDOWN)
{
LWORD dwStyleEdit = GetWindowStyle((HWND)pUnderPointer);
SendNotifyMessage (__mg_ime_wnd, MSG_IME_SETSTATUS,IME_STATUS_SWITCH, IME_SWITCH_TOEN);
if (!IsWindowVisible(__mg_ime_wnd))
{
open_ime_window ((PMAINWIN)pUnderPointer, TRUE, 0);
}
}
}
}
}
- 隐藏
用户在点击控件外区域时产生非客户区鼠标点击消息,非客户区默认鼠标处理函数DefaultNCMouseMsgHandler接收左键点击消息,隐藏软键盘窗口。
static GINT DefaultNCMouseMsgHandler(PMAINWIN pWin, int message, int location, int x, int y)
{
switch (message)
{
case MSG_NCLBUTTONDOWN:
open_ime_window (pWin, FALSE, 0);
}
}
输入和切换
鼠标点击键盘后发送MSG_LBUTTONDOWN消息到SoftKeyWinProc窗口过程函数,调用对应键盘的消息处理函数keyboard->proceed_msg,并根据点击位置循环查找对应按键信息,最终根据不同按键分别处理。
static GINT SoftKeyWinProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case MSG_LBUTTONDOWN:
switch (pdata->keyboard->proceed_msg(pdata->keyboard, hWnd, message, wParam, lParam)) {
//键盘切换
case AC_CHANGE_KBD: {
int y;
POINT p;
p.x = LOSWORD(lParam);
p.y = HISWORD(lParam);
md_key_t* key = pdata->keyboard->key_window->get_key(pdata->keyboard->key_window, p);
if (!key)
break;
/* english */
if (key->scan_code == SCANCODE_TOEN){
y = 0;
pdata->ime_status_language = IME_LANGUAGE_LATIN;
}
/* pinyin */
if (key->scan_code == SCANCODE_TOPY) {
y = 1;
pdata->ime_status_language = IME_LANGUAGE_ZHCN;
}
/* 123 */
if (key->scan_code == SCANCODE_TONUM) {
y = 2;
pdata->ime_status_language = IME_LANGUAGE_LATIN;
}
/* oprator */
if (key->scan_code == SCANCODE_TOOP) {
y = 3;
pdata->ime_status_language = IME_LANGUAGE_LATIN;
}
/*clear old state */
pdata->keyboard->clear(pdata->keyboard);
pdata->current_board_idx = status_table[pdata->current_board_idx][y];
pdata->keyboard = keyboard[pdata->current_board_idx];
SendMessage(hWnd, MSG_ERASEBKGND, 0, 0L);
softkey_reset();
return 0;
}
//字符输入
case AC_SEND_MSG:
#if defined(_MGRM_PROCESSES) && (MINIGUI_MAJOR_VERSION > 1) && !defined(_STAND_ALONE)
Send2ActiveWindow(mgTopmostLayer,
pdata->keyboard->action.message,
pdata->keyboard->action.wParam,
pdata->keyboard->action.lParam);
#elif defined(_MGRM_THREADS) && !defined(_STAND_ALONE)
PostMessage(pdata->target_hwnd,
pdata->keyboard->action.message,
pdata->keyboard->action.wParam,
pdata->keyboard->action.lParam);
#endif
return 0;
return 0;
}
}
static int en_proc_msg(key_board_t* key_board, HWND hwnd, int message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case MSG_LBUTTONDOWN:
p.x = LOSWORD(lParam);
p.y = HISWORD(lParam);
lbuttondown = 1;
key_board->action.operation = AC_NULL;
if (PtInRect(&key_board->view_window->bound, p.x, p.y)) {
vw_proceed_hit(hwnd, key_board->view_window,
key_board->stroke_window, &key_board->action,
TRUE, p, CN, key_board->ime);
break;
}
if (PtInRect(&key_board->key_window->bound, p.x, p.y)) {
key = key_board->key_window->get_key(key_board->key_window, p);
if (key == NULL) {
key_board->action.operation = AC_NULL;
break;
}
kw_proceed_hit(hwnd, key_board->view_window,
key_board->stroke_window, key, &key_board->action,
TRUE, p, EN, key_board->ime, wParam, lParam);
key_down = key;
break;
}
}
}
-
键盘切换
pdata->keyboard->proceed_msg在英文键盘下对应en_proc_msg,接收MSG_LBUTTONDOWN消息后,判断当前点击位置为按键区,通过get_key获取按键信息,并传入kw_proceed_hit函数,当获取的按键信息key->scan_code为SCANCODE_TONUM~SCANCODE_TOOP之间时,返回AC_CHANGE_KBD。最后SoftKeyWinProc通过与status_table二维数组比较,确定将要切换的键盘,完成键盘的切换。 -
字符输入
当获取的按键信息key->style为KEY_PAD_CHAR时,判断为字符键,则kw_proceed_hit函数返回以下信息,ch为按键字符,最后发送消息给目标控件。
action->operation = AC_SEND_MSG;
action->message = MSG_CHAR;
action->wParam = ch;
action->lParam = 0;
以上为miniGUI软键盘的基本实现原理,下一篇会说明如何修改美化原有的软键盘。