mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-24 16:47:41 +00:00
301 lines
9.5 KiB
C++
301 lines
9.5 KiB
C++
/*
|
|
Name: AIWin2000Unicode
|
|
Copyright: Copyright (C) SIL International.
|
|
Documentation:
|
|
Description:
|
|
Create Date: 22 Jan 2007
|
|
|
|
Modified Date: 9 Aug 2015
|
|
Authors: mcdurdin
|
|
Related Files:
|
|
Dependencies:
|
|
|
|
Bugs:
|
|
Todo:
|
|
Notes:
|
|
History: 22 Jan 2007 - mcdurdin - Fix for K_NPENTER
|
|
13 Jul 2007 - mcdurdin - I934 - Prep fox x64
|
|
23 Aug 2007 - mcdurdin - I719 - Fix Alt+LeftShift and Word interactions
|
|
14 Jun 2008 - mcdurdin - I1389 - Supp chars on Vista+ default to single BKSP
|
|
20 Jul 2008 - mcdurdin - I1546 - Language switch not working with some keyboard IDs
|
|
16 Jan 2009 - mcdurdin - I1512 - SendInput support
|
|
27 Jan 2009 - mcdurdin - I1797 - Add fallback for AIWin2000 app integration
|
|
11 Dec 2009 - mcdurdin - I934 - x64 - Initial version
|
|
12 Mar 2010 - mcdurdin - I934 - x64 - Complete
|
|
12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings
|
|
15 Jun 2010 - mcdurdin - I2426 - Remove incorrectl KEYMAN_CHARFLAG
|
|
24 Jun 2010 - mcdurdin - I2436 - Add space to context for AIWin2000Unicode when not matched
|
|
27 Aug 2012 - mcdurdin - I3438 - V9.0 - Add support for custom virtual keys Created
|
|
18 Feb 2012 - mcdurdin - I3242 - Arrow keys do not function correctly in Internet Explorer
|
|
26 Feb 2012 - mcdurdin - I2787 - Reset keyboard state for a key when key down is sent to avoid confusion for Chrome
|
|
04 Nov 2012 - mcdurdin - I3527 - V9.0 - Merge of I3242 - Arrow keys do not function correctly in Internet Explorer
|
|
04 Nov 2012 - mcdurdin - I3528 - V9.0 - Merge of I2787 - Reset keyboard state for a key when key down is sent to avoid confusion for Chrome
|
|
17 Dec 2013 - mcdurdin - I4006 - V9.0 - Remove old aiDefault code
|
|
24 Apr 2014 - mcdurdin - I4196 - V9.0 - wm_kmmoreposting must be refactored for TIP work as it is not sequential
|
|
01 May 2014 - mcdurdin - I4128 - V9.0 - Shift states still not working with unprocessed keys in V9
|
|
23 Jun 2014 - mcdurdin - I4287 - V9.0 - Remove extraneous AppIntegration class type tests
|
|
13 Aug 2014 - mcdurdin - I4370 - Deadkeys are still not working in Winword TIP mode
|
|
14 Aug 2014 - mcdurdin - I4378 - V9.0 - Rapid typing in legacy mode breaks Keyman input
|
|
13 Oct 2014 - mcdurdin - I4452 - V9.0 - Chinese keyboard is not working correctly
|
|
31 Dec 2014 - mcdurdin - I4548 - V9.0 - When Alt is down, release of Ctrl, Shift is not detectable within TIP in some languages
|
|
09 Aug 2015 - mcdurdin - I4844 - Tidy up PostDummyKeyEvent calls
|
|
*/
|
|
#include "pch.h" // I4128 // I4287
|
|
#include "serialkeyeventclient.h"
|
|
|
|
|
|
AIWin2000Unicode::AIWin2000Unicode()
|
|
{
|
|
context = new AppContext;
|
|
}
|
|
|
|
AIWin2000Unicode::~AIWin2000Unicode()
|
|
{
|
|
delete context;
|
|
}
|
|
|
|
/* Information functions */
|
|
|
|
|
|
BOOL AIWin2000Unicode::CanHandleWindow(HWND ahwnd)
|
|
{
|
|
UNREFERENCED_PARAMETER(ahwnd);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AIWin2000Unicode::HandleWindow(HWND ahwnd)
|
|
{
|
|
if(hwnd != ahwnd)
|
|
{
|
|
hwnd = ahwnd;
|
|
context->Reset();
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AIWin2000Unicode::IsWindowHandled(HWND ahwnd)
|
|
{
|
|
return (hwnd == ahwnd);
|
|
}
|
|
|
|
BOOL AIWin2000Unicode::IsUnicode()
|
|
{
|
|
BOOL Result = IsWindowUnicode(hwnd);
|
|
SendDebugMessageFormat(0, sdmAIDefault, 0, "IsWindowUnicode=%s", Result ? "Yes" : "No");
|
|
return Result;
|
|
}
|
|
|
|
/* Context functions */
|
|
|
|
void AIWin2000Unicode::ReadContext()
|
|
{
|
|
}
|
|
|
|
void AIWin2000Unicode::AddContext(WCHAR ch) //I2436
|
|
{
|
|
context->Add(ch);
|
|
}
|
|
|
|
void AIWin2000Unicode::ResetContext()
|
|
{
|
|
context->Reset();
|
|
}
|
|
|
|
WCHAR *AIWin2000Unicode::ContextBuf(int n)
|
|
{
|
|
return context->Buf(n);
|
|
}
|
|
|
|
WCHAR *AIWin2000Unicode::ContextBufMax(int n)
|
|
{
|
|
return context->BufMax(n);
|
|
}
|
|
|
|
void AIWin2000Unicode::SetContext(const WCHAR* buf)
|
|
{
|
|
return context->Set(buf);
|
|
}
|
|
|
|
BYTE SavedKbdState[256];
|
|
|
|
BOOL AIWin2000Unicode::SendActions() // I4196
|
|
{
|
|
if(*Globals::hwndIM()) {
|
|
PostMessage(*Globals::hwndIM(), wm_keymanim_contextchanged, 0, 0);
|
|
}
|
|
return PostKeys();
|
|
}
|
|
|
|
BOOL AIWin2000Unicode::QueueAction(int ItemType, DWORD dwData)
|
|
{
|
|
int result = AppIntegration::QueueAction(ItemType, dwData);
|
|
|
|
//SendDebugMessageFormat(hwnd, sdmAIDefault, 0, "App::QueueAction ItemType=%d dwData=%x", ItemType, dwData);
|
|
|
|
switch(ItemType)
|
|
{
|
|
case QIT_VKEYDOWN:
|
|
break;
|
|
|
|
case QIT_DEADKEY:
|
|
context->Add(UC_SENTINEL);
|
|
context->Add(CODE_DEADKEY);
|
|
context->Add((WORD) dwData);
|
|
break;
|
|
|
|
case QIT_CHAR:
|
|
context->Add((WORD) dwData);
|
|
break;
|
|
|
|
case QIT_BACK:
|
|
if(dwData & BK_BACKSPACE)
|
|
while(context->CharIsDeadkey()) context->Delete();
|
|
//if(dwData == CODE_DEADKEY) break;
|
|
context->Delete();
|
|
if(dwData & BK_BACKSPACE)
|
|
while(context->CharIsDeadkey()) context->Delete();
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// I1512 - SendInput with VK_PACKET for greater robustness
|
|
|
|
BOOL AIWin2000Unicode::PostKeys()
|
|
{
|
|
PKEYMAN64THREADDATA _td = ThreadGlobals();
|
|
if(!_td) {
|
|
return FALSE;
|
|
}
|
|
|
|
if(QueueSize == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
if (_td->CustomPostKeyCallback != nullptr) {
|
|
BOOL res = _td->CustomPostKeyCallback(Queue, QueueSize);
|
|
QueueSize = 0;
|
|
return res;
|
|
}
|
|
|
|
int n = 0;
|
|
/* 6.0.153.0: Fix repeat state for virtual keys */
|
|
|
|
LPINPUT pInputs = new INPUT[QueueSize*100]; // TODO: Tidy this up. Horrid doing a junky alloc like this each event
|
|
int i = 0;
|
|
|
|
for(; n < QueueSize; n++)
|
|
{
|
|
switch(Queue[n].ItemType) {
|
|
case QIT_VKEYDOWN:
|
|
if((Queue[n].dwData & QVK_KEYMASK) == 0x05) Queue[n].dwData = (Queue[n].dwData & QVK_FLAGMASK) | VK_RETURN; // I649 // I3438
|
|
|
|
/* 6.0.153.0: Fix repeat state for virtual keys */
|
|
|
|
if((Queue[n].dwData & QVK_KEYMASK) <= VK__MAX) // I3438
|
|
{
|
|
pInputs[i].type = INPUT_KEYBOARD;
|
|
pInputs[i].ki.wVk = (WORD)Queue[n].dwData & 0xFF; // I3242 - noted as unclean but was not cause of the issue // I3438 // I3527
|
|
|
|
pInputs[i].ki.wScan = SCAN_FLAG_KEYMAN_KEY_EVENT;
|
|
pInputs[i].ki.dwFlags = ((Queue[n].dwData & QVK_EXTENDED) ? KEYEVENTF_EXTENDEDKEY : 0); // I3438
|
|
|
|
pInputs[i].ki.time = 0;
|
|
pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378
|
|
}
|
|
|
|
//// I2787 - Reset keyboard state so Chrome doesn't get confused with VK_RETURN // I3528
|
|
{
|
|
BYTE keystate[256];
|
|
GetKeyboardState(keystate);
|
|
if(keystate[Queue[n].dwData & 0xFF] & 0x80)
|
|
{
|
|
keystate[Queue[n].dwData & 0xFF] = 0;
|
|
SetKeyboardState(keystate);
|
|
}
|
|
}
|
|
//// I2787 - END CHROME TEST // I3528
|
|
|
|
break;
|
|
case QIT_VKEYUP:
|
|
if((Queue[n].dwData & QVK_KEYMASK) == 0x05) Queue[n].dwData = (Queue[n].dwData & QVK_FLAGMASK) | VK_RETURN; // I649 // I3438
|
|
|
|
if((Queue[n].dwData & QVK_KEYMASK) <= VK__MAX) // I3438
|
|
{
|
|
pInputs[i].type = INPUT_KEYBOARD;
|
|
pInputs[i].ki.wVk = (WORD) Queue[n].dwData & 0xFF; // I3242 - noted as unclean but was not cause of the issue // I3438 // I3527
|
|
pInputs[i].ki.wScan = SCAN_FLAG_KEYMAN_KEY_EVENT;
|
|
pInputs[i].ki.dwFlags = KEYEVENTF_KEYUP | ((Queue[n].dwData & QVK_EXTENDED) ? KEYEVENTF_EXTENDEDKEY : 0); // I3438
|
|
pInputs[i].ki.time = 0;
|
|
pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378
|
|
}
|
|
|
|
break;
|
|
case QIT_VSHIFTDOWN:
|
|
break;
|
|
case QIT_VSHIFTUP:
|
|
break;
|
|
case QIT_CHAR:
|
|
pInputs[i].type = INPUT_KEYBOARD;
|
|
pInputs[i].ki.wVk = 0;
|
|
pInputs[i].ki.wScan = (WORD) Queue[n].dwData;
|
|
pInputs[i].ki.dwFlags = KEYEVENTF_UNICODE;
|
|
pInputs[i].ki.time = 0;
|
|
pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378
|
|
|
|
pInputs[i].type = INPUT_KEYBOARD;
|
|
pInputs[i].ki.wVk = 0;
|
|
pInputs[i].ki.wScan = (WORD) Queue[n].dwData;
|
|
pInputs[i].ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_UNICODE;
|
|
pInputs[i].ki.time = 0;
|
|
pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378
|
|
|
|
break;
|
|
case QIT_DEADKEY:
|
|
break;
|
|
case QIT_BELL:
|
|
MessageBeep(MB_ICONASTERISK); //(UINT) -1);
|
|
break;
|
|
case QIT_BACK:
|
|
if(Queue[n].dwData & BK_DEADKEY) break;
|
|
|
|
pInputs[i].type = INPUT_KEYBOARD;
|
|
pInputs[i].ki.wVk = VK_BACK;
|
|
pInputs[i].ki.wScan = SCAN_FLAG_KEYMAN_KEY_EVENT;
|
|
pInputs[i].ki.dwFlags = ((Queue[n].dwData & 0x0100) ? KEYEVENTF_EXTENDEDKEY : 0);
|
|
pInputs[i].ki.time = 0;
|
|
pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378
|
|
|
|
pInputs[i].type = INPUT_KEYBOARD;
|
|
pInputs[i].ki.wVk = VK_BACK;
|
|
pInputs[i].ki.wScan = SCAN_FLAG_KEYMAN_KEY_EVENT;
|
|
pInputs[i].ki.dwFlags = KEYEVENTF_KEYUP | ((Queue[n].dwData & 0x0100) ? KEYEVENTF_EXTENDEDKEY : 0);
|
|
pInputs[i].ki.time = 0;
|
|
pInputs[i++].ki.dwExtraInfo = 0; //KEYEVENT_EXTRAINFO_KEYMAN; // I4370 // I4378
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
QueueSize = 0;
|
|
|
|
if(ShouldDebug(sdmAIDefault)) {
|
|
for(int j = 0; j < i; j++ ) { // I4548
|
|
SendDebugMessageFormat(0, sdmAIDefault, 0, "App::PostKeys: sending input [i=%d, input[%d]=vk:%s scan:%x flags:%x", i, j, Debug_VirtualKey(pInputs[j].ki.wVk), pInputs[j].ki.wScan, pInputs[j].ki.dwFlags);
|
|
}
|
|
}
|
|
|
|
SetLastError(0);
|
|
|
|
if(i > 0) { // I4452
|
|
_td->pSerialKeyEventClient->SignalServer(pInputs, i);
|
|
}
|
|
|
|
SendDebugMessageFormat(0, sdmAIDefault, 0, "App::PostKeys: sending input finished");
|
|
|
|
delete[] pInputs;
|
|
|
|
return TRUE;
|
|
}
|