@@ -7,72 +7,84 @@ typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
77
88typedef struct {
99 BOOL popup ;
10- BYTE modifier ;
1110} Settings ;
1211
1312void ShowError (LPCSTR message );
1413DWORD GetOSVersion ();
14+ void PressKey (int keyCode );
15+ void ReleaseKey (int keyCode );
1516void ToggleCapsLockState ();
1617LRESULT CALLBACK LowLevelKeyboardProc (int nCode , WPARAM wParam , LPARAM lParam );
1718
1819
1920HHOOK hHook ;
20- BOOL modifier ;
2121BOOL enabled = TRUE;
22- BOOL capsLockPressed = FALSE;
22+ BOOL keystrokeProcessed = FALSE;
2323BOOL winPressed = FALSE;
2424
2525Settings settings = {
26- .popup = FALSE,
27- .modifier = VK_LSHIFT
26+ .popup = FALSE
2827};
2928
3029
31- int main (int argc , char * * argv ) {
32- if (argc > 1 && strcmp (argv [1 ], "nopopup" ) == 0 ) {
30+ int main (int argc , char * * argv )
31+ {
32+ if (argc > 1 && strcmp (argv [1 ], "nopopup" ) == 0 )
33+ {
3334 settings .popup = FALSE;
34- } else {
35+ }
36+ else
37+ {
3538 settings .popup = GetOSVersion () >= 10 ;
3639 }
3740#if _DEBUG
3841 printf ("Pop-up %s\n" , settings .popup ? "enabled" : "disabled" );
3942#endif
4043
4144 HANDLE hMutex = CreateMutex (0 , 0 , "Switchy" );
42- if (GetLastError () == ERROR_ALREADY_EXISTS ) {
45+ if (GetLastError () == ERROR_ALREADY_EXISTS )
46+ {
4347 ShowError ("Another instance of Switchy is already running!" );
4448 return 1 ;
4549 }
4650
4751 hHook = SetWindowsHookEx (WH_KEYBOARD_LL , LowLevelKeyboardProc , 0 , 0 );
48- if (hHook == NULL ) {
52+ if (hHook == NULL )
53+ {
4954 ShowError ("Error calling \"SetWindowsHookEx(...)\"" );
5055 return 1 ;
5156 }
5257
5358 MSG messages ;
54- while (GetMessage (& messages , NULL , 0 , 0 )) {
59+ while (GetMessage (& messages , NULL , 0 , 0 ))
60+ {
5561 TranslateMessage (& messages );
5662 DispatchMessage (& messages );
5763 }
5864
65+ UnhookWindowsHookEx (hHook );
66+
5967 return 0 ;
6068}
6169
6270
63- void ShowError (LPCSTR message ) {
71+ void ShowError (LPCSTR message )
72+ {
6473 MessageBox (NULL , message , "Error" , MB_OK | MB_ICONERROR );
6574}
6675
6776
68- DWORD GetOSVersion () {
77+ DWORD GetOSVersion ()
78+ {
6979 HMODULE hMod = GetModuleHandleW (L"ntdll.dll" );
7080 RTL_OSVERSIONINFOW osvi = { 0 };
7181
72- if (hMod ) {
82+ if (hMod )
83+ {
7384 RtlGetVersionPtr p = (RtlGetVersionPtr )GetProcAddress (hMod , "RtlGetVersion" );
7485
75- if (p ) {
86+ if (p )
87+ {
7688 osvi .dwOSVersionInfoSize = sizeof (osvi );
7789 p (& osvi );
7890 }
@@ -82,68 +94,98 @@ DWORD GetOSVersion() {
8294}
8395
8496
85- void ToggleCapsLockState () {
86- keybd_event (VK_CAPITAL , 0x3A , 0 , 0 );
87- keybd_event (VK_CAPITAL , 0x3A , KEYEVENTF_KEYUP , 0 );
97+ void PressKey (int keyCode )
98+ {
99+ keybd_event (keyCode , 0 , 0 , 0 );
100+ }
101+
102+
103+ void ReleaseKey (int keyCode )
104+ {
105+ keybd_event (keyCode , 0 , KEYEVENTF_KEYUP , 0 );
106+ }
107+
108+
109+ void ToggleCapsLockState ()
110+ {
111+ PressKey (VK_CAPITAL );
112+ ReleaseKey (VK_CAPITAL );
88113#if _DEBUG
89114 printf ("Caps Lock state has been toggled\n" );
90115#endif // _DEBUG
91116}
92117
93118
94- LRESULT CALLBACK LowLevelKeyboardProc (int nCode , WPARAM wParam , LPARAM lParam ) {
119+ LRESULT CALLBACK LowLevelKeyboardProc (int nCode , WPARAM wParam , LPARAM lParam )
120+ {
95121 KBDLLHOOKSTRUCT * key = (KBDLLHOOKSTRUCT * )lParam ;
96- if (nCode == HC_ACTION && !(key -> flags & LLKHF_INJECTED )) {
122+ if (nCode == HC_ACTION && !(key -> flags & LLKHF_INJECTED ))
123+ {
97124#if _DEBUG
98125 const char * keyStatus = (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN ) ? "pressed" : "released" ;
99126 printf ("Key %d has been %s\n" , key -> vkCode , keyStatus );
100127#endif // _DEBUG
101- if (key -> vkCode == VK_CAPITAL ) {
102- if (wParam == WM_SYSKEYDOWN ) {
128+ if (key -> vkCode == VK_CAPITAL )
129+ {
130+ if (wParam == WM_SYSKEYDOWN && !keystrokeProcessed )
131+ {
132+ keystrokeProcessed = TRUE;
103133 enabled = !enabled ;
104134#if _DEBUG
105135 printf ("Switchy has been %s\n" , enabled ? "enabled" : "disabled" );
106136#endif // _DEBUG
107137 return 1 ;
108138 }
109139
110- if (!enabled ) {
111- return CallNextHookEx (NULL , nCode , wParam , lParam );
140+ if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP )
141+ {
142+ keystrokeProcessed = FALSE;
143+
144+ if (winPressed )
145+ {
146+ winPressed = FALSE;
147+ ReleaseKey (VK_LWIN );
148+ }
149+ }
150+
151+ if (!enabled )
152+ {
153+ return CallNextHookEx (hHook , nCode , wParam , lParam );
112154 }
113155
114- if (wParam == WM_KEYDOWN && !capsLockPressed ) {
115- capsLockPressed = TRUE;
156+ if (wParam == WM_KEYDOWN && !keystrokeProcessed )
157+ {
158+ keystrokeProcessed = TRUE;
116159
117- if (GetKeyState (settings .modifier ) & 0x8000 ) {
160+ if (GetKeyState (VK_LSHIFT ) & 0x8000 )
161+ {
118162 ToggleCapsLockState ();
119163 return 1 ;
120- } else {
121- if (settings .popup ) {
122- keybd_event (VK_LWIN , 0x3A , 0 , 0 );
123- keybd_event (VK_SPACE , 0x3A , 0 , 0 );
124- keybd_event (VK_SPACE , 0x3A , KEYEVENTF_KEYUP , 0 );
164+ }
165+ else
166+ {
167+ if (settings .popup )
168+ {
169+ PressKey (VK_LWIN );
170+ PressKey (VK_SPACE );
171+ ReleaseKey (VK_SPACE );
125172 winPressed = TRUE;
126173 }
127- else {
174+ else
175+ {
128176 HWND hWnd = GetForegroundWindow ();
129- if (hWnd ) {
177+ if (hWnd )
178+ {
130179 hWnd = GetAncestor (hWnd , GA_ROOTOWNER );
131180 PostMessage (hWnd , WM_INPUTLANGCHANGEREQUEST , 0 , (LPARAM )HKL_NEXT );
132181 }
133182 }
134183 }
135184 }
136- else if (wParam == WM_KEYUP ) {
137- capsLockPressed = FALSE;
138-
139- if (winPressed ) {
140- keybd_event (VK_LWIN , 0x3A , KEYEVENTF_KEYUP , 0 );
141- }
142- }
143185
144186 return 1 ;
145187 }
146188 }
147189
148- return CallNextHookEx (NULL , nCode , wParam , lParam );
190+ return CallNextHookEx (hHook , nCode , wParam , lParam );
149191}
0 commit comments