spiegel-keyman/windows/src/engine/keyman32/kmhook_keyboard.cpp

193 lines
8.6 KiB
C++

/*
Name: kmhook_keyboard
Copyright: Copyright (C) SIL International.
Documentation:
Description:
Create Date: 1 Aug 2006
Modified Date: 25 Oct 2016
Authors: mcdurdin
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
History: 01 Aug 2006 - mcdurdin - Hotkeys testing
14 Sep 2006 - mcdurdin - Initialise process when no messages have been passed
30 May 2007 - mcdurdin - I864 - Log exceptions in hook procedures
13 Jul 2007 - mcdurdin - I934 - Prep for x64
23 Aug 2007 - mcdurdin - I719 - Fix Alt+LeftShift and Word interactions
05 Nov 2007 - mcdurdin - I1087 - Add language switching hotkeys for Desktop Pro
16 Jan 2009 - mcdurdin - I1512 - Support SendInput
09 Mar 2009 - mcdurdin - I1848 - Keyboard hotkeys interfere with Ctrl+Shift and Alt+Shift
11 Mar 2009 - mcdurdin - I1894 - Fix threading bugs introduced in I1888
23 Apr 2009 - mcdurdin - I1940 - Generate a minidump when an exception occurs in a hook
11 Dec 2009 - mcdurdin - I934 - x64 - Initial version
11 Dec 2009 - mcdurdin - I934 - x64 - per thread keyboard hooks
11 Dec 2009 - mcdurdin - I934 - x64 - test when keyman has shutdown and disconnect
12 Mar 2010 - mcdurdin - I934 - x64 - Complete
12 Mar 2010 - mcdurdin - I2229 - Remove hints and warnings
04 May 2010 - mcdurdin - I2356 - Performance - don't clear keyboard hook if new focus is on same thread
04 May 2010 - mcdurdin - I2349 - Pause key to signal new debug log file
04 May 2010 - mcdurdin - I2351 - Robustness - verify _td return value
10 May 2010 - mcdurdin - Enable exception logging
22 Oct 2010 - mcdurdin - I2522 - Language switch window initial version
26 Jun 2012 - mcdurdin - I3377 - KM9 - Update code references from 8.0 to 9.0
23 Dec 2011 - mcdurdin - I3191 - Corruption of keyboard selection cache between x86 and x64
18 Feb 2012 - mcdurdin - I3242 - Arrow keys do not function correctly in Internet Explorer
21 Feb 2012 - mcdurdin - I3250 - Word 2010 sometimes freezes after hotkey pressed
23 Mar 2012 - mcdurdin - I3284 - Fix blocking of Ctrl+Shift passthrough to other hooks
03 May 2012 - mcdurdin - I3301 - Resolve regression introduced by I3250 with Alt inadvertently activating menus
15 Jun 2012 - mcdurdin - I3358 - Media keys generate characters when positional keyboard is active
04 Nov 2012 - mcdurdin - I3534 - V9.0 - Merge of I3301 - Resolve regression introduced by I3250 with Alt inadvertently activating menus
04 Nov 2012 - mcdurdin - I3527 - V9.0 - Merge of I3242 - Arrow keys do not function correctly in Internet Explorer
04 Nov 2012 - mcdurdin - I3535 - V9.0 - Merge of I3358 - Media keys generate characters when positional keyboard is active
04 Nov 2012 - mcdurdin - I3529 - V9.0 - Merge of I3284 - Fix blocking of Ctrl+Shift passthrough to other hooks
04 Nov 2012 - mcdurdin - I3526 - V9.0 - Merge of I3191 - Corruption of keyboard selection cache between x86 and x64
17 Nov 2012 - mcdurdin - I3576 - V9.0 - Keyboard hook should avoid processing any keys when KMTIP is active
28 Nov 2012 - mcdurdin - I3596 - V9.0 - Remove keyboard hook
28 Nov 2012 - mcdurdin - I3594 - V9.0 - Remove old SelectKeyboard code and related messages
01 Dec 2012 - mcdurdin - I3617 - V9.0 - Keyboard hook obsolete, strip out code
06 Mar 2014 - mcdurdin - I4124 - V9.0 - Language switch dialog is not working in v9
24 Apr 2014 - mcdurdin - I4197 - V9.0 - Avoid interactions with full-screen RDP
01 May 2014 - mcdurdin - I4203 - V9.0 - Order that modifiers are depressed changes actions when Keyman is running
03 Aug 2014 - mcdurdin - I4326 - V9.0 - Switch-off hotkey not working, then keyboard hotkey stopped working (win 8.1 jeremy) [High]
31 Dec 2014 - mcdurdin - I4548 - V9.0 - When Alt is down, release of Ctrl, Shift is not detectable within TIP in some languages
27 Mar 2015 - mcdurdin - I4641 - V9.0 - Keyman can crash silently on exit due to null hotkeys being addressed
09 Aug 2015 - mcdurdin - I4844 - Tidy up PostDummyKeyEvent calls
25 Oct 2016 - mcdurdin - I5136 - Remove additional product references from Keyman Engine
*/
// I4326
#include "keyman64.h"
#include <Psapi.h>
#ifdef _WIN64
#error kmhook_keyboard.cpp is not required for win64.
#endif
// I3617
BOOL IsLanguageSwitchWindowVisible();
void SendToLanguageSwitchWindow(WPARAM wParam, LPARAM lParam);
BOOL ForegroundWindowIsRDP(); // I4197
BOOL InLanguageSwitchKeySequence = FALSE;
HWND hwndLanguageSwitch = 0;
BOOL ForegroundWindowIsRDP() { // I4197
DWORD dwProcessId;
HWND hwnd = GetForegroundWindow();
if(hwnd == NULL) {
return FALSE;
}
if(GetWindowThreadProcessId(hwnd, &dwProcessId) == 0) {
return FALSE;
}
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, dwProcessId);
if(hProcess == NULL) {
return FALSE;
}
char buf[260];
BOOL bResult = GetProcessImageFileName(hProcess, buf, _countof(buf)) > 0;
CloseHandle(hProcess);
if(bResult) {
char *p = strrchr(buf, '\\');
bResult = p && _stricmp(p, "\\mstsc.exe") == 0;
}
return bResult;
}
BOOL KeyLanguageSwitchPress(WPARAM wParam, BOOL extended, BOOL isUp, DWORD ShiftState)
{
/* Let's avoid the cascaded remote desktop switching issues */
if(ForegroundWindowIsRDP()) return FALSE; // I4197
/* This is a special-case hotkey for language switching - ALT+LEFT SHIFT */
Hotkeys *hotkeys = Hotkeys::Instance(); // I4641
if(!hotkeys) {
return FALSE;
}
Hotkey *hotkey = hotkeys->GetHotkey(HK_ALT | HK_SHIFT); // I4641
if(!hotkey)
{
hotkey = hotkeys->GetHotkey(HK_CTRL | HK_SHIFT); // I4641
if(!hotkey) return FALSE;
}
if((hotkey->HotkeyValue & HK_CTRL) && (wParam == VK_CONTROL || wParam == VK_LCONTROL || wParam == VK_RCONTROL) && !isUp && (ShiftState & K_MODIFIERFLAG & ~(LCTRLFLAG|RCTRLFLAG)) == 0) // I4124
{
InLanguageSwitchKeySequence = TRUE;
return FALSE;
}
else if((hotkey->HotkeyValue & HK_ALT) && (wParam == VK_MENU || wParam == VK_LMENU || wParam == VK_RMENU) && !extended && !isUp && (ShiftState & K_MODIFIERFLAG & ~LALTFLAG) == 0) // I4124
{
InLanguageSwitchKeySequence = TRUE;
return FALSE;
}
else if(InLanguageSwitchKeySequence)
{
if(wParam == VK_SHIFT || wParam == VK_LSHIFT || wParam == VK_RSHIFT) // I4124
{
if(isUp)
{
InLanguageSwitchKeySequence = FALSE;
//ReportActiveKeyboard(_td, 0);
Globals::PostControllers(wm_keyman_control, MAKELONG(KMC_INTERFACEHOTKEY, hotkey->Target), 0);
PostDummyKeyEvent(); // I4124 // I4844
keybd_event(VK_SHIFT, SCAN_FLAG_KEYMAN_KEY_EVENT, KEYEVENTF_KEYUP, 0); // I4203
return TRUE;
}
return FALSE;
}
else
InLanguageSwitchKeySequence = FALSE;
return FALSE;
}
return FALSE;
}
BOOL IsLanguageSwitchWindowVisible() {
hwndLanguageSwitch = FindWindow("TfrmLanguageSwitch", NULL);
if(hwndLanguageSwitch == NULL) return FALSE;
return IsWindowVisible(hwndLanguageSwitch);
}
void SendToLanguageSwitchWindow(WPARAM wParam, LPARAM lParam) {
DWORD keyFlags = (DWORD) lParam; // I4124
PostMessage(hwndLanguageSwitch, wm_keyman_control, keyFlags & LLKHF_UP ? KMC_KEYUP : KMC_KEYDOWN, wParam); // I4124
}
int ProcessLanguageSwitchShiftKey(WPARAM wParam, BOOL isUp)
{
if(!isUp) return 1;
/* When a ctrl, shift or alt is released we want to know about it, so we can update shift states etc */
switch(wParam) // I4548
{
case VK_LSHIFT:
case VK_RSHIFT:
case VK_SHIFT:
case VK_CONTROL:
case VK_LCONTROL: // I4124
case VK_RCONTROL: // I4124
case VK_MENU:
case VK_LMENU: // I4124
case VK_RMENU: // I4124
break;
default:
return 1;
}
/* Generate a dummy keystroke to block menu activations, etc but let the shift key through */
PostDummyKeyEvent(); // I3301 - this is imperfect because we don't deal with HC_NOREMOVE. But good enough? // I3534 // I4844
return 0;
}