mirror of
https://github.com/reactos/reactos.git
synced 2024-12-27 09:34:43 +00:00
[SETUPLIB][NTUSER] Toggle input language/layout on Alt+Shift / Ctrl+Shift (#5839)
- Respect the toggle key settings. - Change the hot key settings in base/setup/lib/mui.c. - Revert IntDefWindowProc function about Alt+Shift handling. - Delete some code in co_IntProcessKeyboardMessage for Alt+Shift handling. - Add IntGetNextKL, IntLanguageToggle, and IntCheckLanguageToggle helper functions. - Modify ProcessKeyEvent and UserGetLanguageToggle functions to support [Left Alt]+Shift and Ctrl+Shift. - Improve WM_INPUTLANGCHANGEREQUEST handling. - Message handling shouldn't access kbswitch directly. CORE-10667
This commit is contained in:
parent
8a049d0b68
commit
25b7447818
9 changed files with 164 additions and 110 deletions
|
@ -359,10 +359,7 @@ AddKbLayoutsToRegistry(
|
|||
uIndex++;
|
||||
}
|
||||
|
||||
if (uIndex > 1)
|
||||
AddHotkeySettings(L"2", L"2", L"1");
|
||||
else
|
||||
AddHotkeySettings(L"3", L"3", L"3");
|
||||
AddHotkeySettings(L"1", L"1", L"2");
|
||||
|
||||
NtClose(SubKeyHandle);
|
||||
NtClose(KeyHandle);
|
||||
|
|
|
@ -531,7 +531,6 @@ DefWndScreenshot(PWND pWnd)
|
|||
/*
|
||||
Win32k counterpart of User DefWindowProc
|
||||
*/
|
||||
/* Win: xxxRealDefWindowProc */
|
||||
LRESULT FASTCALL
|
||||
IntDefWindowProc(
|
||||
PWND Wnd,
|
||||
|
@ -946,24 +945,6 @@ IntDefWindowProc(
|
|||
wParamTmp = UserGetKeyState(VK_SHIFT) & 0x8000 ? SC_PREVWINDOW : SC_NEXTWINDOW;
|
||||
co_IntSendMessage( Active, WM_SYSCOMMAND, wParamTmp, wParam );
|
||||
}
|
||||
else if (wParam == VK_SHIFT) // Alt+Shift
|
||||
{
|
||||
RTL_ATOM ClassAtom = 0;
|
||||
UNICODE_STRING ustrClass, ustrWindow;
|
||||
HWND hwndSwitch;
|
||||
|
||||
RtlInitUnicodeString(&ustrClass, L"kbswitcher");
|
||||
RtlInitUnicodeString(&ustrWindow, L"");
|
||||
|
||||
IntGetAtomFromStringOrAtom(&ustrClass, &ClassAtom);
|
||||
|
||||
hwndSwitch = IntFindWindow(UserGetDesktopWindow(), NULL, ClassAtom, &ustrWindow);
|
||||
if (hwndSwitch)
|
||||
{
|
||||
#define ID_NEXTLAYOUT 10003
|
||||
UserPostMessage(hwndSwitch, WM_COMMAND, ID_NEXTLAYOUT, (LPARAM)UserHMGetHandle(Wnd));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( wParam == VK_F10 )
|
||||
{
|
||||
|
|
|
@ -75,8 +75,10 @@ VOID NTAPI UserProcessKeyboardInput(PKEYBOARD_INPUT_DATA pKeyInput);
|
|||
BOOL NTAPI UserSendKeyboardInput(KEYBDINPUT *pKbdInput, BOOL bInjected);
|
||||
PKL NTAPI UserHklToKbl(HKL hKl);
|
||||
BOOL NTAPI UserSetDefaultInputLang(HKL hKl);
|
||||
extern int gLanguageToggleKeyState;
|
||||
extern INT gLanguageToggleKeyState;
|
||||
extern DWORD gdwLanguageToggleKey;
|
||||
extern INT gLayoutToggleKeyState;
|
||||
extern DWORD gdwLayoutToggleKey;
|
||||
|
||||
/* Mouse */
|
||||
WORD FASTCALL UserGetMouseButtonsState(VOID);
|
||||
|
|
|
@ -15,8 +15,10 @@ static BYTE gafAsyncKeyStateRecentDown[256 / 8]; // 1 bit per key
|
|||
static PKEYBOARD_INDICATOR_TRANSLATION gpKeyboardIndicatorTrans = NULL;
|
||||
static KEYBOARD_INDICATOR_PARAMETERS gIndicators = {0, 0};
|
||||
KEYBOARD_ATTRIBUTES gKeyboardInfo;
|
||||
int gLanguageToggleKeyState = 0;
|
||||
DWORD gdwLanguageToggleKey = 0;
|
||||
INT gLanguageToggleKeyState = 0;
|
||||
DWORD gdwLanguageToggleKey = 1;
|
||||
INT gLayoutToggleKeyState = 0;
|
||||
DWORD gdwLayoutToggleKey = 2;
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
|
@ -791,6 +793,92 @@ cleanup:
|
|||
UserReleaseDC(pWnd, hdc, FALSE);
|
||||
}
|
||||
|
||||
/* Find the next/previous keyboard layout of the same/different language */
|
||||
static PKL FASTCALL
|
||||
IntGetNextKL(
|
||||
_In_ PKL pKL,
|
||||
_In_ BOOL bNext,
|
||||
_In_ BOOL bSameLang)
|
||||
{
|
||||
PKL pFirstKL = pKL;
|
||||
LANGID LangID = LOWORD(pKL->hkl);
|
||||
|
||||
do
|
||||
{
|
||||
pKL = (bNext ? pKL->pklNext : pKL->pklPrev);
|
||||
|
||||
if (!(pKL->dwKL_Flags & KLF_UNLOAD) && bSameLang == (LangID == LOWORD(pKL->hkl)))
|
||||
return pKL;
|
||||
} while (pKL != pFirstKL);
|
||||
|
||||
return pFirstKL;
|
||||
}
|
||||
|
||||
/* Perform layout toggle by [Left Alt]+Shift or Ctrl+Shift */
|
||||
static VOID
|
||||
IntLanguageToggle(
|
||||
_In_ PUSER_MESSAGE_QUEUE pFocusQueue,
|
||||
_In_ BOOL bSameLang,
|
||||
_In_ INT nKeyState)
|
||||
{
|
||||
PWND pWnd = pFocusQueue->spwndFocus;
|
||||
HWND hWnd;
|
||||
WPARAM wParam = 0;
|
||||
PTHREADINFO pti;
|
||||
PKL pkl;
|
||||
|
||||
if (!pWnd)
|
||||
pWnd = pFocusQueue->spwndActive;
|
||||
if (!pWnd)
|
||||
return;
|
||||
|
||||
pti = pWnd->head.pti;
|
||||
pkl = pti->KeyboardLayout;
|
||||
|
||||
if (nKeyState == INPUTLANGCHANGE_FORWARD)
|
||||
pkl = IntGetNextKL(pkl, TRUE, bSameLang);
|
||||
else if (nKeyState == INPUTLANGCHANGE_BACKWARD)
|
||||
pkl = IntGetNextKL(pkl, FALSE, bSameLang);
|
||||
|
||||
if (gSystemFS & pkl->dwFontSigs)
|
||||
wParam |= INPUTLANGCHANGE_SYSCHARSET;
|
||||
|
||||
hWnd = UserHMGetHandle(pWnd);
|
||||
UserPostMessage(hWnd, WM_INPUTLANGCHANGEREQUEST, wParam, (LPARAM)pkl->hkl);
|
||||
}
|
||||
|
||||
/* Check Language Toggle by [Left Alt]+Shift or Ctrl+Shift */
|
||||
static BOOL
|
||||
IntCheckLanguageToggle(
|
||||
_In_ PUSER_MESSAGE_QUEUE pFocusQueue,
|
||||
_In_ BOOL bIsDown,
|
||||
_In_ WORD wVk,
|
||||
_Inout_ PINT pKeyState)
|
||||
{
|
||||
if (bIsDown) /* Toggle key combination is pressed? */
|
||||
{
|
||||
if (wVk == VK_LSHIFT)
|
||||
*pKeyState = INPUTLANGCHANGE_FORWARD;
|
||||
else if (wVk == VK_RSHIFT)
|
||||
*pKeyState = INPUTLANGCHANGE_BACKWARD;
|
||||
else if (!wVk && IS_KEY_DOWN(gafAsyncKeyState, VK_LSHIFT))
|
||||
*pKeyState = INPUTLANGCHANGE_FORWARD;
|
||||
else if (!wVk && IS_KEY_DOWN(gafAsyncKeyState, VK_RSHIFT))
|
||||
*pKeyState = INPUTLANGCHANGE_BACKWARD;
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*pKeyState == 0)
|
||||
return FALSE;
|
||||
|
||||
IntLanguageToggle(pFocusQueue, (pKeyState == &gLayoutToggleKeyState), *pKeyState);
|
||||
*pKeyState = 0;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* UserSendKeyboardInput
|
||||
*
|
||||
|
@ -808,6 +896,7 @@ ProcessKeyEvent(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD d
|
|||
BOOL bWasSimpleDown = FALSE, bPostMsg = TRUE, bIsSimpleDown;
|
||||
MSG Msg;
|
||||
static BOOL bMenuDownRecently = FALSE;
|
||||
BOOL bLangToggled = FALSE;
|
||||
|
||||
/* Get virtual key without shifts (VK_(L|R)* -> VK_*) */
|
||||
wSimpleVk = IntSimplifyVk(wVk);
|
||||
|
@ -906,6 +995,41 @@ ProcessKeyEvent(WORD wVk, WORD wScanCode, DWORD dwFlags, BOOL bInjected, DWORD d
|
|||
TRACE("Alt-Tab/Esc Pressed wParam %x\n",wVk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check Language/Layout Toggle by [Left Alt]+Shift or Ctrl+Shift.
|
||||
* @see https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc976564%28v=technet.10%29
|
||||
*/
|
||||
if (gdwLanguageToggleKey == 1 || gdwLanguageToggleKey == 2)
|
||||
{
|
||||
if (wSimpleVk == VK_SHIFT) /* Shift key is pressed or released */
|
||||
{
|
||||
UINT targetKey = ((gdwLanguageToggleKey == 1) ? VK_LMENU : VK_CONTROL);
|
||||
if (IS_KEY_DOWN(gafAsyncKeyState, targetKey))
|
||||
bLangToggled = IntCheckLanguageToggle(pFocusQueue, bIsDown, wVk, &gLanguageToggleKeyState);
|
||||
}
|
||||
else if ((wSimpleVk == VK_MENU && gdwLanguageToggleKey == 1) ||
|
||||
(wSimpleVk == VK_CONTROL && gdwLanguageToggleKey == 2))
|
||||
{
|
||||
if (IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT))
|
||||
bLangToggled = IntCheckLanguageToggle(pFocusQueue, bIsDown, 0, &gLanguageToggleKeyState);
|
||||
}
|
||||
}
|
||||
if (!bLangToggled && (gdwLayoutToggleKey == 1 || gdwLayoutToggleKey == 2))
|
||||
{
|
||||
if (wSimpleVk == VK_SHIFT) /* Shift key is pressed or released */
|
||||
{
|
||||
UINT targetKey = ((gdwLayoutToggleKey == 1) ? VK_LMENU : VK_CONTROL);
|
||||
if (IS_KEY_DOWN(gafAsyncKeyState, targetKey))
|
||||
IntCheckLanguageToggle(pFocusQueue, bIsDown, wVk, &gLayoutToggleKeyState);
|
||||
}
|
||||
else if ((wSimpleVk == VK_MENU && gdwLayoutToggleKey == 1) ||
|
||||
(wSimpleVk == VK_CONTROL && gdwLayoutToggleKey == 2))
|
||||
{
|
||||
if (IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT))
|
||||
IntCheckLanguageToggle(pFocusQueue, bIsDown, 0, &gLayoutToggleKeyState);
|
||||
}
|
||||
}
|
||||
|
||||
if (bIsDown && wVk == VK_SNAPSHOT)
|
||||
{
|
||||
if (pFocusQueue &&
|
||||
|
|
|
@ -76,19 +76,27 @@ IntTID2PTI(HANDLE id)
|
|||
return pti;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc976564%28v=technet.10%29
|
||||
*/
|
||||
DWORD
|
||||
FASTCALL
|
||||
UserGetLanguageToggle(VOID)
|
||||
UserGetLanguageToggle(
|
||||
_In_ PCWSTR pszType,
|
||||
_In_ DWORD dwDefaultValue)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
DWORD dwValue = 0;
|
||||
DWORD dwValue = dwDefaultValue;
|
||||
WCHAR szBuff[4];
|
||||
|
||||
Status = RegReadUserSetting(L"Keyboard Layout\\Toggle", L"Layout Hotkey", REG_SZ, &dwValue, sizeof(dwValue));
|
||||
Status = RegReadUserSetting(L"Keyboard Layout\\Toggle", pszType, REG_SZ, szBuff, sizeof(szBuff));
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
dwValue = atoi((char *)&dwValue);
|
||||
TRACE("Layout Hotkey %d\n",dwValue);
|
||||
szBuff[RTL_NUMBER_OF(szBuff) - 1] = UNICODE_NULL;
|
||||
dwValue = _wtoi(szBuff);
|
||||
}
|
||||
|
||||
TRACE("%ls: %lu\n", pszType, dwValue);
|
||||
return dwValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1770,7 +1770,6 @@ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
|
|||
PWND pWnd;
|
||||
UINT ImmRet;
|
||||
BOOL Ret = TRUE;
|
||||
WPARAM wParam = Msg->wParam;
|
||||
PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
|
||||
|
||||
if (Msg->message == VK_PACKET)
|
||||
|
@ -1852,69 +1851,6 @@ BOOL co_IntProcessKeyboardMessage(MSG* Msg, BOOL* RemoveMessages)
|
|||
}
|
||||
}
|
||||
|
||||
if ( *RemoveMessages && (Msg->message == WM_SYSKEYDOWN || Msg->message == WM_KEYDOWN) )
|
||||
{
|
||||
if (gdwLanguageToggleKey < 3)
|
||||
{
|
||||
if (IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL)) // L Alt 1 or Ctrl 2 .
|
||||
{
|
||||
if ( wParam == VK_LSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_FORWARD; // Left Alt - Left Shift, Next
|
||||
//// FIXME : It seems to always be VK_LSHIFT.
|
||||
if ( wParam == VK_RSHIFT ) gLanguageToggleKeyState = INPUTLANGCHANGE_BACKWARD; // Left Alt - Right Shift, Previous
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//// Key Up! Alt Key Ctrl Key
|
||||
if ( *RemoveMessages && (Msg->message == WM_SYSKEYUP || Msg->message == WM_KEYUP) )
|
||||
{
|
||||
// When initializing win32k: Reading from the registry hotkey combination
|
||||
// to switch the keyboard layout and store it to global variable.
|
||||
// Using this combination of hotkeys in this function
|
||||
|
||||
if ( gdwLanguageToggleKey < 3 &&
|
||||
IS_KEY_DOWN(gafAsyncKeyState, gdwLanguageToggleKey == 1 ? VK_LMENU : VK_CONTROL) )
|
||||
{
|
||||
if ( Msg->wParam == VK_SHIFT && !(IS_KEY_DOWN(gafAsyncKeyState, VK_SHIFT)))
|
||||
{
|
||||
WPARAM wParamILR;
|
||||
PKL pkl = pti->KeyboardLayout;
|
||||
|
||||
if (pWnd) UserDerefObjectCo(pWnd);
|
||||
|
||||
//// Seems to override message window.
|
||||
if (!(pWnd = pti->MessageQueue->spwndFocus))
|
||||
{
|
||||
pWnd = pti->MessageQueue->spwndActive;
|
||||
}
|
||||
if (pWnd) UserRefObjectCo(pWnd, &Ref);
|
||||
|
||||
if (pkl != NULL && gLanguageToggleKeyState)
|
||||
{
|
||||
TRACE("Posting WM_INPUTLANGCHANGEREQUEST KeyState %d\n", gLanguageToggleKeyState );
|
||||
|
||||
wParamILR = gLanguageToggleKeyState;
|
||||
// If system character set and font signature send flag.
|
||||
if ( gSystemFS & pkl->dwFontSigs )
|
||||
{
|
||||
wParamILR |= INPUTLANGCHANGE_SYSCHARSET;
|
||||
}
|
||||
|
||||
UserPostMessage( UserHMGetHandle(pWnd),
|
||||
WM_INPUTLANGCHANGEREQUEST,
|
||||
wParamILR,
|
||||
(LPARAM)pkl->hkl );
|
||||
|
||||
gLanguageToggleKeyState = 0;
|
||||
//// Keep looping.
|
||||
Ret = FALSE;
|
||||
//// Skip the rest.
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (co_HOOK_CallHooks( WH_KEYBOARD,
|
||||
*RemoveMessages ? HC_ACTION : HC_NOREMOVE,
|
||||
LOWORD(Msg->wParam),
|
||||
|
|
|
@ -37,7 +37,7 @@ VOID FASTCALL UserEnterExclusive(VOID);
|
|||
VOID FASTCALL UserLeave(VOID);
|
||||
BOOL FASTCALL UserIsEntered(VOID);
|
||||
BOOL FASTCALL UserIsEnteredExclusive(VOID);
|
||||
DWORD FASTCALL UserGetLanguageToggle(VOID);
|
||||
DWORD FASTCALL UserGetLanguageToggle(_In_ LPCWSTR pszType, _In_ DWORD dwDefaultValue);
|
||||
|
||||
_Success_(return != FALSE)
|
||||
BOOL
|
||||
|
|
|
@ -355,7 +355,8 @@ SpiUpdatePerUserSystemParameters(VOID)
|
|||
if (SPITESTPREF(UPM_COMBOBOXANIMATION)) gpsi->PUSIFlags |= PUSIF_COMBOBOXANIMATION;
|
||||
if (SPITESTPREF(UPM_LISTBOXSMOOTHSCROLLING)) gpsi->PUSIFlags |= PUSIF_LISTBOXSMOOTHSCROLLING;
|
||||
}
|
||||
gdwLanguageToggleKey = UserGetLanguageToggle();
|
||||
gdwLanguageToggleKey = UserGetLanguageToggle(L"Language Hotkey", 1);
|
||||
gdwLayoutToggleKey = UserGetLanguageToggle(L"Layout Hotkey", 2);
|
||||
|
||||
g_bWindowSnapEnabled = IntIsWindowSnapEnabled();
|
||||
}
|
||||
|
@ -1470,9 +1471,9 @@ SpiGetSet(UINT uiAction, UINT uiParam, PVOID pvParam, FLONG fl)
|
|||
}
|
||||
|
||||
case SPI_SETLANGTOGGLE:
|
||||
gdwLanguageToggleKey = UserGetLanguageToggle();
|
||||
gdwLayoutToggleKey = UserGetLanguageToggle(L"Layout Hotkey", 2);
|
||||
gdwLanguageToggleKey = UserGetLanguageToggle(L"Language Hotkey", 1);
|
||||
return gdwLanguageToggleKey;
|
||||
break;
|
||||
|
||||
case SPI_GETWINDOWSEXTENSION:
|
||||
ERR("SPI_GETWINDOWSEXTENSION is unimplemented\n");
|
||||
|
|
|
@ -547,22 +547,27 @@ User32DefWindowProc(HWND hWnd,
|
|||
|
||||
case WM_INPUTLANGCHANGEREQUEST:
|
||||
{
|
||||
HKL NewHkl;
|
||||
HKL hNewKL;
|
||||
HWND hwndFocus;
|
||||
|
||||
if(wParam & INPUTLANGCHANGE_BACKWARD
|
||||
&& wParam & INPUTLANGCHANGE_FORWARD)
|
||||
{
|
||||
if ((wParam & INPUTLANGCHANGE_BACKWARD) && (wParam & INPUTLANGCHANGE_FORWARD))
|
||||
return FALSE;
|
||||
|
||||
hwndFocus = GetFocus();
|
||||
if (hwndFocus && hwndFocus != hWnd &&
|
||||
GetClassLongPtrW(hWnd, GCW_ATOM) != (ULONG_PTR)WC_DIALOG)
|
||||
{
|
||||
return SendMessageW(hwndFocus, Msg, wParam, lParam);
|
||||
}
|
||||
|
||||
//FIXME: What to do with INPUTLANGCHANGE_SYSCHARSET ?
|
||||
|
||||
if(wParam & INPUTLANGCHANGE_BACKWARD) NewHkl = (HKL) HKL_PREV;
|
||||
else if(wParam & INPUTLANGCHANGE_FORWARD) NewHkl = (HKL) HKL_NEXT;
|
||||
else NewHkl = (HKL) lParam;
|
||||
|
||||
NtUserActivateKeyboardLayout(NewHkl, KLF_SETFORPROCESS);
|
||||
if (wParam & INPUTLANGCHANGE_FORWARD)
|
||||
hNewKL = (HKL)UlongToHandle(HKL_NEXT);
|
||||
else if (wParam & INPUTLANGCHANGE_BACKWARD)
|
||||
hNewKL = (HKL)UlongToHandle(HKL_PREV);
|
||||
else
|
||||
hNewKL = (HKL)lParam;
|
||||
|
||||
NtUserActivateKeyboardLayout(hNewKL, KLF_SETFORPROCESS);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue