上一篇文章说到,miniGUI软键盘根本上是由图片和按键坐标配合实现的,若想美化软键盘,则需替换重新设计的键盘图片。
图片资源的相关内容在source.c文件中,RESDATA结构体中为所有的键盘图片资源名称,图片替换后需根据图片位置修改对应宏定义和按键坐标。
宏 | 说明 |
---|---|
SKB_WIN_W/SKB_WIN_H | 键盘的宽高 |
SKB_CLOSE_L/SKB_CLOSE_T / SKB_CLOSE_R/SKB_CLOSE_B | 关闭键盘按钮的坐标 |
SKB_VW_L/SKB_VW_T/SKB_VW_R/SKB_VW_B | 文字候选词区域坐标 |
SKB_VW_PU_L/SKB_VW_PU_T/SKB_VW_PU_R/SKB_VW_PU_B | 文字候选上一页按钮的坐标 |
SKB_VW_PD_L/SKB_VW_PD_T/SKB_VW_PD_R/SKB_VW_PD_B | 文字候选下一页按钮的坐标 |
SKB_SW_L/SKB_SW_T/SKB_SW_R/SKB_SW_B | 输入字符显示区域坐标 |
SKB_KW_L/SKB_KW_T/SKB_KW_R/SKB_KW_B | 键盘按键区域的坐标 |
VW_ELMT_LEN | 单个候选词最大长度 |
VW_BUFFER_LEN | 一页候选词最大长度 |
VW_ELMENT_NR | 一页候选词最多能有多少个候选词 |
SW_STR_LEN | 输出字符最大长度 |
按键坐标则需在size_*.h文件中修改,然后将修改后的坐标与各键盘文件(如en_kbd.c)中的md_key_t结构体匹配,如果图片中按键布局做了调整,则需相应调整md_key_t中的信息,保证按键位置和字符等信息一一对应。
#define RECT_EN_KEY_1 { 2, 2, 31, 33}
#define RECT_EN_KEY_2 { 32, 2, 61, 33}
static md_key_t en_key_pads[] = {
{RECT_EN_KEY_1, 'q', SCANCODE_Q, KEY_PAD_CHAR, NULL, share_key_update},
{RECT_EN_KEY_2, 'w', SCANCODE_W, KEY_PAD_CHAR, NULL, share_key_update},
}
拼音键盘
拼音键盘的输入需要stroke_window和view_window区域来显示输入的字符和候选字,但由于软键盘窗口空间有限,字体显示会比较小,若将区域空间改大则影响美观。如何实现windows系统下的输入效果,输入字符直接显示在目标控件中,而软键盘中只显示候选字,这样即可取消stroke_window区域,view_window的显示空间会更大,实际效果如图中所示。
实现方法
1. 隐藏stroke_window
stroke_window区域并不是完全取消,只是将区域空间缩小不显示,而stroke_window的功能依然存在,因为view_window会根据stroke_window中的字符联想候选词,因此输入字符依然要存入stroke_window中。
另外需注意stroke_window宽高不可设为0,因为stroke_window不是实际窗口,没有窗口句柄,判断stroke_window是否存在的方法是判断区域大小是否为0。
#define SKB_SW_L 0
#define SKB_SW_T 0
#define SKB_SW_R (SKB_SW_L+1)
#define SKB_SW_B (SKB_SW_T+1)
2. 字符发送到目标控件
英文输入时会直接将字符发送到目标控件,而拼音字符输入时没有将字符显示在目标控件中,因此,我们只需在处理拼音输入时也将字符发送到目标控件。
字符输入的处理在kw_proceed_hit函数中,其中参数flag的作用是区分英文和中文,只需在key->style & KEY_PAD_CHAR的判断为TRUE时加入以下代码。
if (flag == CN)
{
PostMessage(pdata->target_hwnd, MSG_CHAR, ch, 0);
}
3. 输入字符选中
为了区分拼音输入字符和英文输入下的不同,将拼音输入的字符设为选中状态,此方法的好处有以下两点:
- 高亮显示,表示正在输入的字符
- 可利用选中效果实现点击候选词后的直接覆盖
设置输入高亮需在edit控件中处理MSG_CHAR消息时判断,当前键盘为拼音键盘并且stroke_window中有字符时,设置选中字符,选中部分起点为当前光标位置减去stroke_window中字符的个数,终点为光标位置,代码如下
if (__mg_ime_wnd
&& IsWindowVisible(__mg_ime_wnd)
&& (NULL != pdata))
{
if(SFKB_IDX_PINYIN == pdata->current_board_idx)
{
if(strlen(pdata->keyboard->stroke_window->str) > 0)
{
sleSetSel (hWnd, sled, sled->editPos - strlen(pdata->keyboard->stroke_window->str), sled->editPos);
}
}
}
输入字符设为选中后也相应的会出现一些问题:
- 选中后再输入会自动覆盖前面的输入,只能显示一个字符
- 删除输入时会将选中的所有字符一起删除,输入错误只能重新输入
为解决此问题,需了解选中效果的处理逻辑,edit控件字符输入函数sleInsertText中,当(sled->selStart != sled->selEnd)即出现选中时,会进行特殊处理,我们只需在此部分处理时,判断当前是否为拼音键盘输入,如果是则不进行此部分处理。
4. 注意
此实现效果有以下几点需要额外注意:
- 字符输入时超过控件限制,需要解除字符输入时的限制,仅限制汉字的个数,否则最后一个汉字无法输入完整的拼音
- 字符输入时切换键盘,需要清除选中效果
- stroke_window需和目标控件中的选中字符同步,包括各种场景下的同步,例如输入字符后为选中态,此时输入数字会将字符覆盖,需同步stroke_window->str