-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAutoMESwitch_v0.5.cpp
More file actions
223 lines (212 loc) · 7.41 KB
/
Copy pathAutoMESwitch_v0.5.cpp
File metadata and controls
223 lines (212 loc) · 7.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "taiwanKeyGroupDefine.h"
// intro:
// use tone keys( group no.4 ) as seperate point, generate 'sections'
// record the section sizes in this buffer
// ex. 134 => LLKP_SecSizeRecord[ 2 ]++
// highly possible Taiwanese input section size: 2, 3
// highly possible English input sectoin size: MaxBufferSize
// highly possible number input section size: 0
// ambiguous input section size: 1, 6~12
// another highly possible English input is more than 3 consecutive key in the same group
// todo: i can use AI to train a decision maker
// version 0.5 by Joseph Chen 17/11/2021
const static unsigned int LLKP_KEYBUFFERSIZE = 12;
static DWORD LLKP_KeyBuffer[ LLKP_KEYBUFFERSIZE ] = { 0 };
static unsigned int LLKP_KeyCntInBuffer = 0;
static unsigned int LLKP_SecSizeRecord[ LLKP_KEYBUFFERSIZE ] = { 0 };
static unsigned int LLKP_SecCnt = 0;
static unsigned int LLKP_SecSizeTmp = 0;
static unsigned int LLKP_lastKeyGrp = 0;
static unsigned int LLKP_consecSameGrpCnt = 0;
static boolean LLKP_bProcLock = false;
static unsigned int LLKP_KEYGROUPMAP[ 0xFF ] = { 0 };
static HWND LLKP_lastHWnd = NULL;
// initialize key group map
static void LLKP_Init( void ) {
for( DWORD i : LLKP_KEYGROUPUPPER ) {
LLKP_KEYGROUPMAP[ i ] = 1;
}
for( DWORD i : LLKP_KEYGROUPMIDDLE ) {
LLKP_KEYGROUPMAP[ i ] = 2;
}
for( DWORD i : LLKP_KEYGROUPLOWER ) {
LLKP_KEYGROUPMAP[ i ] = 3;
}
for( DWORD i : LLKP_KEYGROUPTONE ) {
LLKP_KEYGROUPMAP[ i ] = 4;
}
// space is a special key
LLKP_KEYGROUPMAP[ 0x20 ] = 5;
}
// clear buffer and clear count
static void LLKP_ClearBuffers() {
memset( LLKP_KeyBuffer, 0, sizeof( DWORD ) * LLKP_KEYBUFFERSIZE );
LLKP_KeyCntInBuffer = 0;
memset( LLKP_SecSizeRecord, 0, sizeof( DWORD ) * LLKP_KEYBUFFERSIZE );
LLKP_SecCnt = 0;
LLKP_SecSizeTmp = 0;
LLKP_lastKeyGrp = 0;
LLKP_consecSameGrpCnt = 0;
}
// calculate backspace count needed to correct content in buffer in Taiwanese
static unsigned int LLKP_CalcTWBackspaceCnt( void ) {
unsigned int ret = LLKP_SecCnt;
unsigned int one = 0, two = 0, three = 0;
for( int i = LLKP_KeyCntInBuffer - 1; i >= 0; --i ) {
switch( LLKP_KEYGROUPMAP[ LLKP_KeyBuffer[ i ] ] ) {
case 4:
return ret + one + two + three;
break;
case 1:
one = 1;
break;
case 2:
two = 1;
break;
case 3:
three = 1;
break;
default:
break;
}
}
return ret + one + two + three;
}
// resend keyboard input in the key buffer
// normally call this method after changing keyboard layout
static void LLKP_ReviseQuedKBInput( LPCSTR language_select ) {
unsigned int backspaceCnt = 0;
// for now we assume there are only two KBLs, Taiwanese and English in this computer
// I always have only two :)
// todo: optimize delete count( maybe I should use more lock? )
// delete wrong input in English
if( language_select == "00000404" ) {
backspaceCnt = LLKP_KeyCntInBuffer;
}
// delete wrong input in Taiwanese
else {
backspaceCnt = LLKP_CalcTWBackspaceCnt();
}
// resend queued input
INPUT bsInput[ LLKP_KEYBUFFERSIZE ];
int i = 0;
for(; i < backspaceCnt; ++i ) {
bsInput[ i ].type = INPUT_KEYBOARD;
bsInput[ i ].ki.wVk = (WORD)VK_BACK;
bsInput[ i ].ki.dwFlags = KEYEVENTF_UNICODE;
}
SendInput( backspaceCnt, bsInput, sizeof( INPUT ) );
INPUT inputs[ LLKP_KEYBUFFERSIZE ];
// don't send the last one because the key is still going through the KB chain
for(int i = 0; i < LLKP_KeyCntInBuffer; ++i ) {
inputs[ i ].type = INPUT_KEYBOARD;
inputs[ i ].ki.wVk = LLKP_KeyBuffer[ i ];
inputs[ i ].ki.dwFlags = KEYEVENTF_UNICODE;
}
SendInput( LLKP_KeyCntInBuffer, inputs, sizeof( INPUT ) );
}
// switch keyboard layout
static void LLKP_SwitchKBLayout( LPCSTR language_select ) {
// "00000409" is code for US-English
// "00000404" is code for Chinese-Taiwan
HWND curWnd = GetForegroundWindow();
HKL curKBL = GetKeyboardLayout( GetWindowThreadProcessId( curWnd, nullptr ) );
if( language_select == "00000409" && curKBL == (HKL)0x4090409 ) return;
if( language_select == "00000404" && curKBL == (HKL)0x4040404 ) return;
SendMessageA( curWnd, WM_INPUTLANGCHANGEREQUEST, 0,
reinterpret_cast<LPARAM>( LoadKeyboardLayoutA( language_select, KLF_ACTIVATE ) ) );
LLKP_ReviseQuedKBInput( language_select );
}
// determine user KBL according to buffer data
// todo: optimize this
LPCSTR LLKP_DetermineKBL() {
if( LLKP_SecCnt == 0 || LLKP_SecSizeRecord[ 0 ] > 1 ) {
return "00000409";
}
else if( LLKP_SecSizeRecord[ 1 ] + LLKP_SecSizeRecord[ 2 ] + LLKP_SecSizeRecord[ 3 ] > 2 ) {
return "00000404";
}
else return "0";
}
// single input key router
static void AutoMESwitch( DWORD nKey ) {
unsigned int nKeyGroup = LLKP_KEYGROUPMAP[ nKey ];
switch( nKeyGroup ) {
case 0:
// return key
// highly possible to be a Taiwanese input
if( nKey == 0x0D ) {
LLKP_ClearBuffers();
}
// backspace key
if( nKey == 0x08 ) {
if( LLKP_KeyCntInBuffer > 0 )
--LLKP_KeyCntInBuffer;
LLKP_KeyBuffer[ LLKP_KeyCntInBuffer ] = 0;
if( LLKP_SecSizeTmp > 0 )
--LLKP_SecSizeTmp;
}
break;
case 4:
// put key pattern into buffers
LLKP_KeyBuffer[ LLKP_KeyCntInBuffer++ ] = nKey;
++LLKP_SecSizeRecord[ LLKP_SecSizeTmp ];
++LLKP_SecCnt;
LLKP_SecSizeTmp = 0;
LLKP_lastKeyGrp = 0;
LLKP_consecSameGrpCnt = 0;
break;
default:
// put key pattern into buffers
++LLKP_SecSizeTmp;
LLKP_KeyBuffer[ LLKP_KeyCntInBuffer++ ] = nKey;
if( nKeyGroup != 5 && nKeyGroup == LLKP_lastKeyGrp ) {
// more than 3 consecutive number in the same group
// highly possible to be english or number input
if( ++LLKP_consecSameGrpCnt > 3 ) {
LPCSTR KBL = LLKP_DetermineKBL();
if( KBL != "0" ) {
LLKP_bProcLock = true;
LLKP_SwitchKBLayout( KBL );
LLKP_ClearBuffers();
LLKP_bProcLock = false;
return;
}
}
}
else {
LLKP_consecSameGrpCnt = 0;
LLKP_lastKeyGrp = nKeyGroup;
}
if( LLKP_KeyCntInBuffer >= LLKP_KEYBUFFERSIZE ) {
LPCSTR KBL = LLKP_DetermineKBL();
if( KBL != "0" ) {
LLKP_bProcLock = true;
LLKP_SwitchKBLayout( KBL );
}
LLKP_ClearBuffers();
LLKP_bProcLock = false;
}
break;
}
}
// hook procedure
static LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if ( !LLKP_bProcLock && ( wParam == WM_KEYUP ) && lParam != NULL ) {
AutoMESwitch( ( (LPKBDLLHOOKSTRUCT)lParam )->vkCode );
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
LLKP_Init();
HHOOK hHook = SetWindowsHookExW(WH_KEYBOARD_LL, LowLevelKeyboardProc, NULL, 0);
// it works if I use MessageBox to make it hold
MessageBoxW(NULL, L"AutoMESwitch is running.", L"AutoMESwitch", MB_OK );
UnhookWindowsHookEx(hHook);
return 0;
}