https://git.reactos.org/?p=reactos.git;a=commitdiff;h=25b7447818f0fad1116070598bc88730c90c86b0

commit 25b7447818f0fad1116070598bc88730c90c86b0
Author:     Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com>
AuthorDate: Tue Oct 31 22:37:49 2023 +0900
Commit:     GitHub <nore...@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-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 &&
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-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;
 }
 
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;
         }
 

Reply via email to