spiegel-keyman/windows/src/engine/keyman32/selectkeyboard.cpp
2020-10-02 14:54:43 +10:00

220 lines
10 KiB
C++

/*
Name: selectkeyboard
Copyright: Copyright (C) SIL International.
Documentation:
Description:
Create Date: 6 Apr 2010
Modified Date: 25 Oct 2016
Authors: mcdurdin
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
History: 06 Apr 2010 - mcdurdin - I2271 - Select Keyboard tidy up
19 Apr 2010 - mcdurdin - I2297 - Use global cache to remember last active keyboard for all apps
19 Apr 2010 - mcdurdin - I2297 - Rewrite SelectKeyboard to reduce complexity and increase stability
04 May 2010 - mcdurdin - I2351 - Robustness - verify _td return value
04 May 2010 - mcdurdin - I2297 - Rewrite cache code to share across all apps using file mapping
15 Jun 2010 - mcdurdin - I2425 - Vista security incorrectly applied to WinXP
29 Jun 2010 - mcdurdin - I2441 - SelectKeyboard cache was not zero-initialised at startup
30 Nov 2010 - mcdurdin - I2543 - Support switching to TSF TIPs
30 Nov 2010 - mcdurdin - I2545 - Fix switching to default Windows keyboard from lang switch window
17 Dec 2010 - mcdurdin - I2572 - Keyman keyboard switch has to go twice, also I2557
18 Mar 2011 - mcdurdin - I2779 - HKLs with high bit set do not get selected correctly
19 Aug 2011 - mcdurdin - I3040 - keyman32.dll can crash if advapi32.dll is not loaded when first called from a process
17 Oct 2011 - mcdurdin - I3109 - Language Switcher does not show active HKL until first language switch after keyman started
02 Dec 2011 - mcdurdin - I3159 - When multiple OEM products installed, hotkeys can activate keyboards for non-running products
23 Dec 2011 - mcdurdin - I3191 - Corruption of keyboard selection cache between x86 and x64
24 Jan 2012 - mcdurdin - I3143 - Report more useful information when Keyman fails to start
06 Feb 2012 - mcdurdin - I3227 - When switching keyboards and typing rapidly, Windows/Keyman keyboard links can get out of sync
04 Nov 2012 - mcdurdin - I3537 - V9.0 - Merge of I3159 - When multiple OEM products installed, hotkeys can activate keyboards for non-running products
04 Nov 2012 - mcdurdin - I3523 - V9.0 - Merge of I3143 - Report more useful information when Keyman fails to start
04 Nov 2012 - mcdurdin - I3526 - V9.0 - Merge of I3191 - Corruption of keyboard selection cache between x86 and x64
04 Nov 2012 - mcdurdin - I3538 - V9.0 - Merge of I3227 - When switching keyboards and typing rapidly, Windows/Keyman keyboard links can get out of sync
28 Nov 2012 - mcdurdin - I3594 - V9.0 - Remove old SelectKeyboard code and related messages
07 Nov 2013 - mcdurdin - I3949 - V9.0 - Keyboard selection and notification needs consolidation
21 Feb 2014 - mcdurdin - I4066 - V9.0 - Keyman Desktop needs to run in a lockdown mode when expired so developers can still use it
28 May 2014 - mcdurdin - I4220 - V9.0 - Remove references to LoadKeyboardLayout, Preload, Substitutes, etc. and use only TSF
16 Jun 2014 - mcdurdin - I4271 - V9.0 - Switch language for all applications is not working
23 Jun 2014 - mcdurdin - I4287 - V9.0 - Remove extraneous AppIntegration class type tests
23 Jun 2014 - mcdurdin - I4277 - V9.0 - Switch from Keyman to Keyman keyboard causes loop in global language switch
23 Jun 2014 - mcdurdin - I4285 - V9.0 - Profile change needs debug data for tracing source profile change thread
14 May 2015 - mcdurdin - I4714 - V9.0 - Keyboard and language hotkeys don't always work
25 Oct 2016 - mcdurdin - I5136 - Remove additional product references from Keyman Engine
*/
#include "pch.h" // I5136
#include "accctrl.h"
#include "aclapi.h"
#include "sddl.h"
#include "SharedBuffers.h"
// I3594 // I4220
BOOL SelectKeyboard(DWORD KeymanID)
{
int i;
HWND hwnd = GetFocus();
PKEYMAN64THREADDATA _td = ThreadGlobals();
if(!_td) return FALSE;
SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard-------------------------------------------");
SendDebugMessageFormat(hwnd,sdmGlobal,0,"ENTER SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d",
GetKeyboardLayout(0),
_td->ActiveKeymanID,
_td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name,
//_td->NextKeyboardLayout,
KeymanID);
__try
{
if(_td->ForceFileName[0])
{
SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Ignored due to ForceFile");
return FALSE; // Keyboard file is force-loaded
}
KMHideIM();
if(_td->lpActiveKeyboard) DeactivateDLLs(_td->lpActiveKeyboard);
_td->lpActiveKeyboard = NULL;
_td->ActiveKeymanID = KEYMANID_NONKEYMAN;
//SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: nKeyboards=%d", nKeyboards);
for(i = 0; i < _td->nKeyboards; i++)
{
if(_td->lpKeyboards[i].KeymanID == KeymanID)
{
if(!_td->lpKeyboards[i].Keyboard && !LoadlpKeyboard(i))
{
SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Unable to load");
return TRUE;
}
_td->lpActiveKeyboard = &_td->lpKeyboards[i];
_td->ActiveKeymanID = _td->lpActiveKeyboard->KeymanID;
SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: NewKeymanID: %x", _td->ActiveKeymanID);
if(_td->app) _td->app->ResetContext();
ResetCapsLock();
SelectApplicationIntegration(); // I4287
if(_td->app && !_td->app->IsWindowHandled(hwnd)) _td->app->HandleWindow(hwnd);
_td->state.windowunicode = !_td->app || _td->app->IsUnicode();
ActivateDLLs(_td->lpActiveKeyboard);
return TRUE;
}
}
if(IsFocusedThread())
{
SendDebugMessageFormat(hwnd,sdmGlobal,0,"SelectKeyboard: Keyboard Not Found");
}
}
__finally
{
SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard: Current:(HKL=%x KeymanID=%x %s) New:(ID=%x)", //lpActiveKeyboard=%s ActiveKeymanID: %x sk: %x KeymanID: %d",
GetKeyboardLayout(0),
_td->ActiveKeymanID,
_td->lpActiveKeyboard == NULL ? "NULL" : _td->lpActiveKeyboard->Name,
KeymanID);
SendDebugMessageFormat(hwnd,sdmGlobal,0,"EXIT SelectKeyboard-------------------------------------------");
}
return TRUE;
}
BOOL SelectKeyboardTSF(PKEYMAN64THREADDATA _td, DWORD dwIdentity, BOOL foreground) // I3933 // I3949 // I4271
{
if (!foreground && IsFocusedThread()) {
return FALSE; // I4277
}
ISharedBufferManager *sbm = GetThreadSharedBufferManager();
if (!sbm) {
return FALSE;
}
SelectKeyboardBuffer skb;
if(!sbm->ReadSelectKeyboardBuffer(dwIdentity, &skb)) {
return FALSE;
}
if(!OpenTSF(_td)) return FALSE;
BOOL bResult = FALSE;
SendDebugMessageFormat(0, sdmGlobal, 0, "SelectKeyboardTSF: Selecting language identity=%d %x [%d]", dwIdentity, skb.LangID, foreground);
HRESULT hr = _td->pInputProcessorProfiles->ChangeCurrentLanguage(skb.LangID);
if(SUCCEEDED(hr)) {
SendDebugMessageFormat(0, sdmGlobal, 0, "SelectKeyboardTSF: Activating profile");
hr = _td->pInputProcessorProfileMgr->ActivateProfile(TF_PROFILETYPE_INPUTPROCESSOR, skb.LangID, skb.CLSID, skb.GUIDProfile, NULL, TF_IPPMF_DONTCARECURRENTINPUTLANGUAGE); // I4714
bResult = SUCCEEDED(hr);
}
SendDebugMessageFormat(0, sdmGlobal, 0, "SelectKeyboardTSF: Exiting with %x", hr);
return bResult;
}
void SelectKeyboardHKL(PKEYMAN64THREADDATA _td, DWORD hkl, BOOL foreground) { // I3933 // I3949 // I4271
if(!foreground && IsFocusedThread()) {
return; // I4277
}
if(OpenTSF(_td)) {
LANGID langid = HKLToLanguageID(ForceKeymanIDToHKL(hkl)); // I3191
SendDebugMessageFormat(0, sdmGlobal, 0, "SelectKeyboardHKL: Activating language %x [%d]", langid, foreground);
HRESULT hr = _td->pInputProcessorProfiles->ChangeCurrentLanguage(langid);
if(SUCCEEDED(hr)) {
SendDebugMessageFormat(0, sdmGlobal, 0, "SelectKeyboardHKL: Activating keyboard layout %x for %x", hkl, langid);
hr = _td->pInputProcessorProfileMgr->ActivateProfile(TF_PROFILETYPE_KEYBOARDLAYOUT, langid, CLSID_NULL, GUID_NULL, ForceKeymanIDToHKL(hkl), TF_IPPMF_DONTCARECURRENTINPUTLANGUAGE); // I3191 // I4714
}
SendDebugMessageFormat(0, sdmGlobal, 0, "SelectKeyboardHKL: Exiting with %x", hr);
}
}
void PrepareLanguageSwitchString(UINT langid, HKL hkl, char *str) {
wsprintf(str, "%d|%d|%d", (int) GetCurrentThreadId(), langid, (int) hkl); // I4285
}
void PrepareLanguageSwitchString(UINT langid, GUID clsid, GUID guidProfile, char *str) {
WCHAR clsidstr[40], profilestr[40];
StringFromGUID2(clsid, clsidstr, _countof(clsidstr));
StringFromGUID2(guidProfile, profilestr, _countof(profilestr));
wsprintf(str, "%d|%d|%ls|%ls", (int) GetCurrentThreadId(), langid, clsidstr, profilestr); // I4285
}
void ReportActiveKeyboard(PKEYMAN64THREADDATA _td, WORD wCommand) { // I3933 // I3949
//OutputDebugString("ReportActiveKeyboard\n");
if(OpenTSF(_td) && IsFocusedThread()) { // I4277
TF_INPUTPROCESSORPROFILE profile;
if(SUCCEEDED(_td->pInputProcessorProfileMgr->GetActiveProfile(GUID_TFCAT_TIP_KEYBOARD, &profile))) {
ReportKeyboardChanged(wCommand, profile.dwProfileType, profile.langid, profile.hkl, profile.clsid, profile.guidProfile);
}
}
}
BOOL ReportKeyboardChanged(WORD wCommand, DWORD dwProfileType, UINT langid, HKL hkl, GUID clsid, GUID guidProfile) {
char str[128];
//OutputDebugString(" ReportKeyboardChanged: ");
if (dwProfileType == TF_PROFILETYPE_KEYBOARDLAYOUT) {
PrepareLanguageSwitchString(langid, hkl, str);
}
else if (dwProfileType == TF_PROFILETYPE_INPUTPROCESSOR) {
PrepareLanguageSwitchString(langid, clsid, guidProfile, str);
}
else {
return FALSE;
}
//OutputDebugStringA(str);
//OutputDebugString("\n");
WORD wAtom = GlobalAddAtom(str); // TODO: stop abusing atoms and use a rolling shared memory buffer with index
Globals::PostMasterController(wm_keyman_control, KMC_PROFILECHANGED, MAKELONG(wCommand, wAtom));
return TRUE;
}