OSDN Git Service

Separate SetKeyboardFookFlag(BOOL) in CXkeymacsDll into
[xkeymacs/xkeymacs.git] / xkeymacsdll / xkeymacsdll.cpp
1 // xkeymacsdll.cpp : Defines the initialization routines for the DLL.\r
2 //\r
3 \r
4 #include "stdafx.h"\r
5 #include "resource.h"\r
6 #include "Utils.h"\r
7 #include "Commands.h"\r
8 #include <afxdllx.h>\r
9 #include <math.h>\r
10 #include <Imm.h>\r
11 \r
12 #ifdef _DEBUG\r
13 #define new DEBUG_NEW\r
14 #undef THIS_FILE\r
15 static char THIS_FILE[] = __FILE__;\r
16 #endif\r
17 \r
18 struct KbdMacro\r
19 {\r
20         int nCode;\r
21         WPARAM wParam;\r
22         LPARAM lParam;\r
23         BOOL bOriginal;\r
24 };\r
25 \r
26 struct Modifier {\r
27         LPCTSTR name;\r
28         int id;\r
29 };\r
30 \r
31 static const Modifier Modifiers[] = {\r
32 //      { _T("A-"), ALT },\r
33         { _T("C-"), CONTROL},\r
34 //      { _T("H-"), HYPER },\r
35         { _T("M-"), META },\r
36         { _T("S-"), SHIFT },\r
37 //      { _T("s-"), SUPER },\r
38         { _T("Ctrl+"), WIN_CTRL },\r
39         { _T("Alt+"), WIN_ALT },\r
40         { _T("Win+"), WIN_WIN },\r
41 };\r
42 \r
43 static const KeyName ControlCharacters[] = {\r
44 //      { VK_LBUTTON,           _T("mouse-1") },                                // does not work well\r
45 //      { VK_RBUTTON,           _T("mouse-3") },                                // does not work well\r
46         { VK_CANCEL,            _T("break") },\r
47 //      { VK_MBUTTON,           _T("mouse-2") },                                // does not work well\r
48         { VK_BACK,                      _T("backspace") },\r
49         { VK_TAB,                       _T("tab") },\r
50         { VK_RETURN,            _T("return") },\r
51         { VK_CAPITAL,           _T("capslock") },\r
52         { VK_KANA,                      _T("kana") },\r
53         { VK_KANJI,                     _T("kanji") },\r
54         { VK_ESCAPE,            _T("escape") },\r
55         { VK_CONVERT,           _T("convert") },\r
56         { VK_NONCONVERT,        _T("nonconvert") },\r
57 //      { VK_SPACE,                     _T("SPC") },                                    // [? ]\r
58         { VK_PRIOR,                     _T("prior") },\r
59         { VK_NEXT,                      _T("next") },\r
60         { VK_END,                       _T("end") },\r
61         { VK_HOME,                      _T("home") },\r
62         { VK_LEFT,                      _T("left") },\r
63         { VK_UP,                        _T("up") },\r
64         { VK_RIGHT,                     _T("right") },\r
65         { VK_DOWN,                      _T("down") },\r
66         { VK_SELECT,            _T("select") },\r
67         { VK_PRINT,                     _T("print") },\r
68         { VK_EXECUTE,           _T("execute") },\r
69         { VK_SNAPSHOT,          _T("printscreen") },                    // work as print\r
70         { VK_INSERT,            _T("insert") },\r
71         { VK_DELETE,            _T("delete") },\r
72         { VK_LWIN,                      _T("lwindow") },\r
73         { VK_RWIN,                      _T("rwindow") },\r
74         { VK_APPS,                      _T("apps") },\r
75         { VK_SLEEP,                     _T("sleep") },\r
76         { VK_NUMPAD0,           _T("kp-0") },\r
77         { VK_NUMPAD1,           _T("kp-1") },\r
78         { VK_NUMPAD2,           _T("kp-2") },\r
79         { VK_NUMPAD3,           _T("kp-3") },\r
80         { VK_NUMPAD4,           _T("kp-4") },\r
81         { VK_NUMPAD5,           _T("kp-5") },\r
82         { VK_NUMPAD6,           _T("kp-6") },\r
83         { VK_NUMPAD7,           _T("kp-7") },\r
84         { VK_NUMPAD8,           _T("kp-8") },\r
85         { VK_NUMPAD9,           _T("kp-9") },\r
86         { VK_MULTIPLY,          _T("kp-multiply") },\r
87         { VK_ADD,                       _T("kp-add") },\r
88         { VK_SUBTRACT,          _T("kp-subtract") },\r
89         { VK_DECIMAL,           _T("kp-decimal") },\r
90         { VK_DIVIDE,            _T("kp-divide") },\r
91 //      { VK_F1,                        _T("f1") },                                             // FIXME\r
92 //      { VK_F2,                        _T("f2") },                                             // Move at the end of definition of funcgtion keys to keep away confliction f1/f2 and f1?/f2? by _tcsncmp() i.e. strncmp()\r
93         { VK_F3,                        _T("f3") },\r
94         { VK_F4,                        _T("f4") },\r
95         { VK_F5,                        _T("f5") },\r
96         { VK_F6,                        _T("f6") },\r
97         { VK_F7,                        _T("f7") },\r
98         { VK_F8,                        _T("f8") },\r
99         { VK_F9,                        _T("f9") },\r
100         { VK_F10,                       _T("f10") },\r
101         { VK_F11,                       _T("f11") },\r
102         { VK_F12,                       _T("f12") },\r
103         { VK_F13,                       _T("f13") },\r
104         { VK_F14,                       _T("f14") },\r
105         { VK_F15,                       _T("f15") },\r
106         { VK_F16,                       _T("f16") },\r
107         { VK_F17,                       _T("f17") },\r
108         { VK_F18,                       _T("f18") },\r
109         { VK_F19,                       _T("f19") },\r
110         { VK_F20,                       _T("f20") },\r
111         { VK_F21,                       _T("f21") },\r
112         { VK_F22,                       _T("f22") },\r
113         { VK_F23,                       _T("f23") },\r
114         { VK_F24,                       _T("f24") },\r
115         { VK_F1,                        _T("f1") },\r
116         { VK_F2,                        _T("f2") },\r
117         { VK_NUMLOCK,           _T("kp-numlock") },\r
118         { VK_SCROLL,            _T("scroll") },\r
119         { 0xa6,                         _T("browser-back") },                   // VK_BROWSER_BACK\r
120         { 0xa7,                         _T("browser-forward") },                // VK_BROWSER_FORWARD\r
121         { 0xa8,                         _T("browser-refresh") },                // VK_BROWSER_REFRESH\r
122         { 0xa9,                         _T("browser-stop") },                   // VK_BROWSER_STOP\r
123         { 0xaa,                         _T("browser-search") },                 // VK_BROWSER_SEARCH\r
124         { 0xab,                         _T("browser-favorites") },              // VK_BROWSER_FAVORITES\r
125         { 0xac,                         _T("browser-home") },                   // VK_BROWSER_HOME\r
126         { 0xad,                         _T("volume-mute") },                    // VK_VOLUME_MUTE\r
127         { 0xae,                         _T("volume-down") },                    // VK_VOLUME_DOWN\r
128         { 0xaf,                         _T("volume-up") },                              // VK_VOLUME_UP\r
129         { 0xb0,                         _T("media-next-track") },               // VK_MEDIA_NEXT_TRACK\r
130         { 0xb1,                         _T("media-prev-track") },               // VK_MEDIA_PREV_TRACK\r
131         { 0xb2,                         _T("media-stop") },                             // VK_MEDIA_STOP\r
132         { 0xb3,                         _T("media-play-pause") },               // VK_MEDIA_PLAY_PAUSE\r
133         { 0xb4,                         _T("launch-mail") },                    // VK_LAUNCH_MAIL\r
134         { 0xb5,                         _T("launch-media-select") },    // VK_LAUNCH_MEDIA_SELECT\r
135         { 0xb6,                         _T("launch-1") },                               // VK_LAUNCH_APP1\r
136         { 0xb7,                         _T("launch-2") },                               // VK_LAUNCH_APP2\r
137 };\r
138 \r
139 static AFX_EXTENSION_MODULE XkeymacsdllDLL = { NULL, NULL };\r
140 \r
141 HINSTANCE g_hDllInst = NULL;\r
142 UINT g_ImeManipulationMessage = 0;\r
143 #pragma data_seg(".xkmcs")\r
144 HHOOK g_hHookKeyboard = NULL;\r
145 HHOOK g_hHookDummy = NULL;\r
146 #pragma data_seg()\r
147 \r
148 inline bool IsWow64(HANDLE mod) {\r
149         typedef BOOL (WINAPI *pfnIsWow64Process_t)(HANDLE, PBOOL);\r
150         if (const pfnIsWow64Process_t IsWow64Process = (pfnIsWow64Process_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "IsWow64Process")) {\r
151                 BOOL b;\r
152                 return IsWow64Process(mod, &b) && b;\r
153         }\r
154         return false;\r
155 }\r
156 \r
157 inline bool Is64System() {\r
158         SYSTEM_INFO info;\r
159         GetNativeSystemInfo(&info);\r
160         return info.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL;\r
161 }\r
162 \r
163 inline bool Is64Process(HANDLE mod) {\r
164         return Is64System() && !IsWow64(mod);\r
165 }\r
166 \r
167 const bool IsDll64 = sizeof(void *) == 8;\r
168 \r
169 inline bool Is64ProcessHwnd(HWND hwnd) {\r
170         DWORD pid;\r
171         GetWindowThreadProcessId(hwnd, &pid);\r
172         HANDLE hmod = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);\r
173         bool b = Is64Process(hmod);\r
174         CloseHandle(hmod);\r
175         return b;\r
176 }\r
177 \r
178 extern "C" int APIENTRY\r
179 DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r
180 {\r
181         g_hDllInst = hInstance;\r
182         \r
183         // Remove this if you use lpReserved\r
184         UNREFERENCED_PARAMETER(lpReserved);\r
185 \r
186         switch (dwReason) {\r
187         case DLL_PROCESS_ATTACH:\r
188                 TRACE0("XKEYMACSDLL.DLL Initializing!\n");\r
189                 g_ImeManipulationMessage = RegisterWindowMessage(_T("XkManipulateIME"));\r
190 \r
191                 // Extension DLL one-time initialization\r
192                 if (!AfxInitExtensionModule(XkeymacsdllDLL, hInstance)) {\r
193                         return 0;\r
194                 }\r
195 \r
196                 // Insert this DLL into the resource chain\r
197                 // NOTE: If this Extension DLL is being implicitly linked to by\r
198                 //  an MFC Regular DLL (such as an ActiveX Control)\r
199                 //  instead of an MFC application, then you will want to\r
200                 //  remove this line from DllMain and put it in a separate\r
201                 //  function exported from this Extension DLL.  The Regular DLL\r
202                 //  that uses this Extension DLL should then explicitly call that\r
203                 //  function to initialize this Extension DLL.  Otherwise,\r
204                 //  the CDynLinkLibrary object will not be attached to the\r
205                 //  Regular DLL's resource chain, and serious problems will\r
206                 //  result.\r
207 \r
208                 try {\r
209                         new CDynLinkLibrary(XkeymacsdllDLL);\r
210                 }\r
211                 catch (CMemoryException* e) {\r
212                         e->Delete();\r
213 //                      CUtils::Log("DllMain: 'new' threw an exception");\r
214                 }\r
215                 break;\r
216         case DLL_PROCESS_DETACH:\r
217                 TRACE0("XKEYMACSDLL.DLL Terminating!\n");\r
218                 // Terminate the library before destructors are called\r
219                 AfxTermExtensionModule(XkeymacsdllDLL);\r
220                 break;\r
221         }\r
222         return 1;   // ok\r
223 }\r
224 \r
225 //////////////////////////////////////////////////////////////////////\r
226 // CXkeymacsDll Class\r
227 //////////////////////////////////////////////////////////////////////\r
228 \r
229 #include "xkeymacsDll.h"\r
230 #pragma data_seg(".xkmcs")\r
231         DWORD   CXkeymacsDll::m_nHookAltRelease = 0;\r
232         HHOOK   CXkeymacsDll::m_hHookCallWnd = NULL;\r
233         HHOOK   CXkeymacsDll::m_hHookCallWndRet = NULL;\r
234         HHOOK   CXkeymacsDll::m_hHookGetMessage = NULL;\r
235         HHOOK   CXkeymacsDll::m_hHookShell = NULL;\r
236         BOOL    CXkeymacsDll::m_bRightControl   = FALSE;\r
237         BOOL    CXkeymacsDll::m_bRightAlt               = FALSE;\r
238         BOOL    CXkeymacsDll::m_bRightShift             = FALSE;\r
239         BOOL    CXkeymacsDll::m_bHook                   = TRUE;\r
240         BOOL    CXkeymacsDll::m_bDefiningMacro  = FALSE;\r
241         CList<CClipboardSnap *, CClipboardSnap *> CXkeymacsDll::m_oKillRing;\r
242         CObList CXkeymacsDll::m_Macro;\r
243         int             CXkeymacsDll::m_nKillRing = 0;\r
244         int             CXkeymacsDll::m_nOriginal[MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
245         int             CXkeymacsDll::m_nApplicationID = 0;\r
246         int             CXkeymacsDll::m_nAccelerate = 0;\r
247         int             CXkeymacsDll::m_nKeyboardSpeed = 31;\r
248         HCURSOR CXkeymacsDll::m_hCursor[MAX_STATUS] = {'\0'};\r
249         HCURSOR CXkeymacsDll::m_hCurrentCursor = NULL;\r
250         BOOL    CXkeymacsDll::m_bCursor = FALSE;\r
251         TCHAR   CXkeymacsDll::m_M_xTip[128] = "";\r
252         CONFIG  CXkeymacsDll::m_Config = {0};\r
253 #pragma data_seg()\r
254 \r
255 //////////////////////////////////////////////////////////////////////\r
256 // Construction/Destruction\r
257 //////////////////////////////////////////////////////////////////////\r
258 \r
259 CXkeymacsDll::CXkeymacsDll()\r
260 {\r
261 \r
262 }\r
263 \r
264 CXkeymacsDll::~CXkeymacsDll()\r
265 {\r
266 \r
267 }\r
268 \r
269 BOOL CXkeymacsDll::SaveConfig()\r
270 {\r
271         TCHAR szTmp[MAX_PATH];\r
272         if (!GetTempPath(MAX_PATH, szTmp))\r
273                 return FALSE;\r
274         if (_tmakepath_s(szTmp, NULL, szTmp, _T("xkeymacs"), _T("tmp")))\r
275                 return FALSE;\r
276         HANDLE hFile = CreateFile(szTmp, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);\r
277         if (hFile == INVALID_HANDLE_VALUE)\r
278                 return FALSE;\r
279         DWORD written;\r
280         BOOL res = WriteFile(hFile, &m_Config, sizeof(m_Config), &written, NULL) || written != sizeof(m_Config);\r
281         CloseHandle(hFile);\r
282         return res;\r
283 }\r
284 \r
285 BOOL CXkeymacsDll::LoadConfig()\r
286 {\r
287         TCHAR szTmp[MAX_PATH];\r
288         if (!GetTempPath(MAX_PATH, szTmp))\r
289                 return FALSE;\r
290         if (_tmakepath_s(szTmp, NULL, szTmp, _T("xkeymacs"), _T("tmp")))\r
291                 return FALSE;\r
292         HANDLE hFile = CreateFile(szTmp, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);\r
293         if (hFile == INVALID_HANDLE_VALUE)\r
294                 return FALSE;\r
295         DWORD read;\r
296         BOOL res = ReadFile(hFile, &m_Config, sizeof(m_Config), &read, NULL) && read == sizeof(m_Config);\r
297         CloseHandle(hFile);\r
298         return res;\r
299 }\r
300 \r
301 // set hooks\r
302 LRESULT WINAPI DummyProc(int code, WPARAM wp, LPARAM lp) {\r
303         return CallNextHookEx(0, code, wp, lp);\r
304 }\r
305 \r
306 void CXkeymacsDll::SetHooks()\r
307 {\r
308         m_hHookCallWnd = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWndProc, g_hDllInst, 0);\r
309         m_hHookCallWndRet = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)CallWndRetProc, g_hDllInst, 0);\r
310         m_hHookGetMessage = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllInst, 0);\r
311         m_hHookShell = SetWindowsHookEx(WH_SHELL, (HOOKPROC)ShellProc, g_hDllInst, 0);\r
312         g_hHookDummy = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)DummyProc, g_hDllInst, 0);\r
313         g_hHookKeyboard = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, g_hDllInst, 0);\r
314 }\r
315 \r
316 inline void unhook(HHOOK &hh) {\r
317         if (hh)\r
318                 UnhookWindowsHookEx(hh);\r
319         hh = NULL;\r
320 }\r
321 \r
322 void CXkeymacsDll::ResetHooks() \r
323 {\r
324         ReleaseHooks();\r
325         SetHooks();\r
326 }\r
327 \r
328 // release hooks\r
329 void CXkeymacsDll::ReleaseHooks()\r
330 {\r
331         unhook(m_hHookCallWnd);\r
332         unhook(m_hHookCallWndRet);\r
333         unhook(m_hHookGetMessage);\r
334         unhook(m_hHookShell);\r
335         unhook(g_hHookKeyboard);\r
336         unhook(g_hHookDummy);\r
337 }\r
338 \r
339 void CXkeymacsDll::ToggleKeyboardHookState()\r
340 {\r
341         m_bHook = !m_bHook;\r
342         ShowKeyboardHookState();\r
343 }\r
344 \r
345 void CXkeymacsDll::ShowKeyboardHookState()\r
346 {\r
347         ICONMSG msg = {MAIN_ICON,};\r
348         if (m_bHook) {\r
349                 if (CCommands::IsTemporarilyDisableXKeymacs()) {\r
350                         msg.nState = STATUS_DISABLE_TMP;\r
351                         m_hCurrentCursor = m_hCursor[STATUS_DISABLE_TMP];\r
352                 } else {\r
353                         msg.nState = STATUS_ENABLE;\r
354                         m_hCurrentCursor = m_hCursor[STATUS_ENABLE];\r
355                 }\r
356         } else {\r
357                 msg.nState = STATUS_DISABLE_WOCQ;\r
358         }\r
359         if (m_Config.nSettingStyle[m_nApplicationID] == SETTING_DISABLE\r
360          || (!_tcsicmp(m_Config.szSpecialApp[m_nApplicationID], _T("Default"))\r
361           && CUtils::IsDefaultIgnoreApplication())) {\r
362                 msg.nState = STATUS_DISABLE;\r
363                 m_hCurrentCursor = m_hCursor[STATUS_DISABLE];\r
364         }\r
365         SendIconMessage(&msg, 1);\r
366         DoSetCursor();\r
367 }\r
368 \r
369 BOOL CXkeymacsDll::IsKeyboardHook()\r
370 {\r
371         return m_bHook;\r
372 }\r
373 \r
374 void CXkeymacsDll::LogCallWndProcMessage(WPARAM wParam, LPARAM lParam)\r
375 {\r
376         CWPSTRUCT &cwps = *(CWPSTRUCT *)lParam;\r
377 \r
378         switch (cwps.message) {\r
379         case WM_PAINT:                                  // 0x000F\r
380         case WM_MDIGETACTIVE:                   // 0x0229\r
381         case 0x0403:\r
382         case 0x0407:\r
383         case 0x0418:\r
384         case 0x043F:\r
385         case 0x0440:\r
386                 break;\r
387         case WM_CREATE:                                 // 0x0001\r
388 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_CREATE"));\r
389                 break;\r
390         case WM_DESTROY:                                // 0x0002\r
391 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_DESTROY"));\r
392                 break;\r
393         case WM_MOVE:                                   // 0x0003\r
394 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_MOVE");)\r
395                 break;\r
396         case WM_SIZE:                                   // 0x0005\r
397 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_SIZE"));\r
398                 break;\r
399         case WM_GETTEXT:                                // 0x000D\r
400 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_GETTEXT"));\r
401                 break;\r
402         case WM_ERASEBKGND:                             // 0x0014\r
403 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_ERASEBKGND"));\r
404                 break;\r
405         case WM_WINDOWPOSCHANGING:              // 0x0046\r
406 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_WINDOWPOSCHANGING"));\r
407                 break;\r
408         case WM_WINDOWPOSCHANGED:               // 0x0047\r
409 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_WINDOWPOSCHANGED"));\r
410                 break;\r
411         case WM_COPYDATA:                               // 0x004A\r
412 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_COPYDATA"));\r
413                 break;\r
414         case WM_NCCREATE:                               // 0x0081\r
415 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCCREATE"));\r
416                 break;\r
417         case WM_NCDESTROY:                              // 0x0082\r
418 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCDESTROY"));\r
419                 break;\r
420         case WM_NCCALCSIZE:                             // 0x0083\r
421 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCCALCSIZE"));\r
422                 break;\r
423         case WM_NCPAINT:                                // 0x0085\r
424 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCPAINT"));\r
425                 break;\r
426         case WM_IME_STARTCOMPOSITION:   // 0x010D\r
427 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_STARTCOMPOSITION"));\r
428                 break;\r
429         case WM_IME_ENDCOMPOSITION:             // 0x010E\r
430 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_ENDCOMPOSITION"));\r
431                 break;\r
432         case WM_IME_KEYLAST:                    // 0x010F\r
433 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_KEYLAST"));\r
434                 break;\r
435         case WM_COMMAND:                                // 0x0111\r
436 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_COMMAND"));\r
437                 break;\r
438         case WM_CTLCOLOREDIT:                   // 0x0133\r
439 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_CTLCOLOREDIT"));\r
440                 break;\r
441         case WM_POWERBROADCAST:                 // 0x0218\r
442 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_POWERBROADCAST"));\r
443                 switch (wParam) {\r
444                 case PBT_APMQUERYSUSPEND:               // 0x0000\r
445 //                      CUtils::Log(_T("PBT_APMQUERYSUSPEND"));\r
446                         break;\r
447                 case PBT_APMQUERYSTANDBY:               // 0x0001\r
448 //                      CUtils::Log(_T("PBT_APMQUERYSTANDBY"));\r
449                         break;\r
450                 case PBT_APMQUERYSUSPENDFAILED: // 0x0002\r
451 //                      CUtils::Log(_T("PBT_APMQUERYSUSPENDFAILED"));\r
452                         break;\r
453                 case PBT_APMQUERYSTANDBYFAILED: // 0x0003\r
454 //                      CUtils::Log(_T("PBT_APMQUERYSTANDBYFAILED"));\r
455                         break;\r
456                 case PBT_APMSUSPEND:                    // 0x0004\r
457 //                      CUtils::Log(_T("PBT_APMSUSPEND"));\r
458                         break;\r
459                 case PBT_APMSTANDBY:                    // 0x0005\r
460 //                      CUtils::Log(_T("PBT_APMSTANDBY"));\r
461                         break;\r
462                 case PBT_APMRESUMECRITICAL:             // 0x0006\r
463 //                      CUtils::Log(_T("PBT_APMRESUMECRITICAL"));\r
464                         break;\r
465                 case PBT_APMRESUMESUSPEND:              // 0x0007\r
466 //                      CUtils::Log(_T("PBT_APMRESUMESUSPEND"));\r
467                         break;\r
468                 case PBT_APMRESUMESTANDBY:              // 0x0008\r
469 //                      CUtils::Log(_T("PBT_APMRESUMESTANDBY"));\r
470                         break;\r
471                 case PBT_APMBATTERYLOW:                 // 0x0009\r
472 //                      CUtils::Log(_T("PBT_APMBATTERYLOW"));\r
473                         break;\r
474                 case PBT_APMPOWERSTATUSCHANGE:  // 0x000A\r
475 //                      CUtils::Log(_T("PBT_APMPOWERSTATUSCHANGE"));\r
476                         break;\r
477                 case PBT_APMOEMEVENT:                   // 0x000B\r
478 //                      CUtils::Log(_T("PBT_APMOEMEVENT"));\r
479                         break;\r
480                 case PBT_APMRESUMEAUTOMATIC:    // 0x0012\r
481 //                      CUtils::Log(_T("PBT_APMRESUMEAUTOMATIC"));\r
482                         break;\r
483                 default:\r
484 //                      CUtils::Log(_T("PBT_OTHERS: %d"), wParam);\r
485                         break;\r
486                 }\r
487                 break;\r
488         case WM_IME_NOTIFY:                             // 0x0282\r
489 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_NOTIFY"));\r
490                 break;\r
491         default:\r
492 //              CUtils::Log(_T("CallWndProc: cwps.message = 0x%04X"), cwps.message);\r
493                 break;\r
494         }\r
495 }\r
496 \r
497 LRESULT CALLBACK CXkeymacsDll::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)\r
498 {\r
499 //      LogCallWndProcMessage(wParam, lParam);\r
500 \r
501         if (0 <= nCode) {\r
502                 CWPSTRUCT &cwps = *(CWPSTRUCT *)lParam;\r
503                 switch (cwps.message) {\r
504                 case WM_IME_STARTCOMPOSITION:\r
505                         InitKeyboardProc(TRUE);\r
506                         break;\r
507                 case WM_IME_ENDCOMPOSITION:\r
508                         InitKeyboardProc(FALSE);\r
509                         break;\r
510                 case WM_SETFOCUS:\r
511                         if (cwps.hwnd == GetForegroundWindow()) {\r
512                                 InitKeyboardProc(FALSE);\r
513                                 ShowKeyboardHookState();\r
514                         }\r
515                         break;\r
516                 case WM_NCACTIVATE:\r
517                         if (cwps.wParam) {\r
518                                 if (cwps.hwnd == GetForegroundWindow()) {\r
519                                         InitKeyboardProc(FALSE);\r
520                                         ShowKeyboardHookState();\r
521                                 }\r
522                         }\r
523                         break;\r
524                 case WM_POWERBROADCAST:\r
525                         switch (wParam) {\r
526                         case PBT_APMRESUMECRITICAL: // 0x0006\r
527                         case PBT_APMRESUMESUSPEND:  // 0x0007\r
528                         case PBT_APMRESUMESTANDBY:  // 0x0008\r
529                                 ReleaseHooks();\r
530                                 SetHooks();\r
531                                 break;\r
532                         default:\r
533                                 break;\r
534                         }\r
535                         break;\r
536                 default:\r
537                         break;\r
538                 }\r
539         }\r
540         return CallNextHookEx(m_hHookCallWnd, nCode, wParam, lParam);\r
541 }\r
542 \r
543 LRESULT CALLBACK CXkeymacsDll::CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)\r
544 {\r
545         if (0 <= nCode) {\r
546                 CWPRETSTRUCT &cwprets = *(CWPRETSTRUCT *)lParam;\r
547                 switch (cwprets.message) {\r
548                 case WM_SETTEXT:\r
549                         if (cwprets.hwnd == GetForegroundWindow()) {\r
550                                 InitKeyboardProc(FALSE);\r
551                         }\r
552                         break;\r
553                 case WM_SETCURSOR:\r
554                         DoSetCursor();\r
555                         break;\r
556                 default:\r
557                         break;\r
558                 }\r
559         }\r
560         return CallNextHookEx(m_hHookCallWndRet, nCode, wParam, lParam);\r
561 }\r
562 \r
563 LRESULT CALLBACK CXkeymacsDll::GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)\r
564 {\r
565         MSG &msg = (*(MSG *)lParam);\r
566         if (msg.message == g_ImeManipulationMessage) {\r
567                 if (wParam)\r
568                         CCommands::DoSetInputMethodOpenStatus((INPUT_METHOD_OPEN_STATUS)msg.wParam, msg.lParam);\r
569                 return 1;\r
570         }\r
571         switch (msg.message) {\r
572         case WM_IME_STARTCOMPOSITION:\r
573                 InitKeyboardProc(TRUE);\r
574                 break;\r
575         case WM_IME_ENDCOMPOSITION:\r
576                 InitKeyboardProc(FALSE);\r
577                 break;\r
578         }\r
579         return CallNextHookEx(m_hHookGetMessage, nCode, wParam, lParam);\r
580 }\r
581 \r
582 LRESULT CALLBACK CXkeymacsDll::ShellProc(int nCode, WPARAM wParam, LPARAM lParam)\r
583 {\r
584         switch (nCode) {\r
585         case HSHELL_WINDOWACTIVATED:\r
586         {\r
587                 TCHAR className[256];\r
588                 ::GetClassName((HWND)wParam, className, 255);\r
589                 if (!_tcsicmp(className, _T("ConsoleWindowClass"))) {\r
590                         InitKeyboardProc(FALSE);\r
591                         ShowKeyboardHookState();\r
592                 }\r
593                 break;\r
594         }\r
595         default:\r
596                 break;\r
597         }\r
598         return CallNextHookEx( m_hHookShell, nCode, wParam, lParam );\r
599 }\r
600 \r
601 UINT CXkeymacsDll::GetModifierState(BOOL bPhysicalKey)\r
602 {\r
603         UINT result = 0;\r
604         if (IsDown(VK_SHIFT, bPhysicalKey))\r
605                 result |= SHIFT;\r
606         if (IsDown(VK_CONTROL, bPhysicalKey))\r
607                 result |= CONTROL;\r
608         if (IsDown(VK_MENU, bPhysicalKey))\r
609                 result |= META;\r
610         return result;\r
611 }\r
612 \r
613 void CXkeymacsDll::SetModifierState(UINT after, UINT before)\r
614 {\r
615         if (after & SHIFT && !(before & SHIFT))\r
616                 DepressKey(VK_SHIFT);\r
617         else if (!(after & SHIFT) && before & SHIFT)\r
618                 ReleaseKey(VK_SHIFT);\r
619 \r
620         if (after & CONTROL && !(before & CONTROL)) {\r
621                 UpdateKeyboardState(VK_CONTROL, 1);\r
622                 DepressKey(VK_CONTROL);\r
623         } else if (!(after & CONTROL) && before & CONTROL) {\r
624                 ReleaseKey(VK_CONTROL);\r
625                 UpdateKeyboardState(VK_CONTROL, 0);\r
626         }\r
627 \r
628         BOOL bHookApp = CUtils::IsVisualCpp() || CUtils::IsFirefox() || CUtils::IsVisualStudio() || CUtils::IsInternetExplorer();\r
629         if (after & META && !(before & META)) {\r
630                 if (bHookApp)\r
631                         m_nHookAltRelease |= HOOK_ALT_LATER;\r
632                 DepressKey(VK_MENU);\r
633         } else if (!(after & META) && before & META) {\r
634                 if (bHookApp)\r
635                         m_nHookAltRelease++;\r
636                 ReleaseKey(VK_MENU);\r
637         }\r
638 }\r
639 \r
640 BOOL CXkeymacsDll::UpdateKeyboardState(BYTE bVk, BYTE bState)\r
641 {\r
642         BYTE ks[256] = {'\0'};\r
643         if (!GetKeyboardState(ks))\r
644                 return FALSE;\r
645         ks[bVk] = bState;\r
646         return SetKeyboardState(ks);\r
647 }\r
648 \r
649 BOOL CXkeymacsDll::IsDown(BYTE bVk, BOOL bPhysicalKey)\r
650 {\r
651         return bPhysicalKey ? GetAsyncKeyState(bVk) < 0 : GetKeyState(bVk) < 0;\r
652 }\r
653 \r
654 // Do keybd_event\r
655 void CXkeymacsDll::DoKeybd_event(BYTE bVk, DWORD dwFlags)\r
656 {\r
657         // Set KEYEVENTF_EXTENDEDKEY if needed\r
658         switch (bVk) {\r
659         case VK_CONTROL:\r
660                 if (m_bRightControl)\r
661                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
662                 break;\r
663 \r
664         case VK_MENU:\r
665                 if (m_bRightAlt)\r
666                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
667                 break;\r
668 \r
669         case VK_SHIFT:\r
670                 if (m_bRightShift) {\r
671                         if (CUtils::IsXPorLater())\r
672                                 bVk = VK_RSHIFT;\r
673                         else\r
674                                 dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
675                 }\r
676                 break;\r
677         case VK_PAUSE:\r
678                 if (IsDown(VK_CONTROL, FALSE)) // Break\r
679                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
680                 break;\r
681         case VK_INSERT:\r
682         case VK_DELETE:\r
683         case VK_HOME:\r
684         case VK_END:\r
685         case VK_NEXT:\r
686         case VK_PRIOR:\r
687         case VK_UP:\r
688         case VK_DOWN:\r
689         case VK_RIGHT:\r
690         case VK_LEFT:\r
691         case VK_NUMLOCK:\r
692         case VK_PRINT:\r
693                 dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
694                 break;\r
695         }\r
696 //      CUtils::Log(_T("b: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
697         keybd_event(bVk, 0, dwFlags, GetMessageExtraInfo());\r
698 //      CUtils::Log(_T("a: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
699 }\r
700 \r
701 // the key is being depressed\r
702 void CXkeymacsDll::DepressKey(BYTE bVk, BOOL bOriginal) // bVk is virtual-key code, MSDN said\r
703 {\r
704         if (bOriginal) {\r
705 //              CUtils::Log(_T("i: %x, %d, %d, %d, %d, %d, %d, %d, %d"), bVk,\r
706 //                      IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),\r
707 //                      IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));\r
708                 Original(GetModifierState(), bVk, 1);\r
709         }\r
710         DoKeybd_event(bVk, 0);\r
711 }\r
712 \r
713 // the key is being released\r
714 void CXkeymacsDll::ReleaseKey(BYTE bVk) // bVk is virtual-key code, MSDN said\r
715 {\r
716         DoKeybd_event(bVk, KEYEVENTF_KEYUP);\r
717 }\r
718 \r
719 // bVk down, bVk up\r
720 void CXkeymacsDll::Kdu(BYTE bVk, DWORD n, BOOL bOriginal)\r
721 {\r
722         while (n--) {\r
723                 DepressKey(bVk, bOriginal);\r
724                 ReleaseKey(bVk);\r
725         }\r
726 }\r
727 \r
728 void CXkeymacsDll::InitKeyboardProc(BOOL bImeComposition)\r
729 {\r
730         if (CUtils::IsFindDialog()) {\r
731                 static BOOL bImeCompositionOld = FALSE;\r
732                 if (!bImeComposition\r
733                  && bImeCompositionOld) {\r
734                         DepressKey(VK_END);\r
735                         ReleaseKey(VK_END);\r
736                 }\r
737                 bImeCompositionOld = bImeComposition;\r
738         }\r
739 \r
740         CUtils::SetApplicationName(bImeComposition);\r
741 \r
742         if (_tcsnicmp(m_Config.szSpecialApp[m_nApplicationID], CUtils::GetApplicationName(), 0xF) || !IsMatchWindowText(m_Config.szWindowText[m_nApplicationID])) {     // PROCESSENTRY32 has only 0xF bytes of Name\r
743                 m_nApplicationID = -1;\r
744 \r
745                 for (int nApplicationID = 0; nApplicationID < MAX_APP; ++nApplicationID) {\r
746                         if (!_tcsnicmp(m_Config.szSpecialApp[nApplicationID], CUtils::GetApplicationName(), 0xF) && IsMatchWindowText(m_Config.szWindowText[nApplicationID])) {\r
747 \r
748                                 if (m_nApplicationID < 0\r
749                                  || CUtils::GetWindowTextType(m_Config.szWindowText[m_nApplicationID]) < CUtils::GetWindowTextType(m_Config.szWindowText[nApplicationID])\r
750                                  || CUtils::GetWindowTextType(m_Config.szWindowText[m_nApplicationID]) == CUtils::GetWindowTextType(m_Config.szWindowText[nApplicationID])\r
751                                  && _tcscmp(m_Config.szWindowText[m_nApplicationID], m_Config.szWindowText[nApplicationID]) <= 0) {\r
752                                         m_nApplicationID = nApplicationID;\r
753                                 }\r
754                         }\r
755                 }\r
756 \r
757                 if (m_nApplicationID < 0) {\r
758                         for (int nApplicationID = 0; nApplicationID < MAX_APP; ++nApplicationID) {\r
759                                 if (!_tcsicmp(m_Config.szSpecialApp[nApplicationID], _T("Default"))) {\r
760                                         m_nApplicationID = nApplicationID;\r
761                                         break;\r
762                                 }\r
763                         }\r
764 \r
765                         if (m_nApplicationID < 0) {\r
766                                 m_nApplicationID = 0;\r
767                         }\r
768                 }\r
769         }\r
770 \r
771         if (m_Config.nSettingStyle[m_nApplicationID] != SETTING_DISABLE\r
772          && (_tcsicmp(m_Config.szSpecialApp[m_nApplicationID], _T("Default")) || !CUtils::IsDefaultIgnoreApplication())\r
773          && !bImeComposition\r
774          && CUtils::IsDialog()) {\r
775                 // Use Dialog Setting\r
776                 if (m_Config.bUseDialogSetting[m_nApplicationID]) {\r
777                         int nOriginalApplicationID = m_nApplicationID;\r
778                         for (m_nApplicationID = 0; m_nApplicationID < MAX_APP; ++m_nApplicationID) {\r
779                                 if (!_tcsicmp(m_Config.szSpecialApp[m_nApplicationID], _T("Dialog"))) {\r
780                                         break;\r
781                                 }\r
782                         }\r
783                         if (m_nApplicationID == MAX_APP) {\r
784                                 m_nApplicationID = nOriginalApplicationID;\r
785                         }\r
786                 }\r
787         }\r
788 \r
789         ICONMSG msg[3] = {\r
790                 {CX_ICON, OFF_ICON, ""},\r
791                 {MX_ICON, OFF_ICON, ""},\r
792                 {META_ICON, OFF_ICON, ""}\r
793         };\r
794         SendIconMessage(msg, 3);\r
795         CCommands::SetMark(FALSE);\r
796         CCommands::SetTemporarilyDisableXKeymacs(FALSE);\r
797         CCommands::Reset();\r
798 }\r
799 \r
800 // emulate emacs        // cf virtual-key code\r
801 LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)\r
802 {\r
803         ASSERT(0 <= wParam && wParam <= UCHAR_MAX);\r
804 \r
805         int nCommandType = NONE;\r
806         BYTE nKey = (BYTE)wParam;\r
807 \r
808         static BOOL bLocked = FALSE;\r
809         static const BYTE RECURSIVE_KEY = 0x07;\r
810         static int (*fCommand)() = NULL;\r
811         static BYTE nOneShotModifier[MAX_KEY] = {'\0'};\r
812         static BOOL bCherryOneShotModifier = FALSE;\r
813 \r
814 //      CUtils::Log(_T("nCode = %#x, nKey = %#x, lParam = %p, %d, %d"), nCode, nKey, lParam, IsDll64, Is64ProcessHwnd(GetForegroundWindow()));\r
815 \r
816         if (Is64ProcessHwnd(GetForegroundWindow()) != IsDll64 || CUtils::IsXkeymacs())\r
817                 return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam);\r
818 \r
819         if (nCode < 0 || nCode == HC_NOREMOVE) {\r
820                 goto DO_NOTHING;\r
821         }\r
822 \r
823         if (nKey == RECURSIVE_KEY) {\r
824                 if (lParam & BEING_RELEASED) {\r
825                         goto HOOK_RECURSIVE_KEY;\r
826                 } else {\r
827                         goto RECURSIVE_COMMAND;\r
828                 }\r
829         }\r
830 \r
831         {\r
832                 static BOOL bShift = FALSE;\r
833                 if (IsDepressedShiftKeyOnly(nKey)) {\r
834                         if (lParam & BEING_RELEASED) {\r
835                                 if (bShift) {\r
836                                         CCommands::SetMark(FALSE);\r
837                                 }\r
838                         } else {\r
839                                 bShift = TRUE;\r
840                         }\r
841                 } else {\r
842                         bShift = FALSE;\r
843                 }\r
844         }\r
845 \r
846         switch (nKey) {\r
847         case VK_CONTROL:\r
848                 if (lParam & EXTENDED_KEY) {\r
849                         nKey = VK_RCONTROL;\r
850                 } else {\r
851                         nKey = VK_LCONTROL;\r
852                 }\r
853                 break;\r
854         case VK_MENU:\r
855                 if (lParam & EXTENDED_KEY) {\r
856                         nKey = VK_RMENU;\r
857                 } else {\r
858                         nKey = VK_LMENU;\r
859                 }\r
860                 break;\r
861         case VK_SHIFT:\r
862                 if (lParam & EXTENDED_KEY) {\r
863                         nKey = VK_RSHIFT;\r
864                 } else {\r
865                         nKey = VK_LSHIFT;\r
866                 }\r
867                 break;\r
868         default:\r
869                 break;\r
870         }\r
871 \r
872         if (lParam & BEING_RELEASED) {\r
873                 BOOL bAlt = FALSE;\r
874                 switch (nKey) {\r
875                 case VK_MENU:\r
876                 case VK_LMENU:\r
877                 case VK_RMENU:\r
878                         bAlt = TRUE;\r
879                         if (m_nHookAltRelease) {\r
880                                 if (m_nHookAltRelease & ~HOOK_ALT_LATER)\r
881                                         m_nHookAltRelease--;\r
882                                 else if (m_nHookAltRelease & HOOK_ALT_LATER)\r
883                                         m_nHookAltRelease = 0;\r
884                                 goto HOOK;\r
885                         }\r
886                         // pass through\r
887                 case VK_LWIN:\r
888                 case VK_RWIN:\r
889                 case VK_APPS:\r
890                         for (int i = 0; i < MAX_COMMAND_TYPE; i++) {\r
891                                 int (*func)() = Commands[m_Config.nCommandID[m_nApplicationID][i][nKey]].fCommand;\r
892                                 if (func && !(bAlt && func == CCommands::MetaAlt))\r
893                                         goto HOOK;\r
894                         }\r
895                 }\r
896                 if (nOneShotModifier[nKey]) {\r
897                         ReleaseKey(nOneShotModifier[nKey]);\r
898                         nOneShotModifier[nKey] = 0;\r
899 \r
900                         if (bCherryOneShotModifier) {\r
901                                 bCherryOneShotModifier = FALSE;\r
902                                 Kdu(nKey);\r
903                         }\r
904                 }\r
905                 goto DO_NOTHING;\r
906         }\r
907 \r
908         if (m_Config.nSettingStyle[m_nApplicationID] == SETTING_DISABLE) {\r
909                 goto DO_NOTHING;\r
910         }\r
911 \r
912         // Do Nothing for Meadow, Mule for Win32, ... if those use default setting.\r
913         if (!_tcsicmp(m_Config.szSpecialApp[m_nApplicationID], _T("Default"))\r
914          && CUtils::IsDefaultIgnoreApplication()) {\r
915                 goto DO_NOTHING;\r
916         }\r
917 \r
918         switch (IsPassThrough(nKey)) {\r
919         case GOTO_DO_NOTHING:\r
920                 goto DO_NOTHING;\r
921         case GOTO_HOOK:\r
922                 goto HOOK;\r
923         case CONTINUE:\r
924                 break;\r
925         default:\r
926                 ASSERT(0);\r
927                 break;\r
928         }\r
929 \r
930         // set command type\r
931         nCommandType = IsDown(VK_SHIFT) * SHIFT | IsControl() * CONTROL | IsMeta() * META | CCommands::bC_x() * CONTROLX;\r
932         // Ignore undefined C-x ?\r
933         if (nCommandType & CONTROLX) {\r
934                 if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == NULL\r
935                  && m_Config.nFunctionID[m_nApplicationID][nCommandType][nKey] < 0) {\r
936                         if (m_Config.bIgnoreUndefinedC_x[m_nApplicationID]) {\r
937                                 CCommands::Reset(GOTO_HOOK);\r
938                                 goto HOOK;\r
939                         }\r
940                         nCommandType &= ~CONTROLX;\r
941                 }\r
942         }\r
943         // Ignore undefined Meta Ctrl+?\r
944         if (CCommands::bM_() && (nCommandType & CONTROL)) {\r
945                 if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == NULL\r
946                  && m_Config.nFunctionID[m_nApplicationID][nCommandType][nKey] < 0) {\r
947                         if (m_Config.bIgnoreUndefinedMetaCtrl[m_nApplicationID]) {\r
948                                 if (Original(CONTROL, nKey)) {\r
949                                         Original(CONTROL, nKey, -1);\r
950                                         goto DO_NOTHING;\r
951                                 }\r
952                                 CCommands::Reset(GOTO_HOOK);\r
953                                 goto HOOK;\r
954                         }\r
955                         nCommandType &= ~META;\r
956                 }\r
957         }\r
958 \r
959         {\r
960                 BYTE nKey = (BYTE)wParam; // VK_CONTROL is needed instead of VK_RCONTROL and VK_LCONTROL in this block just for Original()\r
961                 int nVirtualCommandType = GetModifierState(FALSE);\r
962                 if (nKey == VK_CONTROL)\r
963                         nVirtualCommandType &= ~CONTROL;\r
964                 if (nKey == VK_MENU)\r
965                         nVirtualCommandType &= ~META;\r
966                 if (Original(nVirtualCommandType, nKey)) {\r
967                         Original(nVirtualCommandType, nKey, -1);\r
968                         goto DO_NOTHING;\r
969                 }\r
970         }\r
971 \r
972         if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EnableOrDisableXKeymacs) {\r
973                 ToggleKeyboardHookState();\r
974                 goto HOOK;\r
975         }\r
976         if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EnableXKeymacs) {\r
977                 if (!m_bHook) {\r
978                         ToggleKeyboardHookState();\r
979                 }\r
980                 goto HOOK;\r
981         }\r
982         if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DisableXKeymacs) {\r
983                 if (m_bHook) {\r
984                         ToggleKeyboardHookState();\r
985                 }\r
986                 goto HOOK;\r
987         }\r
988         if (!m_bHook) {\r
989                 goto DO_NOTHING;\r
990         }\r
991 \r
992         if (CCommands::bM_x()) {\r
993                 static unsigned int index = 0;\r
994                 static TCHAR szPath[MAX_PATH] = {'\0'};\r
995 \r
996                 if (lParam & BEING_RELEASED) {\r
997                         // ignore\r
998                 } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::BackwardChar) {\r
999                         if (index) {\r
1000                                 --index;\r
1001                         }\r
1002                         goto HOOKX;\r
1003                 } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::BeginningOfLine) {\r
1004                         index = 0;\r
1005                         goto HOOKX;\r
1006                 } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DeleteBackwardChar) {\r
1007                         if (index) {\r
1008                                 --index;\r
1009                                 memmove(&szPath[index], &szPath[index + 1], _tcslen(szPath) - index);\r
1010                                 SetM_xTip(szPath);\r
1011                         }\r
1012                         goto HOOKX;\r
1013                 } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DeleteChar) {\r
1014                         if (index < _tcslen(szPath)) {\r
1015                                 memmove(&szPath[index], &szPath[index + 1], _tcslen(szPath) - index);\r
1016                                 SetM_xTip(szPath);\r
1017                         }\r
1018                         goto HOOKX;\r
1019                 } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EndOfLine) {\r
1020                         index = _tcslen(szPath);\r
1021                         goto HOOKX;\r
1022                 } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::ForwardChar) {\r
1023                         if (index < _tcslen(szPath)) {\r
1024                                 ++index;\r
1025                         }\r
1026                         goto HOOKX;\r
1027                 } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::KeyboardQuit) {\r
1028                         CCommands::bM_x(FALSE);\r
1029                         index = 0;\r
1030                         memset(szPath, 0, sizeof(szPath));\r
1031                         goto HOOK;\r
1032                 } else if (nKey == VK_RETURN\r
1033                                 || Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::Newline) {\r
1034                         InvokeM_x(szPath);\r
1035 \r
1036                         CCommands::bM_x(FALSE);\r
1037                         index = 0;\r
1038                         memset(szPath, 0, sizeof(szPath));\r
1039                         goto HOOK;\r
1040                 } else if (index < MAX_PATH - 1) {\r
1041                         const BOOL bIsShiftDown = IsDown(VK_SHIFT, FALSE);\r
1042                         for (TCHAR nAscii = 1; nAscii != 0; ++nAscii) { // repeat until overflow\r
1043                                 if (nKey != 0 && a2v(nAscii) == nKey && bIsShiftDown == IsShift(nAscii)) {\r
1044 //                                      CUtils::Log("M-x: %#X (%c), %#X (%c)", nKey, nKey, nAscii, nAscii);\r
1045                                         if (index < _tcslen(szPath)) {\r
1046                                                 memmove(&szPath[index + 1], &szPath[index], __min(_tcslen(szPath) - index, MAX_PATH - (index + 1) - 1));\r
1047                                         }\r
1048                                         szPath[index++] = nAscii;\r
1049 //                                      CUtils::Log("M-x: %c(%#04x)", nAscii, nAscii);\r
1050                                         SetM_xTip(szPath);\r
1051                                         goto HOOKX;\r
1052                                 }\r
1053                         }\r
1054                 }\r
1055         }\r
1056 \r
1057         if (CCommands::bC_u()) {\r
1058                 if ((nCommandType == NONE) && ('0' <= nKey) && (nKey <= '9')) {\r
1059                         CCommands::NumericArgument(nKey - '0');\r
1060                         goto HOOK0_9;\r
1061                 }\r
1062                 if ((nCommandType == NONE) && (nKey == 0xBD)) {\r
1063                         CCommands::NumericArgumentMinus();\r
1064                         goto HOOK0_9;\r
1065                 }\r
1066         }\r
1067 \r
1068         if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType & ~CONTROL][nKey]].fCommand == CCommands::OneShotModifierCtrl) {\r
1069                 nOneShotModifier[nKey] = VK_LCONTROL;\r
1070                 DepressKey(nOneShotModifier[nKey]);\r
1071                 bCherryOneShotModifier = TRUE;\r
1072                 goto HOOK;\r
1073         } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierCtrlRepeat) {\r
1074                 nOneShotModifier[nKey] = VK_LCONTROL;\r
1075                 DepressKey(nOneShotModifier[nKey]);\r
1076                 bCherryOneShotModifier = TRUE;\r
1077                 goto HOOK;\r
1078         } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType & ~CONTROL][nKey]].fCommand == CCommands::OneShotModifierCtrlRepeat) {\r
1079                 ReleaseKey(nOneShotModifier[nKey]);\r
1080                 bCherryOneShotModifier = FALSE;\r
1081                 Kdu(nKey);\r
1082                 goto HOOK;\r
1083         } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType & ~META][nKey]].fCommand == CCommands::OneShotModifierAlt) {\r
1084                 nOneShotModifier[nKey] = VK_LMENU;\r
1085                 DepressKey(nOneShotModifier[nKey]);\r
1086                 bCherryOneShotModifier = TRUE;\r
1087                 goto HOOK;\r
1088         } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierAltRepeat) {\r
1089                 nOneShotModifier[nKey] = VK_LMENU;\r
1090                 DepressKey(nOneShotModifier[nKey]);\r
1091                 bCherryOneShotModifier = TRUE;\r
1092                 goto HOOK;\r
1093         } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType & ~META][nKey]].fCommand == CCommands::OneShotModifierAltRepeat) {\r
1094                 ReleaseKey(nOneShotModifier[nKey]);\r
1095                 bCherryOneShotModifier = FALSE;\r
1096                 Kdu(nKey);\r
1097                 goto HOOK;\r
1098         } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType & ~SHIFT][nKey]].fCommand == CCommands::OneShotModifierShift) {\r
1099                 nOneShotModifier[nKey] = VK_SHIFT;\r
1100                 DepressKey(nOneShotModifier[nKey]);\r
1101                 bCherryOneShotModifier = TRUE;\r
1102                 goto HOOK;\r
1103         } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierShiftRepeat) {\r
1104                 nOneShotModifier[nKey] = VK_SHIFT;\r
1105                 DepressKey(nOneShotModifier[nKey]);\r
1106                 bCherryOneShotModifier = TRUE;\r
1107                 goto HOOK;\r
1108         } else if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType & ~SHIFT][nKey]].fCommand == CCommands::OneShotModifierShiftRepeat) {\r
1109                 ReleaseKey(nOneShotModifier[nKey]);\r
1110                 bCherryOneShotModifier = FALSE;\r
1111                 Kdu(nKey);\r
1112                 goto HOOK;\r
1113         } else {\r
1114                 for (int i = 0; i < MAX_KEY; ++i) {\r
1115                         if (nOneShotModifier[i] == nKey) {\r
1116                                 break;\r
1117                         }\r
1118                 }\r
1119                 if (i == MAX_KEY) {\r
1120                         bCherryOneShotModifier = FALSE;\r
1121                 }\r
1122         }\r
1123 \r
1124         if (0 <= m_Config.nFunctionID[m_nApplicationID][nCommandType][nKey]\r
1125          && m_Config.nFunctionID[m_nApplicationID][nCommandType][nKey] < MAX_FUNCTION\r
1126          && _tcslen(m_Config.szFunctionDefinition[m_Config.nFunctionID[m_nApplicationID][nCommandType][nKey]])) {\r
1127                 CallFunction(m_Config.nFunctionID[m_nApplicationID][nCommandType][nKey]);\r
1128                 CCommands::Reset(GOTO_HOOK);\r
1129                 goto HOOK;\r
1130         }\r
1131 \r
1132         if (!Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand) {\r
1133                 if (nKey == VK_CONTROL\r
1134                  || nKey == VK_LCONTROL\r
1135                  || nKey == VK_RCONTROL\r
1136                  || nKey == VK_MENU\r
1137                  || nKey == VK_LMENU\r
1138                  || nKey == VK_RMENU\r
1139                  || nKey == VK_SHIFT\r
1140                  || nKey == VK_LSHIFT\r
1141                  || nKey == VK_RSHIFT) {\r
1142                         goto DO_NOTHING;\r
1143                 }\r
1144 \r
1145                 if (!(nCommandType & SHIFT)) {\r
1146                         if (CCommands::IsSetMark()) {\r
1147                                 if (CCommands::MoveCaret(nKey, nCommandType & CONTROL) != CONTINUE) {\r
1148                                         CCommands::ClearNumericArgument();\r
1149                                         goto HOOK;\r
1150                                 }\r
1151                                 CCommands::SetMark(FALSE);\r
1152                         }\r
1153                 }\r
1154 \r
1155                 if (1 < CCommands::GetNumericArgument()) {\r
1156                         Kdu(nKey, CCommands::GetNumericArgument());\r
1157                         CCommands::ClearNumericArgument();\r
1158                         goto HOOK;\r
1159                 }\r
1160 \r
1161                 goto DO_NOTHING;\r
1162         }\r
1163 \r
1164         if (CCommands::IsTemporarilyDisableXKeymacs()\r
1165          && Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand != CCommands::KeyboardQuit) {\r
1166                 CCommands::SetTemporarilyDisableXKeymacs(FALSE);\r
1167                 goto DO_NOTHING;\r
1168         }\r
1169 \r
1170         if (m_Config.bAtIbeamCursorOnly[m_nApplicationID][nCommandType][nKey]) {\r
1171                 CURSORINFO cursorinfo = { sizeof(cursorinfo) };\r
1172                 if (GetCursorInfo(&cursorinfo) && cursorinfo.flags && cursorinfo.hCursor != LoadCursor(NULL, IDC_IBEAM)) {\r
1173                         goto DO_NOTHING;\r
1174                 }\r
1175         }\r
1176 \r
1177         m_bRightControl = IsDown(VK_RCONTROL, FALSE);\r
1178         m_bRightAlt = IsDown(VK_RMENU, FALSE);\r
1179         m_bRightShift = IsDown(VK_RSHIFT, FALSE);\r
1180 \r
1181         if (!bLocked) {\r
1182                 bLocked = TRUE;\r
1183                 fCommand = Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand;\r
1184 RECURSIVE_COMMAND:\r
1185                 switch (fCommand()) {\r
1186                 case GOTO_DO_NOTHING:\r
1187                         bLocked = FALSE;\r
1188                         goto DO_NOTHING;\r
1189                 case GOTO_HOOK:\r
1190                         bLocked = FALSE;\r
1191                         goto HOOK;\r
1192                 case GOTO_RECURSIVE:\r
1193                         goto RECURSIVE;\r
1194                 case GOTO_HOOKX:\r
1195                         bLocked = FALSE;\r
1196                         goto HOOKX;\r
1197                 case GOTO_HOOK0_9:\r
1198                         bLocked = FALSE;\r
1199                         goto HOOK0_9;\r
1200                 default:\r
1201                         ASSERT(0);\r
1202                         bLocked = FALSE;\r
1203                         goto DO_NOTHING;\r
1204                 }\r
1205         } else {\r
1206                 goto HOOK_RECURSIVE_KEY;\r
1207         }\r
1208 \r
1209 DO_NOTHING:\r
1210         SetModifierIcons();\r
1211         {\r
1212                 static BOOL bDefiningMacro = FALSE;\r
1213                 if (m_bDefiningMacro) {\r
1214                         static BOOL bDown[MAX_KEY] = {'\0'};\r
1215 \r
1216                         if (!bDefiningMacro) {\r
1217                                 while (m_Macro.GetHeadPosition()) {\r
1218                                         void *p = m_Macro.GetAt(m_Macro.GetHeadPosition());\r
1219                                         m_Macro.RemoveHead();\r
1220                                         delete p;\r
1221                                         p = NULL;\r
1222                                 }\r
1223                                 memset(bDown, 0, sizeof(bDown));\r
1224                         }\r
1225 \r
1226                         if ((!(lParam & BEING_RELEASED)) || bDown[wParam]) {\r
1227                                 try {\r
1228                                         KbdMacro *pKbdMacro = new KbdMacro;\r
1229                                         if (pKbdMacro) {\r
1230                                                 pKbdMacro->nCode = nCode;\r
1231                                                 pKbdMacro->wParam = wParam;\r
1232                                                 pKbdMacro->lParam = lParam;\r
1233                                                 pKbdMacro->bOriginal = TRUE;\r
1234                                                 m_Macro.AddTail((CObject *)pKbdMacro);\r
1235                                         }\r
1236                                 }\r
1237                                 catch (CMemoryException* e) {\r
1238                                         e->Delete();\r
1239 //                                      CUtils::Log("KeyboardProc: 'new' threw an exception");\r
1240                                 }\r
1241                                 if (!(lParam & BEING_RELEASED)) {\r
1242                                         bDown[wParam] = TRUE;\r
1243                                 }\r
1244                         }\r
1245                 }\r
1246                 bDefiningMacro = m_bDefiningMacro;\r
1247         }\r
1248 \r
1249         return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam);\r
1250 \r
1251 RECURSIVE:\r
1252         Kdu(RECURSIVE_KEY, 1, FALSE);\r
1253         goto HOOKX;\r
1254 HOOK:\r
1255         CCommands::SetLastCommand(fCommand);\r
1256 HOOK0_9:\r
1257 HOOKX:\r
1258         SetModifierIcons();\r
1259 HOOK_RECURSIVE_KEY:\r
1260         return TRUE;\r
1261 }\r
1262 \r
1263 void CXkeymacsDll::SetModifierIcons()\r
1264 {\r
1265 #define IconState(x) ((x) ? ON_ICON : OFF_ICON)\r
1266         ICONMSG msg[6] = {\r
1267                 {MX_ICON, IconState(CCommands::bM_x()), ""},\r
1268                 {CX_ICON, IconState(CCommands::bC_x()), ""},\r
1269                 {META_ICON, IconState(CCommands::bM_()), ""},\r
1270                 {SHIFT_ICON, IconState(IsDown(VK_SHIFT, FALSE)), ""},\r
1271                 {CTRL_ICON, IconState(IsControl()), ""},\r
1272                 {ALT_ICON, IconState(IsDown(VK_MENU, FALSE)), ""}\r
1273         };\r
1274         _tcscpy_s(msg[0].szTip, m_M_xTip);\r
1275         SendIconMessage(msg, 6);\r
1276 }\r
1277 \r
1278 void CXkeymacsDll::SetApplicationName(int nApplicationID, CString szApplicationName)\r
1279 {\r
1280         ZeroMemory(m_Config.szSpecialApp[nApplicationID], CLASS_NAME_LENGTH);\r
1281         _tcsncpy_s(m_Config.szSpecialApp[nApplicationID], szApplicationName, _TRUNCATE);\r
1282 }\r
1283 \r
1284 void CXkeymacsDll::SetWindowText(int nApplicationID, CString szWindowText)\r
1285 {\r
1286         ZeroMemory(m_Config.szWindowText[nApplicationID], WINDOW_TEXT_LENGTH);\r
1287         _tcsncpy_s(m_Config.szWindowText[nApplicationID], szWindowText, _TRUNCATE);\r
1288 }\r
1289 \r
1290 void CXkeymacsDll::SetCommandID(int nApplicationID, int nCommandType, int nKey, int nCommandID)\r
1291 {\r
1292         m_Config.nCommandID[nApplicationID][nCommandType][nKey] = nCommandID;\r
1293 }\r
1294 \r
1295 void CXkeymacsDll::SetAtIbeamCursorOnly(int nApplicationID, int nCommandType, int nKey, BOOL bAtIbeamCursorOnly)\r
1296 {\r
1297         m_Config.bAtIbeamCursorOnly[nApplicationID][nCommandType][nKey] = bAtIbeamCursorOnly;\r
1298 }\r
1299 \r
1300 void CXkeymacsDll::SetKillRingMax(int nApplicationID, int nKillRingMax)\r
1301 {\r
1302         m_Config.nKillRingMax[nApplicationID] = nKillRingMax;\r
1303 }\r
1304 \r
1305 void CXkeymacsDll::SetUseDialogSetting(int nApplicationID, BOOL bUseDialogSetting)\r
1306 {\r
1307         m_Config.bUseDialogSetting[nApplicationID] = bUseDialogSetting;\r
1308 }\r
1309 \r
1310 // Clear data of nApplicationID\r
1311 void CXkeymacsDll::Clear(int nApplicationID)\r
1312 {\r
1313         if (0 <= nApplicationID && nApplicationID < MAX_APP) {\r
1314                 ZeroMemory(m_Config.szSpecialApp[nApplicationID], sizeof(m_Config.szSpecialApp[nApplicationID]));\r
1315                 ZeroMemory(m_Config.nCommandID[nApplicationID], sizeof(m_Config.nCommandID[nApplicationID]));\r
1316                 ZeroMemory(m_Config.bAtIbeamCursorOnly[nApplicationID], sizeof(m_Config.bAtIbeamCursorOnly[nApplicationID]));\r
1317                 m_Config.nKillRingMax[nApplicationID] = 0;\r
1318                 m_Config.bUseDialogSetting[nApplicationID] = FALSE;\r
1319                 m_Config.nSettingStyle[nApplicationID] = 0;\r
1320         } else {\r
1321                 ASSERT(0);\r
1322         }\r
1323 }\r
1324 \r
1325 BOOL CXkeymacsDll::IsValidKey(BYTE bVk)\r
1326 {\r
1327         if (bVk == 0xf0) {      // 0xf0: Eisu key. GetAsyncKeyState returns the wrong state of Eisu key.\r
1328                 return FALSE;\r
1329         }\r
1330 \r
1331         switch (bVk) {\r
1332         case VK_CONTROL:\r
1333         case VK_MENU:\r
1334         case VK_SHIFT:\r
1335                 return FALSE;\r
1336         default:\r
1337                 break;\r
1338         }\r
1339 \r
1340         return TRUE;\r
1341 }\r
1342 \r
1343 BOOL CXkeymacsDll::IsDepressedModifier(int (__cdecl *Modifier)(void), BOOL bPhysicalKey)\r
1344 {\r
1345         BYTE bVk = 0;\r
1346         do {\r
1347                 if (IsValidKey(bVk) && IsDown(bVk, bPhysicalKey) &&\r
1348                                 Commands[m_Config.nCommandID[m_nApplicationID][NONE][bVk]].fCommand == Modifier)\r
1349                         return TRUE;\r
1350         } while (++bVk);\r
1351         return FALSE;\r
1352 }\r
1353 \r
1354 BOOL CXkeymacsDll::IsDepressedShiftKeyOnly(BYTE nKey)\r
1355 {\r
1356         if (nKey != VK_SHIFT\r
1357          && nKey != VK_LSHIFT\r
1358          && nKey != VK_RSHIFT) {\r
1359                 return FALSE;\r
1360         }\r
1361 \r
1362         BYTE bVk = 0;\r
1363         do {\r
1364                 if (bVk == VK_SHIFT\r
1365                  || bVk == VK_LSHIFT\r
1366                  || bVk == VK_RSHIFT) {\r
1367                         continue;\r
1368                 }\r
1369 \r
1370                 if (IsDown(bVk, FALSE)) {\r
1371                         return FALSE;\r
1372                 }\r
1373         } while (++bVk);\r
1374         return TRUE;\r
1375 }\r
1376 \r
1377 BOOL CXkeymacsDll::IsControl()\r
1378 {\r
1379         return CCommands::bC_() || IsDepressedModifier(CCommands::C_);\r
1380 }\r
1381 \r
1382 BOOL CXkeymacsDll::IsMeta()\r
1383 {\r
1384         return CCommands::bM_() || IsDepressedModifier(CCommands::MetaAlt);\r
1385 }\r
1386 \r
1387 void CXkeymacsDll::AddKillRing(BOOL bNewData)\r
1388 {\r
1389         if (m_Config.nKillRingMax[m_nApplicationID] == 0) {\r
1390                 return;\r
1391         }\r
1392 \r
1393         CClipboardSnap *pSnap = new CClipboardSnap;\r
1394         if( !pSnap ) return;\r
1395 \r
1396         BOOL bCapture = pSnap->Capture();\r
1397         bCapture = pSnap->Capture();    // for "office drawing shape format". Can CClipboardSnap care this problem?\r
1398 \r
1399         if( bCapture ) {\r
1400                 if (bNewData) {\r
1401                         m_oKillRing.AddHead(pSnap);\r
1402                 } else {\r
1403                         if (m_oKillRing.IsEmpty()) {\r
1404                                 m_oKillRing.AddHead(pSnap);\r
1405                         } else {\r
1406                                 for (CClipboardSnap *pParent = m_oKillRing.GetHead(); pParent->GetNext(); pParent = pParent->GetNext()) {\r
1407                                         ;\r
1408                                 }\r
1409                                 pParent->SetNext(pSnap);\r
1410                         }\r
1411                 }\r
1412         } else {\r
1413                 delete pSnap;\r
1414                 pSnap = NULL;\r
1415         }\r
1416 \r
1417         m_nKillRing = 0;\r
1418 \r
1419         if (m_Config.nKillRingMax[m_nApplicationID] < m_oKillRing.GetCount()) {\r
1420                 CClipboardSnap *pSnap = m_oKillRing.GetTail();\r
1421                 delete pSnap;\r
1422                 pSnap = NULL;\r
1423                 m_oKillRing.RemoveTail();\r
1424         }\r
1425 }\r
1426 \r
1427 // Return TRUE if there is another data\r
1428 // Return FALSE if there is no more data\r
1429 CClipboardSnap* CXkeymacsDll::GetKillRing(CClipboardSnap* pSnap, BOOL bForce)\r
1430 {\r
1431         if (m_Config.nKillRingMax[m_nApplicationID] == 0) {\r
1432                 return NULL;\r
1433         }\r
1434 \r
1435         if (m_oKillRing.IsEmpty()) {\r
1436                 return NULL;\r
1437         }\r
1438 \r
1439         m_nKillRing %= m_oKillRing.GetCount();\r
1440 \r
1441         if (!bForce) {\r
1442                 CClipboardSnap oCurrentSnap;\r
1443                 oCurrentSnap.Capture();\r
1444 \r
1445                 CClipboardSnap *pKillRing = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));\r
1446                 if (!pKillRing) {\r
1447                         return NULL;\r
1448                 }\r
1449                 for (; pKillRing->GetNext(); pKillRing = pKillRing->GetNext()) {\r
1450                         ;\r
1451                 }\r
1452                 if (*pKillRing != oCurrentSnap) {\r
1453                         return NULL;\r
1454                 }\r
1455         }\r
1456 \r
1457         if (!pSnap) {\r
1458                 pSnap = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));\r
1459         }\r
1460         pSnap->Restore();\r
1461 \r
1462         return pSnap->GetNext();\r
1463 }\r
1464 \r
1465 void CXkeymacsDll::Original(int nCommandType, BYTE bVk, int nOriginal)\r
1466 {\r
1467         nCommandType &= ~SHIFT;\r
1468 \r
1469         switch (bVk) {\r
1470         case VK_CONTROL:\r
1471                 bVk = VK_LCONTROL;\r
1472                 break;\r
1473         case VK_MENU:\r
1474                 bVk = VK_LMENU;\r
1475                 break;\r
1476         case VK_SHIFT:\r
1477                 bVk = VK_LSHIFT;\r
1478                 break;\r
1479         default:\r
1480                 break;\r
1481         }\r
1482 \r
1483         m_nOriginal[nCommandType][bVk] += nOriginal;\r
1484 }\r
1485 \r
1486 int CXkeymacsDll::Original(int nCommandType, BYTE bVk)\r
1487 {\r
1488         nCommandType &= ~SHIFT;\r
1489 \r
1490         switch (bVk) {\r
1491         case VK_CONTROL:\r
1492                 bVk = VK_LCONTROL;\r
1493                 break;\r
1494         case VK_MENU:\r
1495                 bVk = VK_LMENU;\r
1496                 break;\r
1497         case VK_SHIFT:\r
1498                 bVk = VK_LSHIFT;\r
1499                 break;\r
1500         default:\r
1501                 break;\r
1502         }\r
1503 \r
1504         return m_nOriginal[nCommandType][bVk];\r
1505 }\r
1506 \r
1507 void CXkeymacsDll::IncreaseKillRingIndex(int nKillRing)\r
1508 {\r
1509         m_nKillRing += nKillRing;\r
1510 }\r
1511 \r
1512 // nobody use\r
1513 int CXkeymacsDll::GetMickey(int nDifferential, int nThreshold1, int nThreshold2, int nAcceleration, int nSpeed)\r
1514 {\r
1515         nDifferential = nDifferential * 10 / nSpeed;\r
1516 \r
1517         switch (nAcceleration) {\r
1518         case 2:\r
1519                 if (nThreshold2 < fabs((double)(nDifferential / 4))) {\r
1520                         nDifferential /= 4;\r
1521                         break;\r
1522                 }\r
1523                 // Do NOT write break; here.\r
1524         case 1:\r
1525                 if (nThreshold1 < fabs((double)(nDifferential / 2))) {\r
1526                         nDifferential /= 2;\r
1527                 }\r
1528                 break;\r
1529         case 0:\r
1530                 break;\r
1531         default:\r
1532                 ASSERT(0);\r
1533                 break;\r
1534         }\r
1535 \r
1536         return nDifferential;\r
1537 }\r
1538 \r
1539 void CXkeymacsDll::SetSettingStyle(int nApplicationID, int nSettingStyle)\r
1540 {\r
1541         m_Config.nSettingStyle[nApplicationID] = nSettingStyle;\r
1542 }\r
1543 \r
1544 void CXkeymacsDll::SetIgnoreUndefinedMetaCtrl(int nApplicationID, BOOL bIgnoreUndefinedMetaCtrl)\r
1545 {\r
1546         m_Config.bIgnoreUndefinedMetaCtrl[nApplicationID] = bIgnoreUndefinedMetaCtrl;\r
1547 }\r
1548 \r
1549 void CXkeymacsDll::SetIgnoreUndefinedC_x(int nApplicationID, BOOL bIgnoreUndefinedC_x)\r
1550 {\r
1551         m_Config.bIgnoreUndefinedC_x[nApplicationID] = bIgnoreUndefinedC_x;\r
1552 }\r
1553 \r
1554 void CXkeymacsDll::SetEnableCUA(int nApplicationID, BOOL bEnableCUA)\r
1555 {\r
1556         m_Config.bEnableCUA[nApplicationID] = bEnableCUA;\r
1557 }\r
1558 \r
1559 BOOL CXkeymacsDll::GetEnableCUA()\r
1560 {\r
1561         return m_Config.bEnableCUA[m_nApplicationID];\r
1562 }\r
1563 \r
1564 void CXkeymacsDll::DefiningMacro(BOOL bDefiningMacro)\r
1565 {\r
1566         m_bDefiningMacro = bDefiningMacro;\r
1567 \r
1568         if (bDefiningMacro) {   // start-kbd-macro\r
1569                 if (CCommands::bC_u()) {\r
1570                         ReleaseKey(VK_SHIFT);\r
1571                         CallMacro();\r
1572                 }\r
1573         } else {                                // end-kbd-macro\r
1574                 while (!m_Macro.IsEmpty()) {\r
1575                         KbdMacro *pKbdMacro = (KbdMacro *)m_Macro.GetTail();\r
1576                         if (pKbdMacro->lParam & BEING_RELEASED) {\r
1577                                 break;\r
1578                         } else {\r
1579                                 m_Macro.RemoveTail();\r
1580                                 delete pKbdMacro;\r
1581                                 pKbdMacro = NULL;\r
1582                         }\r
1583                 }\r
1584 \r
1585 //              CUtils::Log(_T("Macro MemMap: start"));\r
1586                 if (!m_Macro.IsEmpty()) {\r
1587                         static HANDLE hMacro = NULL;\r
1588                         if (!hMacro) {\r
1589                                 hMacro = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x3000, _T("macro"));\r
1590                         }\r
1591                         if (hMacro) {\r
1592 //                              CUtils::Log(_T("Macro MemMap: 1"));\r
1593                                 PVOID pView = MapViewOfFile(hMacro, FILE_MAP_ALL_ACCESS, 0, 0, 0);\r
1594 //                              CUtils::Log(_T("Macro MemMap: 2"));\r
1595                                 if (pView) {\r
1596 //                                      CUtils::Log(_T("Macro MemMap: 2.5"));\r
1597                                         for (int i = 0; i < m_Macro.GetCount(); ++i) {\r
1598 //                                              CUtils::Log(_T("Macro MemMap: 3-1 %d"), i);\r
1599                                                 KbdMacro *pKbdMacro = (KbdMacro *)m_Macro.GetAt(m_Macro.FindIndex(i));\r
1600 //                                              CUtils::Log(_T("Macro MemMap: 3-2 %d"), i);\r
1601                                                 memcpy((LPTSTR) pView + i * sizeof(KbdMacro), pKbdMacro, sizeof(KbdMacro));\r
1602 //                                              CUtils::Log(_T("Macro MemMap: 3-3 %d"), i);\r
1603                                         }\r
1604 //                                      CUtils::Log(_T("Macro MemMap: 4"));\r
1605                                         UnmapViewOfFile(pView);\r
1606 //                                      CUtils::Log(_T("Macro MemMap: 5"));\r
1607                                 } else {\r
1608 //                                      CUtils::Log(_T("Macro MemMpa: error: %d"), GetLastError());\r
1609                                 }\r
1610                         } else {\r
1611 //                              CUtils::Log(_T("Macro MemMap: 6"));\r
1612                                 ASSERT(0);\r
1613                         }\r
1614                 }\r
1615         }\r
1616 }\r
1617 \r
1618 BOOL CXkeymacsDll::DefiningMacro()\r
1619 {\r
1620         return m_bDefiningMacro;\r
1621 }\r
1622 \r
1623 /**/ \r
1624 void CXkeymacsDll::CallMacro()\r
1625 {\r
1626         UINT before = GetModifierState(FALSE);\r
1627         SetModifierState(0, before);\r
1628         for (POSITION pos = m_Macro.GetHeadPosition(); pos; ) {\r
1629                 KbdMacro *pKbdMacro = (KbdMacro *)m_Macro.GetNext(pos);\r
1630                 if (pKbdMacro->lParam & BEING_RELEASED) {\r
1631                         ReleaseKey((BYTE)pKbdMacro->wParam);\r
1632                 } else {\r
1633                         DepressKey((BYTE)pKbdMacro->wParam, pKbdMacro->bOriginal);\r
1634                 }\r
1635         }\r
1636         SetModifierState(before, 0);\r
1637 }\r
1638 \r
1639 /*\r
1640 void CXkeymacsDll::CallMacro()  // for debug\r
1641 {\r
1642         CString sz;\r
1643         for (POSITION pos = m_Macro.GetHeadPosition(); pos; ) {\r
1644                 KbdMacro_t *pKbdMacro = (KbdMacro_t *)m_Macro.GetNext(pos);\r
1645                 if (pKbdMacro->lParam & BEING_RELEASED) {\r
1646                         CString t;\r
1647                         t.Format(_T("0x%xu "), pKbdMacro->wParam);\r
1648                         sz += t;\r
1649                 } else {\r
1650                         CString t;\r
1651                         t.Format(_T("0x%xd "), pKbdMacro->wParam);\r
1652                         sz += t;\r
1653                 }\r
1654         }\r
1655 //      CUtils::Log(sz);\r
1656 }\r
1657 */\r
1658 \r
1659 void CXkeymacsDll::Set106Keyboard(BOOL b106Keyboard)\r
1660 {\r
1661         m_Config.b106Keyboard = b106Keyboard;\r
1662 }\r
1663 \r
1664 BOOL CXkeymacsDll::Is106Keyboard()\r
1665 {\r
1666         return m_Config.b106Keyboard;\r
1667 }\r
1668 \r
1669 int CXkeymacsDll::IsPassThrough(BYTE nKey)\r
1670 {\r
1671         BYTE bVk = 0;\r
1672         do {\r
1673                 if (IsDown(bVk)\r
1674                  && (Commands[m_Config.nCommandID[m_nApplicationID][NONE][bVk]].fCommand == CCommands::PassThrough)) {\r
1675                         if (bVk == nKey) {\r
1676                                 return GOTO_HOOK;\r
1677                         }\r
1678 \r
1679                         return GOTO_DO_NOTHING;\r
1680                 }\r
1681         } while (++bVk);\r
1682         return CONTINUE;\r
1683 }\r
1684 \r
1685 void CXkeymacsDll::SetFunctionKey(int nFunctionID, int nApplicationID, int nCommandType, int nKey)\r
1686 {\r
1687         if (nApplicationID      < 0 || MAX_APP                  <= nApplicationID\r
1688          || nCommandType        < 0 || MAX_COMMAND_TYPE <= nCommandType\r
1689          || nKey                        < 0 || MAX_KEY                  <= nKey) {\r
1690                 return;\r
1691         }\r
1692 \r
1693         m_Config.nFunctionID[nApplicationID][nCommandType][nKey] = nFunctionID;\r
1694 }\r
1695 \r
1696 void CXkeymacsDll::ClearFunctionDefinition()\r
1697 {\r
1698         memset(m_Config.nFunctionID, -1, sizeof(m_Config.nFunctionID));\r
1699         memset(m_Config.szFunctionDefinition, 0, sizeof(m_Config.szFunctionDefinition));\r
1700 }\r
1701 \r
1702 void CXkeymacsDll::SetFunctionDefinition(int nFunctionID, CString szDefinition)\r
1703 {\r
1704         if (nFunctionID < 0 || MAX_FUNCTION <= nFunctionID) {\r
1705                 return;\r
1706         }\r
1707 \r
1708         memset(m_Config.szFunctionDefinition[nFunctionID], 0, sizeof(m_Config.szFunctionDefinition[nFunctionID]));\r
1709         _stprintf_s(m_Config.szFunctionDefinition[nFunctionID], _T("%s"), szDefinition);\r
1710 \r
1711         return;\r
1712 \r
1713 }\r
1714 \r
1715 // call an original command which is defined in dot.xkeymacs\r
1716 void CXkeymacsDll::CallFunction(int nFunctionID)\r
1717 {\r
1718         CArray<KeyBind, KeyBind> keybinds;\r
1719 \r
1720         if (nFunctionID < 0 || MAX_FUNCTION <= nFunctionID || !_tcslen(m_Config.szFunctionDefinition[nFunctionID])) {\r
1721                 return;\r
1722         }\r
1723 \r
1724         UINT before = GetModifierState(FALSE);\r
1725 \r
1726         if (m_Config.szFunctionDefinition[nFunctionID][0] == _T('"') && m_Config.szFunctionDefinition[nFunctionID][_tcslen(m_Config.szFunctionDefinition[nFunctionID]) - 1] == _T('"')) {\r
1727                 for (unsigned int i = 1; i < _tcslen(m_Config.szFunctionDefinition[nFunctionID]) - 1; ++i) {    // skip '"'\r
1728                         keybinds.Add(ParseKey(nFunctionID, i));\r
1729                 }\r
1730         } else if (m_Config.szFunctionDefinition[nFunctionID][0] == _T('[') && m_Config.szFunctionDefinition[nFunctionID][_tcslen(m_Config.szFunctionDefinition[nFunctionID]) - 1] == _T(']')) {\r
1731                 for (unsigned int i = 1; i < _tcslen(m_Config.szFunctionDefinition[nFunctionID]) - 1; ++i) {    // skip '[' and ']'\r
1732                         if (m_Config.szFunctionDefinition[nFunctionID][i] == _T('?')) { // [?f ?o ?o]\r
1733                                 ++i;\r
1734                                 keybinds.Add(ParseKey(nFunctionID, i));\r
1735                         } else {                                                                                                // [ControlCharacter]\r
1736                                 for (int nKeyID = 0; nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0]); ++nKeyID) {\r
1737                                         if (!_tcsncmp(m_Config.szFunctionDefinition[nFunctionID] + i, ControlCharacters[nKeyID].name, _tcslen(ControlCharacters[nKeyID].name))) {\r
1738                                                 KeyBind keybind = {NONE, ControlCharacters[nKeyID].bVk};\r
1739                                                 keybinds.Add(keybind);\r
1740                                                 i += _tcslen(ControlCharacters[nKeyID].name);\r
1741                                                 break;\r
1742                                         }\r
1743                                 }\r
1744                         }\r
1745                 }\r
1746         } else {\r
1747                 return;\r
1748         }\r
1749 \r
1750         BOOL bM_x = FALSE;\r
1751         TCHAR szPath[MAX_PATH] = {'\0'};\r
1752         unsigned int index = 0;\r
1753         BOOL bInitialized = FALSE;\r
1754 \r
1755         for (int i = 0; i < keybinds.GetSize(); ++i) {\r
1756                 const int nCommandType = keybinds.GetAt(i).nCommandType;\r
1757                 const BYTE bVk = keybinds.GetAt(i).bVk;\r
1758 \r
1759                 if (nCommandType < MAX_COMMAND_TYPE && Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand) {\r
1760                         if (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand == CCommands::ExecuteExtendedCommand) {\r
1761                                 bM_x = TRUE;\r
1762                         } else if (!bInitialized) {\r
1763                                 SetModifierState(0, before);\r
1764                                 bInitialized = TRUE;\r
1765                         }\r
1766 //                      CUtils::Log("CallFunction: Command Name: %s", Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][bVk]].szCommandName);\r
1767                         while (Commands[m_Config.nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand() == GOTO_RECURSIVE) {\r
1768                                 ;\r
1769                         }\r
1770                 } else if (bM_x) {\r
1771                         if (bVk == VK_RETURN) {\r
1772                                 InvokeM_x(szPath);\r
1773                         } else {\r
1774                                 for (TCHAR nAscii = 1; nAscii != 0; ++nAscii) { // repeat until overflow\r
1775                                         if (bVk != 0 && a2v(nAscii) == bVk && ((nCommandType & SHIFT) != 0) == IsShift(nAscii)) {\r
1776 //                                              CUtils::Log("M-x: %#X (%c), %#X (%c)", bVk, bVk, nAscii, nAscii);\r
1777                                                 szPath[index++] = nAscii;\r
1778                                                 break;\r
1779                                         }\r
1780                                 }\r
1781                         }\r
1782                 } else {\r
1783                         if (!bInitialized) {\r
1784                                 SetModifierState(0, before);\r
1785                                 bInitialized = TRUE;\r
1786                         }\r
1787                         if (nCommandType & WIN_WIN)\r
1788                                 DepressKey(VK_LWIN);\r
1789                         if (nCommandType & WIN_CTRL)\r
1790                                 DepressKey(VK_CONTROL);\r
1791                         if (nCommandType & WIN_ALT)\r
1792                                 DepressKey(VK_MENU);\r
1793                         if (nCommandType & SHIFT)\r
1794                                 DepressKey(VK_SHIFT);\r
1795 \r
1796                         Kdu(bVk);\r
1797 \r
1798                         if (nCommandType & SHIFT && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & SHIFT)))\r
1799                                 ReleaseKey(VK_SHIFT);\r
1800                         if (nCommandType & WIN_ALT && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_ALT)))\r
1801                                 ReleaseKey(VK_MENU);\r
1802                         if (nCommandType & WIN_CTRL && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_CTRL)))\r
1803                                 ReleaseKey(VK_CONTROL);\r
1804                         if (nCommandType & WIN_WIN && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_WIN)))\r
1805                                 ReleaseKey(VK_LWIN);\r
1806                 }\r
1807         }\r
1808 \r
1809         keybinds.RemoveAll();\r
1810 \r
1811         if (bInitialized)\r
1812                 // If these lines are invoked at M-x, a window transition does not work well.\r
1813                 SetModifierState(before, 0);\r
1814         return;\r
1815 }\r
1816 \r
1817 KeyBind CXkeymacsDll::ParseKey(const int nFunctionID, unsigned int &i)\r
1818 {\r
1819         KeyBind keybind = {NONE};\r
1820 \r
1821         if (m_Config.szFunctionDefinition[nFunctionID][i] == _T('\\')) {\r
1822                 ++i;\r
1823                 BOOL bFound = FALSE;\r
1824                 do {\r
1825                         bFound = FALSE;\r
1826                         for (int ModifierID = 0; ModifierID < sizeof(Modifiers) / sizeof(Modifiers[0]); ++ModifierID) {\r
1827                                 if (!_tcsncmp(m_Config.szFunctionDefinition[nFunctionID] + i, Modifiers[ModifierID].name, _tcslen(Modifiers[ModifierID].name))\r
1828                                  && _tcslen(Modifiers[ModifierID].name) < _tcslen(m_Config.szFunctionDefinition[nFunctionID] + i)) {\r
1829                                         keybind.nCommandType |= Modifiers[ModifierID].id;\r
1830                                         i+= _tcslen(Modifiers[ModifierID].name);\r
1831                                         bFound = TRUE;\r
1832                                 }\r
1833                         }\r
1834                 } while (bFound);\r
1835         }\r
1836         if (IsShift(m_Config.szFunctionDefinition[nFunctionID][i]) && !(keybind.nCommandType & (WIN_CTRL | WIN_ALT | WIN_WIN))) {\r
1837                 keybind.nCommandType |= SHIFT;\r
1838         }\r
1839 \r
1840         for (int nKeyID = 0; nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0]); ++nKeyID) {\r
1841                 if (!_tcsncmp(m_Config.szFunctionDefinition[nFunctionID] + i, ControlCharacters[nKeyID].name, _tcslen(ControlCharacters[nKeyID].name))) {\r
1842                         i += _tcslen(ControlCharacters[nKeyID].name);\r
1843                         break;\r
1844                 }\r
1845         }\r
1846         if (nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0])) {\r
1847                 keybind.bVk = ControlCharacters[nKeyID].bVk;\r
1848         } else {\r
1849                 keybind.bVk = a2v(m_Config.szFunctionDefinition[nFunctionID][i]);\r
1850         }\r
1851 \r
1852         return keybind;\r
1853 }\r
1854 \r
1855 BOOL CXkeymacsDll::IsShift(TCHAR nAscii)\r
1856 {\r
1857         switch (nAscii) {\r
1858         case _T(' '):\r
1859                 return FALSE;\r
1860         case _T('!'):\r
1861         case _T('"'):\r
1862         case _T('#'):\r
1863         case _T('$'):\r
1864         case _T('%'):\r
1865         case _T('&'):\r
1866                 return TRUE;\r
1867         case _T('\''):\r
1868                 return m_Config.b106Keyboard;\r
1869         case _T('('):\r
1870         case _T(')'):\r
1871         case _T('*'):\r
1872         case _T('+'):\r
1873                 return TRUE;\r
1874         case _T(','):\r
1875         case _T('-'):\r
1876         case _T('.'):\r
1877         case _T('/'):\r
1878         case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'):\r
1879                 return FALSE;\r
1880         case _T(':'):\r
1881                 return !m_Config.b106Keyboard;\r
1882         case _T(';'):\r
1883                 return FALSE;\r
1884         case _T('<'):\r
1885                 return TRUE;\r
1886         case _T('='):\r
1887                 return m_Config.b106Keyboard;\r
1888         case _T('>'):\r
1889         case _T('?'):\r
1890                 return TRUE;\r
1891         case _T('@'):\r
1892                 return !m_Config.b106Keyboard;\r
1893         case _T('A'): case _T('B'): case _T('C'): case _T('D'): case _T('E'): case _T('F'): case _T('G'): case _T('H'): case _T('I'): case _T('J'): \r
1894         case _T('K'): case _T('L'): case _T('M'): case _T('N'): case _T('O'): case _T('P'): case _T('Q'): case _T('R'): case _T('S'): case _T('T'): \r
1895         case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
1896                 return TRUE;\r
1897         case _T('['):\r
1898         case _T('\\'):\r
1899         case _T(']'):\r
1900                 return FALSE;\r
1901         case _T('^'):\r
1902                 return !m_Config.b106Keyboard;\r
1903         case _T('_'):\r
1904                 return TRUE;\r
1905         case _T('`'):\r
1906                 return m_Config.b106Keyboard;\r
1907         case _T('a'): case _T('b'): case _T('c'): case _T('d'): case _T('e'): case _T('f'): case _T('g'): case _T('h'): case _T('i'): case _T('j'): \r
1908         case _T('k'): case _T('l'): case _T('m'): case _T('n'): case _T('o'): case _T('p'): case _T('q'): case _T('r'): case _T('s'): case _T('t'): \r
1909         case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
1910                 return FALSE;\r
1911         case _T('{'):\r
1912         case _T('|'):\r
1913         case _T('}'):\r
1914         case _T('~'):\r
1915                 return TRUE;\r
1916         default:\r
1917                 return FALSE;\r
1918         }\r
1919 }\r
1920 \r
1921 BYTE CXkeymacsDll::a2v(TCHAR nAscii)\r
1922 {\r
1923         switch (nAscii) {\r
1924         case _T(' '):\r
1925                 return VK_SPACE;\r
1926         case _T('!'):\r
1927                 return '1';\r
1928         case _T('"'):\r
1929                 return m_Config.b106Keyboard ? '2' : (BYTE) 0xde;       // VK_OEM_7\r
1930         case _T('#'):\r
1931                 return '3';\r
1932         case _T('$'):\r
1933                 return '4';\r
1934         case _T('%'):\r
1935                 return '5';\r
1936         case _T('&'):\r
1937                 return m_Config.b106Keyboard ? '6' : '7';\r
1938         case _T('\''):\r
1939                 return m_Config.b106Keyboard ? '7' : (BYTE) 0xde;       // VK_OEM_7\r
1940         case _T('('):\r
1941                 return m_Config.b106Keyboard ? '8' : '9';\r
1942         case _T(')'):\r
1943                 return m_Config.b106Keyboard ? '9' : '0';\r
1944         case _T('*'):\r
1945                 return m_Config.b106Keyboard ? (BYTE) 0xba : '8';       // VK_OEM_1\r
1946         case _T('+'):\r
1947                 return 0xbb;    // VK_OEM_PLUS\r
1948         case _T(','):\r
1949                 return 0xbc;    // VK_OEM_COMMA\r
1950         case _T('-'):\r
1951                 return 0xbd;    // VK_OEM_MINUS\r
1952         case _T('.'):\r
1953                 return 0xbe;    // VK_OEM_PERIOD\r
1954         case _T('/'):\r
1955                 return 0xbf;    // VK_OEM_2\r
1956         case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'):\r
1957                 return nAscii;\r
1958         case _T(':'):\r
1959                 return 0xba;    // VK_OEM_1\r
1960         case _T(';'):\r
1961                 return m_Config.b106Keyboard ? (BYTE) 0xbb : (BYTE) 0xba;       // VK_OEM_PLUS  VK_OEM_1\r
1962         case _T('<'):\r
1963                 return 0xbc;    // VK_OEM_COMMA\r
1964         case _T('='):\r
1965                 return m_Config.b106Keyboard ? (BYTE) 0xbd : (BYTE) 0xbb;       // VK_OEM_MINUS VK_OEM_PLUS\r
1966         case _T('>'):\r
1967                 return 0xbe;    // VK_OEM_PERIOD\r
1968         case _T('?'):\r
1969                 return 0xbf;    // VK_OEM_2\r
1970         case _T('@'):\r
1971                 return m_Config.b106Keyboard ? (BYTE) 0xc0 : '2';\r
1972         case _T('A'): case _T('B'): case _T('C'): case _T('D'): case _T('E'): case _T('F'): case _T('G'): case _T('H'): case _T('I'): case _T('J'): \r
1973         case _T('K'): case _T('L'): case _T('M'): case _T('N'): case _T('O'): case _T('P'): case _T('Q'): case _T('R'): case _T('S'): case _T('T'): \r
1974         case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
1975                 return nAscii;\r
1976         case _T('['):\r
1977                 return 0xdb;    // VK_OEM_4\r
1978         case _T('\\'):\r
1979                 return 0xdc;    // VK_OEM_5\r
1980         case _T(']'):\r
1981                 return 0xdd;    // VK_OEM_6\r
1982         case _T('^'):\r
1983                 return m_Config.b106Keyboard ? (BYTE) 0xde : '6';       // VK_OEM_7\r
1984         case _T('_'):\r
1985                 return m_Config.b106Keyboard ? (BYTE) 0xe2 : (BYTE) 0xbd;       // VK_OEM_102   VK_OEM_MINUS\r
1986         case _T('`'):\r
1987                 return 0xc0;    // VK_OEM_3\r
1988         case _T('a'): case _T('b'): case _T('c'): case _T('d'): case _T('e'): case _T('f'): case _T('g'): case _T('h'): case _T('i'): case _T('j'): \r
1989         case _T('k'): case _T('l'): case _T('m'): case _T('n'): case _T('o'): case _T('p'): case _T('q'): case _T('r'): case _T('s'): case _T('t'): \r
1990         case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
1991                 return (BYTE) (nAscii - (_T('a') - _T('A')));\r
1992         case _T('{'):\r
1993                 return 0xdb;    // VK_OEM_4\r
1994         case _T('|'):\r
1995                 return 0xdc;    // VK_OEM_5\r
1996         case _T('}'):\r
1997                 return 0xdd;    // VK_OEM_6\r
1998         case _T('~'):\r
1999                 return m_Config.b106Keyboard ? (BYTE) 0xde : (BYTE) 0xc0;       // VK_OEM_7     VK_OEM_3\r
2000         default:\r
2001                 return 0;\r
2002         }\r
2003 }\r
2004 \r
2005 BOOL CXkeymacsDll::IsMatchWindowText(CString szWindowText)\r
2006 {\r
2007         BOOL bIsMatchWindowText = TRUE;\r
2008 \r
2009         TCHAR szCurrentWindowText[WINDOW_TEXT_LENGTH] = {'\0'};\r
2010         GetWindowText(GetForegroundWindow(), szCurrentWindowText, sizeof(szCurrentWindowText));\r
2011 \r
2012         switch (CUtils::GetWindowTextType(szWindowText)) {\r
2013         case IDS_WINDOW_TEXT_MATCH:                                                             // *foo*\r
2014                 szWindowText.Delete(0);                                                         // Delete first '*'\r
2015                 szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
2016                 bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText);\r
2017                 break;\r
2018         case IDS_WINDOW_TEXT_MATCH_FORWARD:                                             // foo*\r
2019                 szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
2020                 bIsMatchWindowText = 0 == CString(szCurrentWindowText).Find(szWindowText);\r
2021                 break;\r
2022         case IDS_WINDOW_TEXT_MATCH_BACKWARD:                                    // *foo\r
2023                 szWindowText.Delete(0);                                                         // Delete first '*'\r
2024                 bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText, CString(szCurrentWindowText).GetLength() - szWindowText.GetLength());\r
2025                 break;\r
2026         case IDS_WINDOW_TEXT_MATCH_FULL:                                                // foo\r
2027                 bIsMatchWindowText = szWindowText == CString(szCurrentWindowText);\r
2028                 break;\r
2029         case IDS_WINDOW_TEXT_IGNORE:                                                    // *\r
2030                 bIsMatchWindowText = TRUE;\r
2031                 break;\r
2032         default:\r
2033                 ASSERT(0);\r
2034                 break;\r
2035         }\r
2036 \r
2037 //      CUtils::Log(_T("IsMatchWindowText: %d, _%s_, _%s_"), bIsMatchWindowText, szCurrentWindowText, szWindowText);\r
2038         return bIsMatchWindowText;\r
2039 }\r
2040 \r
2041 void CXkeymacsDll::SetAccelerate(int nAccelerate)\r
2042 {\r
2043         m_nAccelerate = nAccelerate;\r
2044 }\r
2045 \r
2046 int CXkeymacsDll::GetAccelerate()\r
2047 {\r
2048         return m_nAccelerate;\r
2049 }\r
2050 \r
2051 void CXkeymacsDll::SetKeyboardSpeed(int nKeyboardSpeed)\r
2052 {\r
2053         m_nKeyboardSpeed = nKeyboardSpeed;\r
2054 }\r
2055 \r
2056 unsigned int CXkeymacsDll::GetMaxKeyInterval()\r
2057 {\r
2058         // m_nKeyboardSpeed == 0:       slowest repeat rate; approximately  2 characters per second\r
2059         // m_nKeyboardSpeed == 31:      fastest repeat rate; approximately 30 characters per second\r
2060         // 47 ms is max on my machine w/ KeyboardSpeed 31.\r
2061         // 1000 /  2 + 50 = 550\r
2062         // 1000 / 30 + 50 = 83\r
2063         return (unsigned int) (1000.0 / (2.0 + m_nKeyboardSpeed % 32 * 28.0 / 31.0) + 50.0);\r
2064 }\r
2065 \r
2066 void CXkeymacsDll::SetCursorData(HCURSOR hEnable, HCURSOR hDisableTMP, HCURSOR hDisableWOCQ, HICON hDisable, BOOL bEnable)\r
2067 {\r
2068         m_hCursor[STATUS_ENABLE] = hEnable;\r
2069         m_hCursor[STATUS_DISABLE_TMP] = hDisableTMP;\r
2070         m_hCursor[STATUS_DISABLE_WOCQ] = hDisableWOCQ;\r
2071         m_hCursor[STATUS_DISABLE] = hDisable;\r
2072         m_bCursor = bEnable;\r
2073 }\r
2074 \r
2075 void CXkeymacsDll::DoSetCursor()\r
2076 {\r
2077         if (m_bCursor && m_hCurrentCursor) {\r
2078                 ::SetCursor(m_hCurrentCursor);\r
2079         }\r
2080 }\r
2081 \r
2082 void CXkeymacsDll::Set326Compatible(int nApplicationID, BOOL b326Compatible)\r
2083 {\r
2084         m_Config.b326Compatible[nApplicationID] = b326Compatible;\r
2085 }\r
2086 \r
2087 BOOL CXkeymacsDll::Get326Compatible()\r
2088 {\r
2089         return m_Config.b326Compatible[m_nApplicationID];\r
2090 }\r
2091 \r
2092 void CXkeymacsDll::InvokeM_x(const TCHAR *const szPath)\r
2093 {\r
2094 //      CUtils::Log("M-x: szPath=_%s_", szPath);\r
2095         int (*fCommand)() = NULL;\r
2096 \r
2097         for (int i = 0; i < MAX_COMMAND; ++i) {\r
2098                 if (_tcsicmp(szPath, Commands[i].szCommandName) == 0) {\r
2099                         fCommand = Commands[i].fCommand;\r
2100                         break;\r
2101                 }\r
2102         }\r
2103 \r
2104         if (fCommand) {\r
2105 //              CUtils::Log("M-x: Command: _%s_", Commands[i].szCommandName);\r
2106                 fCommand();\r
2107         } else {\r
2108 //              CUtils::Log("M-x: Path: _%s_", szPath);\r
2109                 ShellExecute(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);\r
2110         }\r
2111 }\r
2112 \r
2113 void CXkeymacsDll::SetM_xTip(const TCHAR *const szPath)\r
2114 {\r
2115         _tcscpy_s(m_M_xTip, "M-x LED");\r
2116         if (szPath && _tcslen(szPath) < 128 - 5)\r
2117                 _stprintf_s(m_M_xTip, "M-x %s", szPath);\r
2118 }\r
2119 \r
2120 BOOL CXkeymacsDll::SendIconMessage(ICONMSG *pMsg, DWORD num)\r
2121 {\r
2122         DWORD ack, read;\r
2123         return CallNamedPipe(ICON_PIPE, pMsg, sizeof(ICONMSG) * num, &ack, sizeof(DWORD), &read, NMPWAIT_NOWAIT);\r
2124 }\r