Reactos

[KBSWITCH] Make Alt+Shift working Part 1 (#8039)

Recently language switching (Alt+Shift)
was not working. This PR will fix
Alt+Shift (partially).
JIRA issue: CORE-18546
- Add WH_KEYBOARD_LL hook to
detect Alt+Shift.
- Add delay to the action after language
change.
- Increase g_SpecialIds not to be full.
- Delete useless ID_NEXTLAYOUT
command.

authored by

Katayama Hirofumi MZ and committed by
GitHub
3df71d67 c03d7794

+160 -162
+63 -31
base/applications/kbswitch/kbsdll/kbsdll.c
··· 1 1 /* 2 - * PROJECT: ReactOS Keyboard Layout Switcher 3 - * FILE: base/applications/kbswitch/kbsdll/kbsdll.c 4 - * PROGRAMMER: Dmitry Chapyshev <dmitry@reactos.org> 5 - * 2 + * PROJECT: ReactOS Keyboard Layout Switcher 3 + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 + * PURPOSE: Switching Keyboard Layouts 5 + * COPYRIGHT: Copyright Dmitry Chapyshev (dmitry@reactos.org) 6 + * Copyright Colin Finck (mail@colinfinck.de) 7 + * Copyright 2022-2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 6 8 */ 7 9 8 10 #include "../kbswitch.h" 9 11 10 12 HHOOK hWinHook = NULL; 11 13 HHOOK hShellHook = NULL; 14 + HHOOK hKeyboardLLHook = NULL; 12 15 HINSTANCE hInstance = NULL; 13 16 HWND hKbSwitchWnd = NULL; 14 17 ··· 18 21 PostMessage(hKbSwitchWnd, Msg, wParam, lParam); 19 22 } 20 23 21 - LRESULT CALLBACK 22 - WinHookProc(int code, WPARAM wParam, LPARAM lParam) 24 + static LRESULT CALLBACK 25 + WinHookProc(INT code, WPARAM wParam, LPARAM lParam) 23 26 { 24 27 if (code < 0) 25 - { 26 28 return CallNextHookEx(hWinHook, code, wParam, lParam); 27 - } 28 29 29 30 switch (code) 30 31 { 32 + case HCBT_ACTIVATE: 31 33 case HCBT_SETFOCUS: 32 34 { 33 35 HWND hwndFocus = (HWND)wParam; 34 36 if (hwndFocus && hwndFocus != hKbSwitchWnd) 35 - { 36 - PostMessageToMainWnd(WM_WINDOW_ACTIVATE, wParam, lParam); 37 - } 37 + PostMessageToMainWnd(WM_WINDOW_ACTIVATE, (WPARAM)hwndFocus, 0); 38 + break; 38 39 } 39 - break; 40 40 } 41 41 42 42 return CallNextHookEx(hWinHook, code, wParam, lParam); 43 43 } 44 44 45 - LRESULT CALLBACK 46 - ShellHookProc(int code, WPARAM wParam, LPARAM lParam) 45 + static LRESULT CALLBACK 46 + ShellHookProc(INT code, WPARAM wParam, LPARAM lParam) 47 47 { 48 48 if (code < 0) 49 - { 50 49 return CallNextHookEx(hShellHook, code, wParam, lParam); 51 - } 52 50 53 51 switch (code) 54 52 { 53 + case HSHELL_WINDOWACTIVATED: 54 + { 55 + PostMessageToMainWnd(WM_WINDOW_ACTIVATE, wParam, 0); 56 + break; 57 + } 55 58 case HSHELL_LANGUAGE: 56 59 { 57 60 PostMessageToMainWnd(WM_LANG_CHANGED, wParam, lParam); 61 + break; 58 62 } 59 - break; 60 63 } 61 64 62 65 return CallNextHookEx(hShellHook, code, wParam, lParam); 63 66 } 64 67 65 - BOOL WINAPI 66 - KbSwitchSetHooks(VOID) 68 + static LRESULT CALLBACK 69 + KeyboardLLHook(INT code, WPARAM wParam, LPARAM lParam) 67 70 { 68 - hWinHook = SetWindowsHookEx(WH_CBT, WinHookProc, hInstance, 0); 69 - hShellHook = SetWindowsHookEx(WH_SHELL, ShellHookProc, hInstance, 0); 71 + if (code < 0) 72 + return CallNextHookEx(hKeyboardLLHook, code, wParam, lParam); 70 73 71 - if (!hWinHook || !hShellHook) 74 + if (code == HC_ACTION) 72 75 { 73 - return FALSE; 76 + KBDLLHOOKSTRUCT *pKbStruct = (KBDLLHOOKSTRUCT *)lParam; 77 + if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) 78 + { 79 + BOOL bShiftPressed = GetAsyncKeyState(VK_SHIFT) < 0; 80 + BOOL bAltPressed = GetAsyncKeyState(VK_MENU) < 0; 81 + BOOL bCtrlPressed = GetAsyncKeyState(VK_CONTROL) < 0; 82 + // Detect Alt+Shift and Ctrl+Shift 83 + if ((pKbStruct->vkCode == VK_SHIFT && bAltPressed) || 84 + (pKbStruct->vkCode == VK_MENU && bShiftPressed) || 85 + (pKbStruct->vkCode == VK_SHIFT && bCtrlPressed) || 86 + (pKbStruct->vkCode == VK_CONTROL && bShiftPressed)) 87 + { 88 + PostMessageToMainWnd(WM_LANG_CHANGED, 0, 0); 89 + } 90 + } 74 91 } 75 92 76 - return TRUE; 93 + return CallNextHookEx(hKeyboardLLHook, code, wParam, lParam); 77 94 } 78 95 79 - VOID WINAPI 80 - KbSwitchDeleteHooks(VOID) 96 + BOOL APIENTRY 97 + KbSwitchSetHooks(_In_ BOOL bDoHook) 81 98 { 82 - if (hWinHook) 99 + if (bDoHook) 100 + { 101 + hWinHook = SetWindowsHookEx(WH_CBT, WinHookProc, hInstance, 0); 102 + hShellHook = SetWindowsHookEx(WH_SHELL, ShellHookProc, hInstance, 0); 103 + hKeyboardLLHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardLLHook, hInstance, 0); 104 + 105 + if (hWinHook && hShellHook && hKeyboardLLHook) 106 + return TRUE; 107 + } 108 + 109 + /* Unhook */ 110 + if (hKeyboardLLHook) 83 111 { 84 - UnhookWindowsHookEx(hWinHook); 85 - hWinHook = NULL; 112 + UnhookWindowsHookEx(hKeyboardLLHook); 113 + hKeyboardLLHook = NULL; 86 114 } 87 115 if (hShellHook) 88 116 { 89 117 UnhookWindowsHookEx(hShellHook); 90 118 hShellHook = NULL; 91 119 } 120 + if (hWinHook) 121 + { 122 + UnhookWindowsHookEx(hWinHook); 123 + hWinHook = NULL; 124 + } 125 + return !bDoHook; 92 126 } 93 127 94 128 BOOL WINAPI ··· 103 137 hInstance = hinstDLL; 104 138 hKbSwitchWnd = FindWindow(szKbSwitcherName, NULL); 105 139 if (!hKbSwitchWnd) 106 - { 107 140 return FALSE; 108 - } 109 141 } 110 142 break; 111 143 }
+1 -2
base/applications/kbswitch/kbsdll/kbsdll.spec
··· 1 - 1 stdcall KbSwitchSetHooks() 2 - 2 stdcall KbSwitchDeleteHooks() 1 + 1 stdcall KbSwitchSetHooks(long)
+78 -119
base/applications/kbswitch/kbswitch.c
··· 1 1 /* 2 - * PROJECT: Keyboard Layout Switcher 3 - * FILE: base/applications/kbswitch/kbswitch.c 4 - * PURPOSE: Switching Keyboard Layouts 5 - * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org) 6 - * Colin Finck (mail@colinfinck.de) 7 - * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 2 + * PROJECT: ReactOS Keyboard Layout Switcher 3 + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 + * PURPOSE: Switching Keyboard Layouts 5 + * COPYRIGHT: Copyright Dmitry Chapyshev (dmitry@reactos.org) 6 + * Copyright Colin Finck (mail@colinfinck.de) 7 + * Copyright 2022-2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 8 8 */ 9 - 10 9 #include "kbswitch.h" 11 10 #include <shlobj.h> 12 11 #include <shlwapi_undoc.h> ··· 32 31 33 32 #define WM_NOTIFYICONMSG (WM_USER + 248) 34 33 35 - PKBSWITCHSETHOOKS KbSwitchSetHooks = NULL; 36 - PKBSWITCHDELETEHOOKS KbSwitchDeleteHooks = NULL; 34 + #define TIMER_ID_LANG_CHANGED_DELAYED 0x10000 35 + #define TIMER_LANG_CHANGED_DELAY 200 36 + 37 + FN_KbSwitchSetHooks KbSwitchSetHooks = NULL; 37 38 UINT ShellHookMessage = 0; 38 39 39 - HINSTANCE hInst; 40 - HANDLE hProcessHeap; 40 + HINSTANCE g_hInst = NULL; 41 41 HMODULE g_hHookDLL = NULL; 42 42 INT g_nCurrentLayoutNum = 1; 43 43 HICON g_hTrayIcon = NULL; ··· 45 45 INT g_cKLs = 0; 46 46 HKL g_ahKLs[64]; 47 47 48 - ULONG 49 - NTAPI 48 + /* Debug logging */ 49 + ULONG NTAPI 50 50 vDbgPrintExWithPrefix(IN PCCH Prefix, 51 51 IN ULONG ComponentId, 52 52 IN ULONG Level, ··· 54 54 IN va_list ap) 55 55 { 56 56 CHAR Buffer[512]; 57 - 58 57 SIZE_T PrefixLength = strlen(Prefix); 59 58 strncpy(Buffer, Prefix, PrefixLength); 60 - 61 - _vsnprintf(Buffer + PrefixLength, 62 - sizeof(Buffer) - PrefixLength, 63 - Format, 64 - ap); 65 - 59 + _vsnprintf(Buffer + PrefixLength, _countof(Buffer) - PrefixLength, Format, ap); 60 + Buffer[_countof(Buffer) - 1] = ANSI_NULL; /* Avoid buffer overrun */ 66 61 OutputDebugStringA(Buffer); 67 62 return 0; 68 63 } 69 64 70 - typedef struct 65 + typedef struct tagSPECIAL_ID 71 66 { 72 67 DWORD dwLayoutId; 73 68 HKL hKL; 74 69 TCHAR szKLID[CCH_LAYOUT_ID + 1]; 75 70 } SPECIAL_ID, *PSPECIAL_ID; 76 71 77 - SPECIAL_ID g_SpecialIds[80]; 72 + #define MAX_SPECIAL_IDS 256 73 + 74 + SPECIAL_ID g_SpecialIds[MAX_SPECIAL_IDS]; 78 75 INT g_cSpecialIds = 0; 79 76 80 77 static VOID LoadSpecialIds(VOID) ··· 121 118 122 119 if (g_cSpecialIds >= _countof(g_SpecialIds)) 123 120 { 124 - OutputDebugStringA("g_SpecialIds is full!"); 121 + ERR("g_SpecialIds is full!"); 125 122 break; 126 123 } 127 124 } ··· 158 155 } 159 156 } 160 157 158 + static HKL GetActiveKL(VOID) 159 + { 160 + /* FIXME: Get correct console window's HKL when console window */ 161 + HWND hwndTarget = (g_hwndLastActive ? g_hwndLastActive : GetForegroundWindow()); 162 + DWORD dwTID = GetWindowThreadProcessId(hwndTarget, NULL); 163 + return GetKeyboardLayout(dwTID); 164 + } 165 + 161 166 static VOID UpdateLayoutList(HKL hKL OPTIONAL) 162 167 { 163 168 INT iKL; 164 169 165 170 if (!hKL) 166 - { 167 - HWND hwndTarget = (g_hwndLastActive ? g_hwndLastActive : GetForegroundWindow()); 168 - DWORD dwTID = GetWindowThreadProcessId(hwndTarget, NULL); 169 - hKL = GetKeyboardLayout(dwTID); 170 - } 171 + hKL = GetActiveKL(); 171 172 172 173 g_cKLs = GetKeyboardLayoutList(_countof(g_ahKLs), g_ahKLs); 173 174 ··· 191 192 static HKL GetHKLFromLayoutNum(INT nLayoutNum) 192 193 { 193 194 if (0 <= (nLayoutNum - 1) && (nLayoutNum - 1) < g_cKLs) 194 - { 195 195 return g_ahKLs[nLayoutNum - 1]; 196 - } 197 196 else 198 - { 199 - HWND hwndTarget = (g_hwndLastActive ? g_hwndLastActive : GetForegroundWindow()); 200 - DWORD dwTID = GetWindowThreadProcessId(hwndTarget, NULL); 201 - return GetKeyboardLayout(dwTID); 202 - } 197 + return GetActiveKL(); 203 198 } 204 199 205 200 static VOID ··· 587 582 } 588 583 589 584 #define IHOOK_SET 1 590 - #define IHOOK_DELETE 2 591 - KbSwitchSetHooks = (PKBSWITCHSETHOOKS) GetProcAddress(g_hHookDLL, MAKEINTRESOURCEA(IHOOK_SET)); 592 - KbSwitchDeleteHooks = (PKBSWITCHDELETEHOOKS) GetProcAddress(g_hHookDLL, MAKEINTRESOURCEA(IHOOK_DELETE)); 585 + KbSwitchSetHooks = (FN_KbSwitchSetHooks)GetProcAddress(g_hHookDLL, MAKEINTRESOURCEA(IHOOK_SET)); 593 586 594 - if (!KbSwitchSetHooks || !KbSwitchDeleteHooks || !KbSwitchSetHooks()) 587 + if (!KbSwitchSetHooks || !KbSwitchSetHooks(TRUE)) 595 588 { 596 589 ERR("SetHooks failed\n"); 597 590 return FALSE; ··· 604 597 VOID 605 598 DeleteHooks(VOID) 606 599 { 607 - if (KbSwitchDeleteHooks) 600 + if (KbSwitchSetHooks) 608 601 { 609 - KbSwitchDeleteHooks(); 610 - KbSwitchDeleteHooks = NULL; 602 + KbSwitchSetHooks(FALSE); 603 + KbSwitchSetHooks = NULL; 611 604 } 612 605 613 606 if (g_hHookDLL) ··· 654 647 } 655 648 656 649 HWND 657 - GetTargetWindow(HWND hwndFore) 650 + GetTargetWindow(HWND hwndFore OPTIONAL) 658 651 { 659 - TCHAR szClass[64]; 660 - HWND hwndIME; 661 - HWND hwndTarget = hwndFore; 662 - if (hwndTarget == NULL) 663 - hwndTarget = GetForegroundWindow(); 664 - 665 - GetClassName(hwndTarget, szClass, _countof(szClass)); 666 - if (_tcsicmp(szClass, szKbSwitcherName) == 0) 652 + HWND hwndTarget = (hwndFore ? hwndFore : GetForegroundWindow()); 653 + if (IsWndClassName(hwndTarget, szKbSwitcherName)) 667 654 hwndTarget = g_hwndLastActive; 668 - 669 - hwndIME = ImmGetDefaultIMEWnd(hwndTarget); 670 - return (hwndIME ? hwndIME : hwndTarget); 655 + return hwndTarget; 671 656 } 672 657 673 658 UINT ··· 682 667 683 668 static BOOL RememberLastActive(HWND hwnd, HWND hwndFore) 684 669 { 685 - TCHAR szClass[64]; 686 - 687 670 hwndFore = GetAncestor(hwndFore, GA_ROOT); 688 671 689 - if (!IsWindowVisible(hwndFore) || !GetClassName(hwndFore, szClass, _countof(szClass))) 672 + if (!IsWindowVisible(hwndFore)) 690 673 return FALSE; 691 674 692 - if (_tcsicmp(szClass, szKbSwitcherName) == 0 || 693 - _tcsicmp(szClass, TEXT("Shell_TrayWnd")) == 0) 675 + if (IsWndClassName(hwndFore, szKbSwitcherName) || 676 + IsWndClassName(hwndFore, TEXT("Shell_TrayWnd"))) 694 677 { 695 678 return FALSE; /* Special window */ 696 - } 697 - 698 - /* FIXME: CONWND needs special handling */ 699 - if (_tcsicmp(szClass, TEXT("ConsoleWindowClass")) == 0) 700 - { 701 - HKL hKL = GetKeyboardLayout(0); 702 - UpdateLanguageDisplay(hwnd, hKL); 703 679 } 704 680 705 681 g_hwndLastActive = hwndFore; ··· 734 710 break; 735 711 } 736 712 713 + case WM_TIMER: 714 + { 715 + if (wParam == TIMER_ID_LANG_CHANGED_DELAYED) 716 + { 717 + KillTimer(hwnd, TIMER_ID_LANG_CHANGED_DELAYED); 718 + HKL hKL = GetActiveKL(); 719 + UpdateLayoutList(hKL); 720 + UpdateLanguageDisplay(hwnd, hKL); 721 + } 722 + break; 723 + } 724 + 725 + // WM_LANG_CHANGED message: 726 + // wParam: HWND hwndTarget or zero 727 + // lParam: HKL hKL or zero 737 728 case WM_LANG_CHANGED: /* Comes from kbsdll.dll and this module */ 738 729 { 739 730 TRACE("WM_LANG_CHANGED: wParam:%p, lParam:%p\n", wParam, lParam); 740 - UpdateLayoutList((HKL)lParam); 741 - UpdateLanguageDisplay(hwnd, (HKL)lParam); 731 + /* Delayed action */ 732 + KillTimer(hwnd, TIMER_ID_LANG_CHANGED_DELAYED); 733 + SetTimer(hwnd, TIMER_ID_LANG_CHANGED_DELAYED, TIMER_LANG_CHANGED_DELAY, NULL); 742 734 break; 743 735 } 744 736 737 + // WM_WINDOW_ACTIVATE message: 738 + // wParam: HWND hwndTarget or zero 739 + // lParam: zero 745 740 case WM_WINDOW_ACTIVATE: /* Comes from kbsdll.dll and this module */ 746 741 { 747 - HWND hwndFore; 748 742 TRACE("WM_WINDOW_ACTIVATE: wParam:%p, lParam:%p\n", wParam, lParam); 749 - hwndFore = GetForegroundWindow(); 743 + HWND hwndFore = wParam ? (HWND)wParam : GetForegroundWindow(); 750 744 if (RememberLastActive(hwnd, hwndFore)) 751 745 return UpdateLanguageDisplayCurrent(hwnd, hwndFore); 752 746 break; ··· 764 758 GetCursorPos(&pt); 765 759 SetForegroundWindow(hwnd); 766 760 761 + INT nID; 767 762 if (lParam == WM_LBUTTONUP) 768 763 { 769 764 /* Rebuild the left popup menu on every click to take care of keyboard layout changes */ 770 765 hLeftPopupMenu = BuildLeftPopupMenu(); 771 - TrackPopupMenu(hLeftPopupMenu, 0, pt.x, pt.y, 0, hwnd, NULL); 766 + nID = TrackPopupMenu(hLeftPopupMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL); 772 767 DestroyMenu(hLeftPopupMenu); 773 768 } 774 769 else 775 770 { 776 771 if (!s_hRightPopupMenu) 777 772 { 778 - s_hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_POPUP)); 773 + s_hMenu = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_POPUP)); 779 774 s_hRightPopupMenu = GetSubMenu(s_hMenu, 0); 780 775 } 781 - TrackPopupMenu(s_hRightPopupMenu, 0, pt.x, pt.y, 0, hwnd, NULL); 776 + nID = TrackPopupMenu(s_hRightPopupMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL); 782 777 } 783 778 784 779 PostMessage(hwnd, WM_NULL, 0, 0); 780 + 781 + if (nID) 782 + PostMessage(hwnd, WM_COMMAND, nID, 0); 783 + 785 784 break; 786 785 } 787 786 } ··· 807 806 break; 808 807 } 809 808 810 - case ID_NEXTLAYOUT: 811 - { 812 - HWND hwndTarget = (HWND)lParam, hwndTargetSave = NULL; 813 - DWORD dwThreadID; 814 - HKL hKL; 815 - UINT uNum; 816 - TCHAR szClass[64]; 817 - BOOL bCONWND = FALSE; 818 - 819 - if (hwndTarget == NULL) 820 - hwndTarget = g_hwndLastActive; 821 - 822 - /* FIXME: CONWND needs special handling */ 823 - if (hwndTarget && 824 - GetClassName(hwndTarget, szClass, _countof(szClass)) && 825 - _tcsicmp(szClass, TEXT("ConsoleWindowClass")) == 0) 826 - { 827 - bCONWND = TRUE; 828 - hwndTargetSave = hwndTarget; 829 - hwndTarget = NULL; 830 - } 831 - 832 - if (hwndTarget) 833 - { 834 - dwThreadID = GetWindowThreadProcessId(hwndTarget, NULL); 835 - hKL = GetKeyboardLayout(dwThreadID); 836 - uNum = GetLayoutNum(hKL); 837 - if (uNum != 0) 838 - g_nCurrentLayoutNum = uNum; 839 - } 840 - 841 - ActivateLayout(hwnd, GetNextLayout(), hwndTarget, TRUE); 842 - 843 - /* FIXME: CONWND needs special handling */ 844 - if (bCONWND) 845 - ActivateLayout(hwnd, g_nCurrentLayoutNum, hwndTargetSave, TRUE); 846 - 847 - break; 848 - } 849 - 850 809 default: 851 810 { 852 811 if (1 <= LOWORD(wParam) && LOWORD(wParam) <= 1000) ··· 866 825 { 867 826 if (wParam == SPI_SETNONCLIENTMETRICS) 868 827 { 869 - PostMessage(hwnd, WM_WINDOW_ACTIVATE, wParam, lParam); 828 + PostMessage(hwnd, WM_WINDOW_ACTIVATE, 0, 0); 870 829 break; 871 830 } 872 831 } ··· 874 833 875 834 case WM_DESTROY: 876 835 { 836 + KillTimer(hwnd, TIMER_ID_LANG_CHANGED_DELAYED); 877 837 DeleteHooks(); 878 838 DestroyMenu(s_hMenu); 879 839 DeleteTrayIcon(hwnd); ··· 893 853 { 894 854 TRACE("ShellHookMessage: wParam:%p, lParam:%p\n", wParam, lParam); 895 855 if (wParam == HSHELL_LANGUAGE) 896 - PostMessage(hwnd, WM_LANG_CHANGED, wParam, lParam); 897 - else if (wParam == HSHELL_WINDOWACTIVATED) 898 - PostMessage(hwnd, WM_WINDOW_ACTIVATE, wParam, lParam); 856 + PostMessage(hwnd, WM_LANG_CHANGED, 0, 0); 857 + else if (wParam == HSHELL_WINDOWACTIVATED || wParam == HSHELL_RUDEAPPACTIVATED) 858 + PostMessage(hwnd, WM_WINDOW_ACTIVATE, 0, 0); 899 859 900 860 break; 901 861 } ··· 938 898 return 1; 939 899 } 940 900 941 - hInst = hInstance; 942 - hProcessHeap = GetProcessHeap(); 901 + g_hInst = hInstance; 943 902 944 903 ZeroMemory(&WndClass, sizeof(WndClass)); 945 904 WndClass.lpfnWndProc = WndProc;
+18 -9
base/applications/kbswitch/kbswitch.h
··· 1 1 #pragma once 2 2 3 - #include <stdarg.h> 3 + #include <stdlib.h> 4 4 #include <windef.h> 5 5 #include <winbase.h> 6 6 #include <winuser.h> ··· 14 14 15 15 #include "resource.h" 16 16 17 - // Character Count of a layout ID like "00000409" 18 - #define CCH_LAYOUT_ID 8 19 - 20 - // Maximum Character Count of a ULONG in decimal 21 - #define CCH_ULONG_DEC 10 17 + #define CCH_LAYOUT_ID 8 // Character Count of a layout ID like "00000409" 18 + #define CCH_ULONG_DEC 10 // Maximum Character Count of a ULONG in decimal 22 19 23 - #define WM_KEY_PRESSED (WM_USER + 10100) 24 20 #define WM_LANG_CHANGED (WM_USER + 10200) 25 21 #define WM_WINDOW_ACTIVATE (WM_USER + 10300) 26 22 27 - typedef BOOL (WINAPI *PKBSWITCHSETHOOKS) (VOID); 28 - typedef VOID (WINAPI *PKBSWITCHDELETEHOOKS) (VOID); 23 + typedef BOOL (APIENTRY *FN_KbSwitchSetHooks)(BOOL bDoHook); 29 24 30 25 const TCHAR szKbSwitcherName[] = INDICATOR_CLASS; 26 + 27 + static inline BOOL 28 + IsWndClassName(_In_opt_ HWND hwndTarget, PCTSTR pszName) 29 + { 30 + TCHAR szClass[32]; 31 + GetClassName(hwndTarget, szClass, _countof(szClass)); 32 + return lstrcmpi(szClass, pszName) == 0; 33 + } 34 + 35 + static inline BOOL 36 + IsConsoleWnd(_In_opt_ HWND hwndTarget) 37 + { 38 + return IsWndClassName(hwndTarget, TEXT("ConsoleWindowClass")); 39 + }
-1
base/applications/kbswitch/resource.h
··· 9 9 /* Menu items */ 10 10 #define ID_EXIT 10001 11 11 #define ID_PREFERENCES 10002 12 - #define ID_NEXTLAYOUT 10003