mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-08 09:55:32 +00:00
Fixes #4591. I fixed incxstr in 4 places: 1. Common/Core: kmx_xstring.cpp 2. Engine: xstring.cpp 3. Test project importkeyboard importkeyboard.cpp 4. Test project m-to-p m-to-p.cpp I updated mcompile to remove its own copy of incxstr (identical to that in xstring.cpp) to reduce WETness but opted not to do so for the test apps, which are pretty much throwaway anyway. I note that there is more work we could do here; we need to check every character as we increment so we don't miss a `U+0000` end of string with malformed data. But I would like to tackle that as a separate job at some point in the future after Core integration.
257 lines
6.9 KiB
C++
257 lines
6.9 KiB
C++
/*
|
|
Name: syskbdnt32
|
|
Copyright: Copyright (C) SIL International.
|
|
Documentation:
|
|
Description:
|
|
Create Date: 10 Sep 2008
|
|
|
|
Modified Date: 4 May 2010
|
|
Authors: mcdurdin
|
|
Related Files:
|
|
Dependencies:
|
|
|
|
Bugs:
|
|
Todo:
|
|
Notes:
|
|
History: 10 Sep 2008 - mcdurdin - I1635 - Initial version
|
|
11 Mar 2009 - mcdurdin - I1894 - Fix threading bugs introduced in I1888
|
|
30 Nov 2009 - mcdurdin - I934 - Prep for x64 - change UINT to WORD for vkeys
|
|
12 Mar 2010 - mcdurdin - I934 - x64 - Complete
|
|
12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings
|
|
04 May 2010 - mcdurdin - I2351 - Robustness - verify _td return value
|
|
*/
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Use Windows NT/2000 keyboard DLLs for mapping virtual keys to characters
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pch.h"
|
|
#include "../../engine/keyman32/kbd.h" /* DDK kbdlayout */
|
|
|
|
|
|
typedef PKBDTABLES (WINAPI *PKBDLAYERDESCRIPTORFUNC)(VOID);
|
|
|
|
static HMODULE hKbdLibrary = NULL;
|
|
static PKBDTABLES KbdTables = NULL;
|
|
|
|
BOOL LoadNewLibrary_NT(PWSTR filename) {
|
|
if(hKbdLibrary) FreeLibrary(hKbdLibrary);
|
|
|
|
hKbdLibrary = LoadLibrary(filename);
|
|
if(!hKbdLibrary) {
|
|
LogError(L"LoadNewLibrary: Exit -- could not load library");
|
|
return FALSE;
|
|
}
|
|
|
|
PKBDLAYERDESCRIPTORFUNC KbdLayerDescriptorFunc = (PKBDLAYERDESCRIPTORFUNC) GetProcAddress(hKbdLibrary, "KbdLayerDescriptor");
|
|
if(KbdLayerDescriptorFunc)
|
|
{
|
|
KbdTables = (*KbdLayerDescriptorFunc)();
|
|
if(KbdTables) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
FreeLibrary(hKbdLibrary);
|
|
|
|
hKbdLibrary = NULL;
|
|
KbdTables = NULL;
|
|
|
|
LogError(L"LoadNewLibrary: Exit -- failed to find function");
|
|
return FALSE;
|
|
}
|
|
|
|
WCHAR CharFromVK_NT(WORD VKey, UINT ShiftFlags, WCHAR *PDeadKey) {
|
|
PVK_TO_WCHARS1 pv;
|
|
PVK_TO_WCHAR_TABLE pvt;
|
|
int i;
|
|
|
|
/* MCD 02/12/2002: Fix bug with number pad keys when numlock is on */
|
|
|
|
if(IsNumberPadKey(VKey)) {
|
|
return 0;
|
|
}
|
|
|
|
/* Get the appropriate table column for shift state */
|
|
|
|
int shift = -1, shiftidx = 0, capslockbit = 0;
|
|
|
|
for(PVK_TO_BIT pvtb = KbdTables->pCharModifiers->pVkToBit; pvtb->Vk; pvtb++) {
|
|
switch(pvtb->Vk) {
|
|
case VK_MENU:
|
|
if(ShiftFlags & (LALTFLAG|RALTFLAG)) shiftidx |= pvtb->ModBits; break;
|
|
case VK_SHIFT:
|
|
if(ShiftFlags & CAPITALFLAG) capslockbit = pvtb->ModBits;
|
|
if(ShiftFlags & (K_SHIFTFLAG)) shiftidx |= pvtb->ModBits; break;
|
|
case VK_CONTROL:
|
|
if(ShiftFlags & (LCTRLFLAG|RCTRLFLAG)) shiftidx |= pvtb->ModBits; break;
|
|
}
|
|
}
|
|
|
|
/* If the shift modifier is unused, don't produce a character */
|
|
|
|
if(shiftidx > KbdTables->pCharModifiers->wMaxModBits ||
|
|
KbdTables->pCharModifiers->ModNumber[shiftidx] == 0xF) {
|
|
return 0;
|
|
}
|
|
|
|
shift = KbdTables->pCharModifiers->ModNumber[shiftidx];
|
|
|
|
/* Get the appropriate virtual key */
|
|
|
|
for(i = 0, pvt = KbdTables->pVkToWcharTable; pvt->pVkToWchars; i++, pvt++) {
|
|
for(pv = pvt->pVkToWchars; pv->VirtualKey;) {
|
|
if(pv->VirtualKey == VKey) {
|
|
if(shift >= pvt->nModifications) {
|
|
return 0;
|
|
}
|
|
|
|
/* Check for Caps Lock */
|
|
if(ShiftFlags & CAPITALFLAG) {
|
|
if(pv->Attributes & CAPLOK) {
|
|
/* Invert the state of the SHIFT key */
|
|
shift = KbdTables->pCharModifiers->ModNumber[shiftidx ^ capslockbit];
|
|
} else if(pv->Attributes & SGCAPS) {
|
|
pv++; /* Next keystroke has the appropriate capitalised character */
|
|
}
|
|
}
|
|
|
|
/* Found the keystroke combination, return the appropriate character (if existing) */
|
|
switch(pv->wch[shift]) {
|
|
case WCH_DEAD:
|
|
pv = (PVK_TO_WCHARS1) ((BYTE *)pv + pvt->cbSize);
|
|
*PDeadKey = pv->wch[shift];
|
|
return 0xFFFF; /* Don't queue as WM_KEYDOWN -- don't output either */
|
|
case WCH_NONE:
|
|
return 0x0000; /* Not a valid key, queue as WM_KEYDOWN */
|
|
}
|
|
|
|
return (pv->wch[shift] > 31 && pv->wch[shift] != 127) ? pv->wch[shift] : 0; /* Don't generate 'special chars'; I911 - fix ctrl+bksp */
|
|
}
|
|
pv = (PVK_TO_WCHARS1) ((BYTE *)pv + pvt->cbSize);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
WORD ModificationToShift_NT(int mod) {
|
|
WORD ShiftFlags = 0;
|
|
|
|
int shiftidx = -1;
|
|
for(int i = 0; i <= KbdTables->pCharModifiers->wMaxModBits; i++) {
|
|
if(KbdTables->pCharModifiers->ModNumber[i] == mod) {
|
|
shiftidx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(shiftidx == -1) return 0xFFFF;
|
|
|
|
for(PVK_TO_BIT pvtb = KbdTables->pCharModifiers->pVkToBit; pvtb->Vk; pvtb++) {
|
|
if(shiftidx & pvtb->ModBits) {
|
|
switch(pvtb->Vk) {
|
|
case VK_MENU: ShiftFlags |= RALTFLAG; break;
|
|
case VK_SHIFT: ShiftFlags |= K_SHIFTFLAG; break;
|
|
case VK_CONTROL: ShiftFlags |= LCTRLFLAG; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ShiftFlags;
|
|
}
|
|
|
|
WORD CharToUSVK_NT(WORD ch, WORD *shift)
|
|
{
|
|
PVK_TO_WCHARS1 pv;
|
|
PVK_TO_WCHAR_TABLE pvt;
|
|
int i, j;
|
|
|
|
/* Find the appropriate keyboard tables */
|
|
|
|
if(!KbdTables) return 0; /* Could not load keyboard DLL */
|
|
|
|
/* Map the character back to the virtual key */
|
|
|
|
for(i = 0, pvt = KbdTables->pVkToWcharTable; pvt->pVkToWchars; i++, pvt++)
|
|
for(pv = pvt->pVkToWchars; pv->VirtualKey;)
|
|
{
|
|
for(j = 0; j < pvt->nModifications; j++)
|
|
if(pv->wch[j] == ch)
|
|
{
|
|
/* Return the new virtual key */
|
|
*shift = ModificationToShift_NT(j);
|
|
if(*shift == 0xFFFF) return 0;
|
|
return pv->VirtualKey;
|
|
}
|
|
pv = (PVK_TO_WCHARS1) ((BYTE *)pv + pvt->cbSize);
|
|
}
|
|
|
|
/* Remapping not found */
|
|
return 0;
|
|
}
|
|
|
|
|
|
int GetDeadkeys_NT(WORD DeadKey, WORD *OutputPairs) {
|
|
WORD *p = OutputPairs, shift;
|
|
for(int i = 0; KbdTables->pDeadKey[i].dwBoth; i++) {
|
|
if(HIWORD(KbdTables->pDeadKey[i].dwBoth) == DeadKey) {
|
|
WORD vk = CharToUSVK_NT(LOWORD(KbdTables->pDeadKey[i].dwBoth), &shift);
|
|
if(vk != 0) {
|
|
*p++ = vk;
|
|
*p++ = shift;
|
|
*p++ = KbdTables->pDeadKey[i].wchComposed;
|
|
} else {
|
|
LogError(L"Warning: complex deadkey not supported.");
|
|
}
|
|
}
|
|
}
|
|
*p = 0;
|
|
return (INT_PTR)(p-OutputPairs);
|
|
}
|
|
|
|
WORD VKUSToVKUnderlyingLayout_NT(WORD VKey) {
|
|
|
|
/* Num lock test -- MCD: 02/12/2002 Fix num lock not working bug */
|
|
|
|
if((VKey >= VK_NUMPAD0 && VKey <= VK_NUMPAD9) || VKey == VK_DECIMAL) return VKey;
|
|
|
|
/* Find the appropriate keyboard tables */
|
|
|
|
if(!KbdTables) /* Could not load keyboard DLL */
|
|
return VKey;
|
|
|
|
if(VKey > 255) return VKey;
|
|
|
|
UINT scan = USVirtualKeyToScanCode[VKey];
|
|
if(scan == 0 || scan >= KbdTables->bMaxVSCtoVK) return VKey;
|
|
return KbdTables->pusVSCtoVK[scan];
|
|
}
|
|
|
|
WORD VKUnderlyingLayoutToVKUS_NT(WORD VKey) {
|
|
|
|
/* Num lock test -- MCD: 02/12/2002 Fix num lock not working bug */
|
|
|
|
if((VKey >= VK_NUMPAD0 && VKey <= VK_NUMPAD9) || VKey == VK_DECIMAL) return VKey;
|
|
|
|
/* Find the appropriate keyboard tables */
|
|
|
|
if(!KbdTables) /* Could not load keyboard DLL */
|
|
return VKey;
|
|
|
|
UINT scan;
|
|
for(scan = 1; scan <= KbdTables->bMaxVSCtoVK; scan++) {
|
|
if(KbdTables->pusVSCtoVK[scan] == VKey) {
|
|
break;
|
|
}
|
|
}
|
|
if(scan > KbdTables->bMaxVSCtoVK || scan > 127) {
|
|
// no translation.
|
|
return VKey;
|
|
}
|
|
|
|
return ScanCodeToUSVirtualKey[scan];
|
|
}
|