spiegel-keyman/windows/src/engine/mcompile/mc_syskbdnt64.cpp
Marc Durdin b65b982584 Keyman Desktop and Keyman Developer open source 10.0 alpha seed (#121)
* Keyman for Windows 10.0 Open Source

* Squashed 'windows/src/ext/jedi/jedi/' content from commit f444ad2

git-subtree-dir: windows/src/ext/jedi/jedi
git-subtree-split: f444ad2da4693851e523f1ea6bd541f701904c24

* Squashed 'windows/src/ext/jedi/jcl/' content from commit d63d3c9fd

git-subtree-dir: windows/src/ext/jedi/jcl
git-subtree-split: d63d3c9fd9ff84efdd8159084ec6a60313644243

* Squashed 'windows/src/ext/jedi/jvcl/' content from commit bee19f3b4

git-subtree-dir: windows/src/ext/jedi/jvcl
git-subtree-split: bee19f3b46909fde2fa92c06cd2706f41d99f6c3

* Add required .res files

* Add required .res files

* Add docbook files (forced)

* Add required libxslt

* Add required jedi files

* Add installation files

* Tweak .gitignore for open

* CI

* Remove KMW from Developer source (#122)

* Remove KMW from Developer source (copies during build)

* Remove KMW from Developer source (copies during build)

* Remove KMW from Developer source (copies during build)

* Fixup release build and copy license, readme from kmw during build

* Remove obsolete build help documentation

* Keyman Engine 10 on Windows regression for shift states (#129)

* Improve #128 -- cleaner debug messages

* Fixes #127, shift state now resets correctly; and more work for #128

* Fixes #130 (#131)
2017-07-25 10:53:06 +07:00

367 lines
9.9 KiB
C++

/*
Name: syskbdnt64
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 "stdafx.h"
#include "../../engine/keyman32/kbd.h" /* DDK kbdlayout */
typedef struct {
PVK_TO_BIT pVkToBit; // Virtual Keys -> Mod bits
DWORD filler;
WORD wMaxModBits; // max Modification bit combination value
BYTE ModNumber[1]; // Mod bits -> Modification Number
} MODIFIERS_x64, *PMODIFIERS_x64;
typedef struct _VK_TO_WCHAR_TABLE_x64 {
PVK_TO_WCHARS1 pVkToWchars;
DWORD filler;
BYTE nModifications;
BYTE cbSize;
BYTE filler2[2];
DWORD filler3;
} VK_TO_WCHAR_TABLE_x64, *PVK_TO_WCHAR_TABLE_x64;
/***************************************************************************\
* VSC_VK - Associate a Virtual Scancode with a Virtual Key
* Vsc - Virtual Scancode
* Vk - Virtual Key | flags
* Used by VKFromVSC() for scancodes prefixed 0xE0 or 0xE1
\***************************************************************************/
typedef struct _VSC_VK_x64 {
BYTE Vsc;
USHORT Vk;
} VSC_VK_x64, *PVSC_VK_x64;
/***************************************************************************\
* VK_VSC - Associate a Virtual Key with a Virtual Scancode
* Vk - Virtual Key
* Vsc - Virtual Scancode
* Used by MapVirtualKey for Virtual Keys not appearing in ausVK[]
\***************************************************************************/
typedef struct _VK_VSC_x64 {
BYTE Vk;
BYTE Vsc;
} VK_VSC_x64, *PVK_VSC_x64;
typedef struct tagKdbLayer_x64
{
/*
* Modifier keys
*/
PMODIFIERS_x64 pCharModifiers;
DWORD filler1;
/*
* Characters
*/
VK_TO_WCHAR_TABLE_x64 *pVkToWcharTable; // ptr to tbl of ptrs to tbl
DWORD filler2;
/*
* Diacritics
*/
PDEADKEY pDeadKey;
DWORD filler3;
/*
* Names of Keys
*/
VSC_LPWSTR *pKeyNames;
DWORD filler4;
VSC_LPWSTR *pKeyNamesExt;
DWORD filler5;
LPWSTR *pKeyNamesDead;
DWORD filler6;
/*
* Scan codes to Virtual Keys
*/
USHORT *pusVSCtoVK;
DWORD filler7;
BYTE bMaxVSCtoVK;
DWORD filler8;
PVSC_VK_x64 pVSCtoVK_E0; // Scancode has E0 prefix
DWORD filler9;
PVSC_VK_x64 pVSCtoVK_E1; // Scancode has E1 prefix
DWORD fillerA;
/*
* Locale-specific special processing
*/
DWORD fLocaleFlags;
DWORD fillerB;
} KBDTABLES_x64, *PKBDTABLES_x64;
typedef PKBDTABLES_x64 (WINAPI *PKBDLAYERDESCRIPTORFUNC)(VOID);
static HMODULE hKbdLibrary_x64 = NULL;
static PKBDTABLES_x64 KbdTables_x64 = NULL;
BOOL LoadNewLibrary_NT_x64(PWSTR filename) {
if(hKbdLibrary_x64) FreeLibrary(hKbdLibrary_x64);
hKbdLibrary_x64 = LoadLibrary(filename);
if(!hKbdLibrary_x64) {
LogError(L"LoadNewLibrary_x64: Exit -- could not load library");
return FALSE;
}
PKBDLAYERDESCRIPTORFUNC KbdLayerDescriptorFunc = (PKBDLAYERDESCRIPTORFUNC) GetProcAddress(hKbdLibrary_x64, "KbdLayerDescriptor");
if(KbdLayerDescriptorFunc)
{
KbdTables_x64 = (*KbdLayerDescriptorFunc)();
if(KbdTables_x64) {
return TRUE;
}
}
FreeLibrary(hKbdLibrary_x64);
hKbdLibrary_x64 = NULL;
KbdTables_x64 = NULL;
LogError(L"LoadNewLibrary_x64: Exit -- failed to find function");
return FALSE;
}
WCHAR CharFromVK_NT_x64(WORD VKey, UINT ShiftFlags, WCHAR *PDeadKey) {
PVK_TO_WCHARS1 pv;
PVK_TO_WCHAR_TABLE_x64 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_x64->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_x64->pCharModifiers->wMaxModBits ||
KbdTables_x64->pCharModifiers->ModNumber[shiftidx] == 0xF) {
return 0;
}
shift = KbdTables_x64->pCharModifiers->ModNumber[shiftidx];
/* Get the appropriate virtual key */
for(i = 0, pvt = KbdTables_x64->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_x64->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_x64(int mod) {
WORD ShiftFlags = 0;
int shiftidx = -1;
for(int i = 0; i <= KbdTables_x64->pCharModifiers->wMaxModBits; i++) {
if(KbdTables_x64->pCharModifiers->ModNumber[i] == mod) {
shiftidx = i;
break;
}
}
if(shiftidx == -1) return 0xFFFF;
for(PVK_TO_BIT pvtb = KbdTables_x64->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_x64(WORD ch, WORD *shift)
{
PVK_TO_WCHARS1 pv;
PVK_TO_WCHAR_TABLE_x64 pvt;
int i, j;
/* Find the appropriate keyboard tables */
if(!KbdTables_x64) return 0; /* Could not load keyboard DLL */
/* Map the character back to the virtual key */
for(i = 0, pvt = KbdTables_x64->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_x64(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_x64(WORD DeadKey, WORD *OutputPairs) {
WORD *p = OutputPairs, shift;
for(int i = 0; KbdTables_x64->pDeadKey[i].dwBoth; i++) {
if(HIWORD(KbdTables_x64->pDeadKey[i].dwBoth) == DeadKey) {
WORD vk = CharToUSVK_NT_x64(LOWORD(KbdTables_x64->pDeadKey[i].dwBoth), &shift);
if(vk != 0) {
*p++ = vk;
*p++ = shift;
*p++ = KbdTables_x64->pDeadKey[i].wchComposed;
} else {
LogError(L"Warning: complex deadkey not supported.");
}
}
}
*p = 0;
return (int)(p-OutputPairs);
}
WORD VKUSToVKUnderlyingLayout_NT_x64(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_x64) /* Could not load keyboard DLL */
return VKey;
if(VKey > 255) return VKey;
UINT scan = USVirtualKeyToScanCode[VKey];
if(scan == 0 || scan >= KbdTables_x64->bMaxVSCtoVK) return VKey;
return KbdTables_x64->pusVSCtoVK[scan];
}
WORD VKUnderlyingLayoutToVKUS_NT_x64(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_x64) /* Could not load keyboard DLL */
return VKey;
UINT scan;
for(scan = 1; scan <= KbdTables_x64->bMaxVSCtoVK; scan++) {
if(KbdTables_x64->pusVSCtoVK[scan] == VKey) {
break;
}
}
if(scan > KbdTables_x64->bMaxVSCtoVK || scan > 127) {
// no translation.
return VKey;
}
return ScanCodeToUSVirtualKey[scan];
}
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
LPFN_ISWOW64PROCESS
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(L"kernel32"),"IsWow64Process");
BOOL fStored = FALSE;
BOOL bIsWow64 = FALSE;
BOOL IsWow64() {
if(fStored) return bIsWow64;
bIsWow64 = FALSE;
if(NULL != fnIsWow64Process) {
if(!fnIsWow64Process(GetCurrentProcess(),&bIsWow64)){
// handle error
return FALSE;
}
}
fStored = TRUE;
return bIsWow64;
}