| |
在回答完第一个问题之后,让我们在考虑第二个问题,读取键盘扫描码的问题,第一个是时间,无疑是在键盘按下,触发中断时候进行键盘扫描;第二个小问题,在那个函数中,添加我们的扫描代码?
KEYBD_IST keybdIst;
keybdIst.hevInterrupt = m_hevInterrupt;
keybdIst.dwSysIntr_Keybd = g_dwSysIntr_Keybd;
keybdIst.uiPddId = v_uiPddId;
keybdIst.pfnGetKeybdEvent = KeybdPdd_GetEventEx2;
keybdIst.pfnKeybdEvent = v_pfnKeybdEvent;
KeybdIstLoop(&keybdIst);
这个代码很有特色,进行了一些初始化,就调用KeybdIstLoop()函数,只能寄希望与KeybdIstLoop()是否又什么玄机,keybdIst对象首先挂接了hevInterrupt事件,挂接了系统中断g_dwSysIntr_Keybd,又看到一个很有意思的成员变量 keybdIst.pfnGetKeybdEvent = KeybdPdd_GetEventEx2,由字面意思可以看出keybdIst.pfnGetKeybdEvent,.pfn是个函数指针,搜索一下KeybdPdd_GetEventEx2,终于得到了问题2的答案,我们的键盘扫描码程序放在这里就可以了。
令人鄙视的复制 粘贴
static UINT KeybdPdd_GetEventEx2(UINT uiPddId, UINT32 rguiScanCode[16], BOOL rgfKeyUp[16])
{
SETFNAME(_T("KeybdPdd_GetEventEx2"));
UINT32 scInProgress = 0;
static UINT32 scPrevious;
BOOL fKeyUp;
UINT8 ui8ScanCode;
UINT cEvents = 0;
DEBUGCHK(rguiScanCode != NULL);
DEBUGCHK(rgfKeyUp != NULL);
getsFromKBCTL(&ui8ScanCode, 1);
DEBUGMSG(ZONE_SCANCODES,
(_T("%s: scan code 0x%08x, code in progress 0x%08x, previous 0x%08x\r\n"),
pszFname, ui8ScanCode, scInProgress, scPrevious));
scInProgress = ui8ScanCode;
if (scInProgress == scPrevious) {
// mdd handles auto-repeat so ignore auto-repeats from keybd
} else {
// Not a repeated key. This is the real thing.
scPrevious = scInProgress;
if (ui8ScanCode & scKeyUpMask) {
fKeyUp = TRUE;
scInProgress &= ~scKeyUpMask;
} else {
fKeyUp = FALSE;
}
rguiScanCode[cEvents] = scInProgress;
rgfKeyUp[cEvents] = fKeyUp;
++cEvents;
}
return cEvents;
}
不仔细分析了,大体说一下吧。硬件结构上,SMDK2440开发板采用UR5HCSPI芯片实现键盘阵列接口,getsFromKBCTL(&ui8ScanCode, 1);读取UR5HCSPI芯片的一个扫描码,将按键的扫描码保存在rguiScanCode[]数组中,rgfKeyUp表示按键状态。FALSE表示按键按下,TRUE表示按键已经弹起。这样就将按键值和按键状态传递给操作系统。
这段代码运行恰恰是在中断触发后立即执行的一段代码,时间上符合;执行键盘扫描程序,并把按键状态传递给WINCE,功能符合;终于找到点了。下面就需要我们在正确的时间,正确的代码段 运行正确的代码。
修改代码,删除KeybdPdd_GetEventEx2()函数中的所有代码,并添加子定义功能代码:
static UINT KeybdPdd_GetEventEx2(UINT uiPddId, UINT32 rguiScanCode[16], BOOL rgfKeyUp[16])
{
scInProgress = KeyBoard_Scan(); //按键扫描程序
rguiScanCode[cEvents] = scInProgress;
rgfKeyUp[cEvents] = FALSE; //必须为FALSE,否则表示按键没按下就弹起,逻辑上不通
++cEvents;
rguiScanCode[cEvents] = scInProgress;
rgfKeyUp[cEvents] =TRUE;
++cEvents;
return cEvents;
}
KeyBoard_Scan();函数中要完成 自定义 按键键值读取,抖动处理等,并返回按键值。
rguiScanCode[cEvents] = scInProgress;
rgfKeyUp[cEvents] = FALSE;
rguiScanCode[cEvents] = scInProgress;
rgfKeyUp[cEvents] =TRUE;
++cEvents;
return cEvents;
因为是测试代码,代码写得很烂,逻辑上并没有判断按键弹起的时刻。改进方法:键盘按下,下降沿触发中断,读取键值,并rguiScanCode[cEvents] = scInProgress; rgfKeyUp[cEvents] = FALSE;传递给操作系统,修改中断触发方式,改为上升沿触发,当按键弹起时,会再次调用KeybdPdd_GetEventEx2(),将rguiScanCode[cEvents] = scInProgress;
rgfKeyUp[cEvents] =TRUE;传递给操作系统,修改中断方式为下降沿触发。
问题3键盘扫描码该如何与操作系统的码字对应起来?求助网络吧,” WinCE的标准键盘驱动框架定义了两张映射表:即Scan code到virtual key的映射表(Device layout),和virtual key到unicode的映射表(input language)。通过修改这两张映射表的定义,我们就可以控制键盘上的每一个按键或者按键组合的输出”。第一张表,就在C:\WINCE500\PLATFORM\SMDK2440A\Src\Drivers\Keybd\Matrix_0409\s
例如我们有10个键盘,第1个键的扫描码为0X1(即当scInProgress = KeyBoard_Scan();的输出为0X1),并对应于WINCE的‘1’就可以这样写,以此类推,这样ScanCodeToVKeyTable[]=
{
‘0’, // Scan Code 0x0
‘
‘
‘
‘
‘
‘
‘
‘
‘
}
如果换一种定义,例如 a b c d……,可以写成
ScanCodeToVKeyTable[]=
{
‘a’, // Scan Code 0x0
‘b’, // Scan Code 0x1
‘c’, // Scan Code 0x2
‘d’, // Scan Code 0x3
‘e’, // Scan Code 0x4
‘f’, // Scan Code 0x5
‘g’, // Scan Code 0x6
‘h’, // Scan Code 0x7
‘i’, // Scan Code 0x8
‘j’, // Scan Code 0x9
}。
剩下一个问题,virtual key到unicode的映射表(input language),因为目前并不需要这个还没研究过,算是一点小遗憾吧。先留在这里,慢慢补充。
最后总结一下,
1 BOOL Ps2Keybd::IsrThreadProc()实现了硬件中断与WINCE之间的挂接;
2 KeybdPdd_GetEventEx2()函数完成自定义的键盘扫描程序,并把键盘信息传递给操作系统;
3 ScanCodeToVKeyTable完成了键盘扫描键值到WINCE虚拟键值的映射;
上面三点即为自定义键盘驱动所要修改之处。