miniGUI源码分析:软键盘实现原理

软键盘文件目录

文件说明
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软键盘的基本实现原理,下一篇会说明如何修改美化原有的软键盘。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值