https://git.reactos.org/?p=reactos.git;a=commitdiff;h=25b7447818f0fad111607…
commit 25b7447818f0fad1116070598bc88730c90c86b0
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Tue Oct 31 22:37:49 2023 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Oct 31 22:37:49 2023 +0900
[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
---
base/setup/lib/mui.c | 5 +-
win32ss/user/ntuser/defwnd.c | 19 ------
win32ss/user/ntuser/input.h | 4 +-
win32ss/user/ntuser/keyboard.c | 128 ++++++++++++++++++++++++++++++++++-
win32ss/user/ntuser/misc.c | 18 +++--
win32ss/user/ntuser/msgqueue.c | 64 ------------------
win32ss/user/ntuser/ntuser.h | 2 +-
win32ss/user/ntuser/sysparams.c | 7 +-
win32ss/user/user32/windows/defwnd.c | 27 +++++---
9 files changed, 164 insertions(+), 110 deletions(-)
diff --git a/base/setup/lib/mui.c b/base/setup/lib/mui.c
index 8b511cfa56a..cc2bda08eef 100644
--- a/base/setup/lib/mui.c
+++ b/base/setup/lib/mui.c
@@ -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);
diff --git a/win32ss/user/ntuser/defwnd.c b/win32ss/user/ntuser/defwnd.c
index de4b4e12e18..83050064b8c 100644
--- a/win32ss/user/ntuser/defwnd.c
+++ b/win32ss/user/ntuser/defwnd.c
@@ -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 )
{
diff --git a/win32ss/user/ntuser/input.h b/win32ss/user/ntuser/input.h
index 3cae36048f1..35105947d68 100644
--- a/win32ss/user/ntuser/input.h
+++ b/win32ss/user/ntuser/input.h
@@ -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);
diff --git a/win32ss/user/ntuser/keyboard.c b/win32ss/user/ntuser/keyboard.c
index 61f59296be0..3d8bed1ad25 100644
--- a/win32ss/user/ntuser/keyboard.c
+++ b/win32ss/user/ntuser/keyboard.c
@@ -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-…
+ */
+ 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 &&
diff --git a/win32ss/user/ntuser/misc.c b/win32ss/user/ntuser/misc.c
index ae458de7a42..b5b0f27ac0a 100644
--- a/win32ss/user/ntuser/misc.c
+++ b/win32ss/user/ntuser/misc.c
@@ -76,19 +76,27 @@ IntTID2PTI(HANDLE id)
return pti;
}
+/**
+ * @see
https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-…
+ */
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;
}
diff --git a/win32ss/user/ntuser/msgqueue.c b/win32ss/user/ntuser/msgqueue.c
index 7f308530749..a808073374d 100644
--- a/win32ss/user/ntuser/msgqueue.c
+++ b/win32ss/user/ntuser/msgqueue.c
@@ -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),
diff --git a/win32ss/user/ntuser/ntuser.h b/win32ss/user/ntuser/ntuser.h
index 01232f9323a..7c878c4f793 100644
--- a/win32ss/user/ntuser/ntuser.h
+++ b/win32ss/user/ntuser/ntuser.h
@@ -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
diff --git a/win32ss/user/ntuser/sysparams.c b/win32ss/user/ntuser/sysparams.c
index 552a63e1f6a..95bfbe7ca78 100644
--- a/win32ss/user/ntuser/sysparams.c
+++ b/win32ss/user/ntuser/sysparams.c
@@ -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");
diff --git a/win32ss/user/user32/windows/defwnd.c b/win32ss/user/user32/windows/defwnd.c
index cbb421209dc..dbc5b43e9ff 100644
--- a/win32ss/user/user32/windows/defwnd.c
+++ b/win32ss/user/user32/windows/defwnd.c
@@ -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;
- }
-
- //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;
+ hwndFocus = GetFocus();
+ if (hwndFocus && hwndFocus != hWnd &&
+ GetClassLongPtrW(hWnd, GCW_ATOM) != (ULONG_PTR)WC_DIALOG)
+ {
+ return SendMessageW(hwndFocus, Msg, wParam, 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;
}