OSDN Git Service

f1e2b8b4a42da92cc7914b04a17a422a8a9f4d7c
[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 \r
19 static AFX_EXTENSION_MODULE XkeymacsdllDLL = { NULL, NULL };\r
20 \r
21 static __declspec(thread) HINSTANCE g_hDllInst = NULL;\r
22 static __declspec(thread) HHOOK g_hHookKeyboard = NULL;\r
23 \r
24 extern "C" int APIENTRY\r
25 DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r
26 {\r
27         g_hDllInst = hInstance;\r
28         \r
29         // Remove this if you use lpReserved\r
30         UNREFERENCED_PARAMETER(lpReserved);\r
31 \r
32         switch (dwReason) {\r
33         case DLL_PROCESS_ATTACH:\r
34                 TRACE0("XKEYMACSDLL.DLL Initializing!\n");\r
35                 \r
36                 // Extension DLL one-time initialization\r
37                 if (!AfxInitExtensionModule(XkeymacsdllDLL, hInstance)) {\r
38                         return 0;\r
39                 }\r
40 \r
41                 // Insert this DLL into the resource chain\r
42                 // NOTE: If this Extension DLL is being implicitly linked to by\r
43                 //  an MFC Regular DLL (such as an ActiveX Control)\r
44                 //  instead of an MFC application, then you will want to\r
45                 //  remove this line from DllMain and put it in a separate\r
46                 //  function exported from this Extension DLL.  The Regular DLL\r
47                 //  that uses this Extension DLL should then explicitly call that\r
48                 //  function to initialize this Extension DLL.  Otherwise,\r
49                 //  the CDynLinkLibrary object will not be attached to the\r
50                 //  Regular DLL's resource chain, and serious problems will\r
51                 //  result.\r
52 \r
53                 try {\r
54                         new CDynLinkLibrary(XkeymacsdllDLL);\r
55                 }\r
56                 catch (CMemoryException* e) {\r
57                         e->Delete();\r
58 //                      CUtils::Log("DllMain: 'new' threw an exception");\r
59                 }\r
60         case DLL_THREAD_ATTACH:\r
61                 CXkeymacsDll::SetKeyboardHook();\r
62                 break;\r
63         case DLL_PROCESS_DETACH:\r
64                 TRACE0("XKEYMACSDLL.DLL Terminating!\n");\r
65                 // Terminate the library before destructors are called\r
66                 AfxTermExtensionModule(XkeymacsdllDLL);\r
67         case DLL_THREAD_DETACH:\r
68                 CXkeymacsDll::ReleaseKeyboardHook();\r
69         }\r
70         return 1;   // ok\r
71 }\r
72 \r
73 //////////////////////////////////////////////////////////////////////\r
74 // CXkeymacsDll Class\r
75 //////////////////////////////////////////////////////////////////////\r
76 \r
77 #include "xkeymacsDll.h"\r
78 #pragma data_seg(".xkmcs")\r
79         BOOL    CXkeymacsDll::m_bEnableKeyboardHook = FALSE;\r
80         HHOOK   CXkeymacsDll::m_hHookCallWnd = NULL;\r
81         HHOOK   CXkeymacsDll::m_hHookCallWndRet = NULL;\r
82         HHOOK   CXkeymacsDll::m_hHookGetMessage = NULL;\r
83         HHOOK   CXkeymacsDll::m_hHookShell = NULL;\r
84         int             CXkeymacsDll::m_nCommandID[MAX_APP][MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
85         BOOL    CXkeymacsDll::m_bAtIbeamCursorOnly[MAX_APP][MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
86         int             CXkeymacsDll::m_nFunctionID[MAX_APP][MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
87         TCHAR   CXkeymacsDll::m_szSpecialApp[MAX_APP][CLASS_NAME_LENGTH] = {'\0'};\r
88         TCHAR   CXkeymacsDll::m_szWindowText[MAX_APP][WINDOW_TEXT_LENGTH] = {'\0'};\r
89         BOOL    CXkeymacsDll::m_bRightControl   = FALSE;\r
90         BOOL    CXkeymacsDll::m_bRightAlt               = FALSE;\r
91         BOOL    CXkeymacsDll::m_bRightShift             = FALSE;\r
92         BOOL    CXkeymacsDll::m_bHook                   = TRUE;\r
93         BOOL    CXkeymacsDll::m_bDefiningMacro  = FALSE;\r
94         DWORD   CXkeymacsDll::m_dwOldMessage[MAX_ICON_TYPE] = {'\0'};\r
95         NOTIFYICONDATA CXkeymacsDll::m_stNtfyIcon[MAX_ICON_TYPE] = {'\0'};\r
96         NOTIFYICONDATA CXkeymacsDll::m_stOldNtfyIcon[MAX_ICON_TYPE] = {'\0'};\r
97         HICON   CXkeymacsDll::m_hIcon[MAX_ICON_TYPE][MAX_STATUS] = {'\0'};\r
98         BOOL    CXkeymacsDll::m_bIcon[MAX_ICON_TYPE] = {'\0'};\r
99         int             CXkeymacsDll::m_nKillRingMax[MAX_APP] = {'\0'};\r
100         BOOL    CXkeymacsDll::m_bUseDialogSetting[MAX_APP] = {'\0'};\r
101         CList<CClipboardSnap *, CClipboardSnap *> CXkeymacsDll::m_oKillRing;\r
102         CObList CXkeymacsDll::m_Macro;\r
103         int             CXkeymacsDll::m_nKillRing = 0;\r
104         int             CXkeymacsDll::m_nOriginal[MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
105         int             CXkeymacsDll::m_nApplicationID = 0;\r
106         int             CXkeymacsDll::m_nSettingStyle[MAX_APP] = {'\0'};\r
107         BOOL    CXkeymacsDll::m_bIgnoreUndefinedMetaCtrl[MAX_APP] = {'\0'};\r
108         BOOL    CXkeymacsDll::m_bIgnoreUndefinedC_x[MAX_APP] = {'\0'};\r
109 //      int             CXkeymacsDll::m_nPassThrough = 0;\r
110         TCHAR   CXkeymacsDll::m_szApplicationName[MAX_PATH] = {'\0'};\r
111         TCHAR   CXkeymacsDll::m_szOldApplicationName[MAX_PATH] = {'\0'};\r
112         BOOL    CXkeymacsDll::m_bEnableCUA[MAX_APP] = {'\0'};\r
113         TCHAR   CXkeymacsDll::m_szFunctionDefinition[MAX_FUNCTION][MAX_DEFINITION] = {'\0'};\r
114         int             CXkeymacsDll::m_nAccelerate = 0;\r
115         int             CXkeymacsDll::m_nKeyboardSpeed = 31;\r
116         HCURSOR CXkeymacsDll::m_hCursor[MAX_STATUS] = {'\0'};\r
117         HCURSOR CXkeymacsDll::m_hCurrentCursor = NULL;\r
118         BOOL    CXkeymacsDll::m_bCursor = FALSE;\r
119         BOOL    CXkeymacsDll::m_b326Compatible[MAX_APP] = {'\0'};\r
120 \r
121         BOOL    CXkeymacsData::m_b106Keyboard = FALSE;\r
122 #pragma data_seg()\r
123 \r
124 //////////////////////////////////////////////////////////////////////\r
125 // Construction/Destruction\r
126 //////////////////////////////////////////////////////////////////////\r
127 \r
128 CXkeymacsDll::CXkeymacsDll()\r
129 {\r
130         CUtils::InitCUtils();\r
131 }\r
132 \r
133 CXkeymacsDll::~CXkeymacsDll()\r
134 {\r
135 \r
136 }\r
137 \r
138 int CXkeymacsDll::ModifyShell_NotifyIcon(ICON_TYPE icon, BOOL bNewStatus, BOOL bForce)\r
139 {\r
140         if (m_stNtfyIcon[icon].hIcon == (bNewStatus ? m_hIcon[icon][ON_ICON] : m_hIcon[icon][OFF_ICON])) {\r
141                 if (!bForce) {\r
142                         return TRUE;\r
143                 }\r
144         } else {\r
145                 m_stNtfyIcon[icon].hIcon = (bNewStatus ? m_hIcon[icon][ON_ICON] : m_hIcon[icon][OFF_ICON]);\r
146         }\r
147         return DoShell_NotifyIcon(icon, NIM_MODIFY);\r
148 }\r
149 \r
150 void CXkeymacsDll::SetNotifyIconData(ICON_TYPE icon, NOTIFYICONDATA stNtfyIcon, HICON hEnable, HICON hDisableTMP, HICON hDisableWOCQ, HICON hDisable, BOOL bEnable)\r
151 {\r
152         m_hIcon[icon][STATUS_ENABLE] = hEnable;\r
153         m_hIcon[icon][STATUS_DISABLE_TMP] = hDisableTMP;\r
154         m_hIcon[icon][STATUS_DISABLE_WOCQ] = hDisableWOCQ;\r
155         m_hIcon[icon][STATUS_DISABLE] = hDisable;\r
156         m_bIcon[icon] = bEnable;\r
157         m_stNtfyIcon[icon] = stNtfyIcon;\r
158         AddShell_NotifyIcon(icon);\r
159 }\r
160 \r
161 void CXkeymacsDll::SetNotifyIconData(ICON_TYPE icon, NOTIFYICONDATA stNtfyIcon, HICON hOn, HICON hOff, BOOL bEnable)\r
162 {\r
163         m_hIcon[icon][ON_ICON] = hOn;\r
164         m_hIcon[icon][OFF_ICON] = hOff;\r
165         m_bIcon[icon] = bEnable;\r
166         m_stNtfyIcon[icon] = stNtfyIcon;\r
167         AddShell_NotifyIcon(icon);\r
168 }\r
169 \r
170 void CXkeymacsDll::EnableShell_NotifyIcon(ICON_TYPE icon, BOOL bEnable)\r
171 {\r
172         DeleteShell_NotifyIcon(icon);\r
173         m_bIcon[icon] = bEnable;\r
174         AddShell_NotifyIcon(icon);\r
175 }\r
176 \r
177 \r
178 BOOL CXkeymacsDll::DoShell_NotifyIcon(ICON_TYPE icon, DWORD dwMessage)\r
179 {\r
180         if (m_bIcon[icon]\r
181          &&     (m_dwOldMessage[icon] != dwMessage\r
182           || memcmp(&m_stOldNtfyIcon[icon], &m_stNtfyIcon[icon], sizeof(m_stNtfyIcon[icon])))) {\r
183                 m_dwOldMessage[icon] = dwMessage;\r
184                 m_stOldNtfyIcon[icon] = m_stNtfyIcon[icon];\r
185 \r
186                 BOOL rc = FALSE;\r
187                 for (int retry_count = 0; retry_count < 20; ++retry_count) { // retry for timeout\r
188                         rc = Shell_NotifyIcon(dwMessage, &m_stNtfyIcon[icon]);\r
189                         if (dwMessage != NIM_ADD || rc || (GetLastError() != ERROR_TIMEOUT && 5 < retry_count)) {\r
190                                 break;\r
191                         }\r
192                         Sleep(1000); // 1sec\r
193                         if ((rc = Shell_NotifyIcon(NIM_MODIFY, &m_stNtfyIcon[icon])) != FALSE) {\r
194                                 break; // ERROR_TIMEOUT was returned but the icon was also added.\r
195                         }\r
196                 }\r
197                 return rc;\r
198         } else {\r
199                 return TRUE;\r
200         }\r
201 }\r
202 \r
203 void CXkeymacsDll::AddShell_NotifyIcon(ICON_TYPE icon)\r
204 {\r
205         DoShell_NotifyIcon(icon, NIM_ADD);\r
206 }\r
207 \r
208 void CXkeymacsDll::DeleteShell_NotifyIcon(ICON_TYPE icon)\r
209 {\r
210         DoShell_NotifyIcon(icon, NIM_DELETE);\r
211 }\r
212 \r
213 // set hooks\r
214 void CXkeymacsDll::SetHooks()\r
215 {\r
216         m_bEnableKeyboardHook = TRUE;\r
217         m_hHookCallWnd = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWndProc, g_hDllInst, 0);\r
218         m_hHookCallWndRet = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)CallWndRetProc, g_hDllInst, 0);\r
219         m_hHookGetMessage = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllInst, 0);\r
220         m_hHookShell = SetWindowsHookEx(WH_SHELL, (HOOKPROC)ShellProc, g_hDllInst, 0);\r
221 }\r
222 \r
223 void CXkeymacsDll::SetKeyboardHook()\r
224 {\r
225         if (!g_hHookKeyboard)\r
226                 SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, g_hDllInst, GetCurrentThreadId());\r
227 }\r
228 \r
229 // release hooks\r
230 void CXkeymacsDll::ReleaseHooks()\r
231 {\r
232         m_bEnableKeyboardHook = FALSE;\r
233         if (m_hHookCallWnd)\r
234                 UnhookWindowsHookEx(m_hHookCallWnd);\r
235         m_hHookCallWnd = NULL;\r
236         if (m_hHookCallWndRet)\r
237                 UnhookWindowsHookEx(m_hHookCallWndRet);\r
238         m_hHookCallWndRet = NULL;\r
239         if (m_hHookGetMessage)\r
240                 UnhookWindowsHookEx(m_hHookGetMessage);\r
241         m_hHookGetMessage = NULL;\r
242         if (m_hHookShell)\r
243                 UnhookWindowsHookEx(m_hHookShell);\r
244         m_hHookShell = NULL;\r
245 }\r
246 \r
247 void CXkeymacsDll::ReleaseKeyboardHook()\r
248 {\r
249         if (g_hHookKeyboard)\r
250                 UnhookWindowsHookEx(g_hHookKeyboard);\r
251         g_hHookKeyboard = NULL;\r
252 }\r
253 \r
254 void CXkeymacsDll::SetKeyboardHookFlag(BOOL bFlag)\r
255 {\r
256         m_bHook = bFlag;\r
257 \r
258         if (m_bHook) {\r
259                 if (CCommands::IsTemporarilyDisableXKeymacs()) {\r
260                         m_stNtfyIcon[MAIN_ICON].hIcon = m_hIcon[MAIN_ICON][STATUS_DISABLE_TMP];\r
261                         m_hCurrentCursor = m_hCursor[STATUS_DISABLE_TMP];\r
262                 } else {\r
263                         m_stNtfyIcon[MAIN_ICON].hIcon = m_hIcon[MAIN_ICON][STATUS_ENABLE];\r
264                         m_hCurrentCursor = m_hCursor[STATUS_ENABLE];\r
265                 }\r
266         } else {\r
267                 m_stNtfyIcon[MAIN_ICON].hIcon = m_hIcon[MAIN_ICON][STATUS_DISABLE_WOCQ];\r
268                 m_hCurrentCursor = m_hCursor[STATUS_DISABLE_WOCQ];\r
269         }\r
270         if (m_nSettingStyle[m_nApplicationID] == SETTING_DISABLE\r
271          || (!_tcsicmp(m_szSpecialApp[m_nApplicationID], _T("Default"))\r
272           && CUtils::IsDefaultIgnoreApplication())) {\r
273                 m_stNtfyIcon[MAIN_ICON].hIcon = m_hIcon[MAIN_ICON][STATUS_DISABLE];\r
274                 m_hCurrentCursor = m_hCursor[STATUS_DISABLE];\r
275         }\r
276         DoShell_NotifyIcon(MAIN_ICON, NIM_MODIFY);\r
277         DoSetCursor();\r
278 }\r
279 \r
280 // if be keyboard hook, return TRUE\r
281 BOOL CXkeymacsDll::IsKeyboardHook()\r
282 {\r
283         if (m_bHook) {\r
284                 return TRUE;\r
285         }\r
286 \r
287         return FALSE;\r
288 }\r
289 \r
290 void CXkeymacsDll::LogCallWndProcMessage(WPARAM wParam, LPARAM lParam)\r
291 {\r
292         CWPSTRUCT &cwps = *(CWPSTRUCT *)lParam;\r
293 \r
294         switch (cwps.message) {\r
295         case WM_PAINT:                                  // 0x000F\r
296         case WM_MDIGETACTIVE:                   // 0x0229\r
297         case 0x0403:\r
298         case 0x0407:\r
299         case 0x0418:\r
300         case 0x043F:\r
301         case 0x0440:\r
302                 break;\r
303         case WM_CREATE:                                 // 0x0001\r
304 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_CREATE"));\r
305                 break;\r
306         case WM_DESTROY:                                // 0x0002\r
307 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_DESTROY"));\r
308                 break;\r
309         case WM_MOVE:                                   // 0x0003\r
310 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_MOVE");)\r
311                 break;\r
312         case WM_SIZE:                                   // 0x0005\r
313 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_SIZE"));\r
314                 break;\r
315         case WM_GETTEXT:                                // 0x000D\r
316 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_GETTEXT"));\r
317                 break;\r
318         case WM_ERASEBKGND:                             // 0x0014\r
319 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_ERASEBKGND"));\r
320                 break;\r
321         case WM_WINDOWPOSCHANGING:              // 0x0046\r
322 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_WINDOWPOSCHANGING"));\r
323                 break;\r
324         case WM_WINDOWPOSCHANGED:               // 0x0047\r
325 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_WINDOWPOSCHANGED"));\r
326                 break;\r
327         case WM_COPYDATA:                               // 0x004A\r
328 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_COPYDATA"));\r
329                 break;\r
330         case WM_NCCREATE:                               // 0x0081\r
331 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCCREATE"));\r
332                 break;\r
333         case WM_NCDESTROY:                              // 0x0082\r
334 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCDESTROY"));\r
335                 break;\r
336         case WM_NCCALCSIZE:                             // 0x0083\r
337 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCCALCSIZE"));\r
338                 break;\r
339         case WM_NCPAINT:                                // 0x0085\r
340 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCPAINT"));\r
341                 break;\r
342         case WM_IME_STARTCOMPOSITION:   // 0x010D\r
343 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_STARTCOMPOSITION"));\r
344                 break;\r
345         case WM_IME_ENDCOMPOSITION:             // 0x010E\r
346 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_ENDCOMPOSITION"));\r
347                 break;\r
348         case WM_IME_KEYLAST:                    // 0x010F\r
349 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_KEYLAST"));\r
350                 break;\r
351         case WM_COMMAND:                                // 0x0111\r
352 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_COMMAND"));\r
353                 break;\r
354         case WM_CTLCOLOREDIT:                   // 0x0133\r
355 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_CTLCOLOREDIT"));\r
356                 break;\r
357         case WM_POWERBROADCAST:                 // 0x0218\r
358 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_POWERBROADCAST"));\r
359                 switch (wParam) {\r
360                 case PBT_APMQUERYSUSPEND:               // 0x0000\r
361 //                      CUtils::Log(_T("PBT_APMQUERYSUSPEND"));\r
362                         break;\r
363                 case PBT_APMQUERYSTANDBY:               // 0x0001\r
364 //                      CUtils::Log(_T("PBT_APMQUERYSTANDBY"));\r
365                         break;\r
366                 case PBT_APMQUERYSUSPENDFAILED: // 0x0002\r
367 //                      CUtils::Log(_T("PBT_APMQUERYSUSPENDFAILED"));\r
368                         break;\r
369                 case PBT_APMQUERYSTANDBYFAILED: // 0x0003\r
370 //                      CUtils::Log(_T("PBT_APMQUERYSTANDBYFAILED"));\r
371                         break;\r
372                 case PBT_APMSUSPEND:                    // 0x0004\r
373 //                      CUtils::Log(_T("PBT_APMSUSPEND"));\r
374                         break;\r
375                 case PBT_APMSTANDBY:                    // 0x0005\r
376 //                      CUtils::Log(_T("PBT_APMSTANDBY"));\r
377                         break;\r
378                 case PBT_APMRESUMECRITICAL:             // 0x0006\r
379 //                      CUtils::Log(_T("PBT_APMRESUMECRITICAL"));\r
380                         break;\r
381                 case PBT_APMRESUMESUSPEND:              // 0x0007\r
382 //                      CUtils::Log(_T("PBT_APMRESUMESUSPEND"));\r
383                         break;\r
384                 case PBT_APMRESUMESTANDBY:              // 0x0008\r
385 //                      CUtils::Log(_T("PBT_APMRESUMESTANDBY"));\r
386                         break;\r
387                 case PBT_APMBATTERYLOW:                 // 0x0009\r
388 //                      CUtils::Log(_T("PBT_APMBATTERYLOW"));\r
389                         break;\r
390                 case PBT_APMPOWERSTATUSCHANGE:  // 0x000A\r
391 //                      CUtils::Log(_T("PBT_APMPOWERSTATUSCHANGE"));\r
392                         break;\r
393                 case PBT_APMOEMEVENT:                   // 0x000B\r
394 //                      CUtils::Log(_T("PBT_APMOEMEVENT"));\r
395                         break;\r
396                 case PBT_APMRESUMEAUTOMATIC:    // 0x0012\r
397 //                      CUtils::Log(_T("PBT_APMRESUMEAUTOMATIC"));\r
398                         break;\r
399                 default:\r
400 //                      CUtils::Log(_T("PBT_OTHERS: %d"), wParam);\r
401                         break;\r
402                 }\r
403                 break;\r
404         case WM_IME_NOTIFY:                             // 0x0282\r
405 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_NOTIFY"));\r
406                 break;\r
407         default:\r
408 //              CUtils::Log(_T("CallWndProc: cwps.message = 0x%04X"), cwps.message);\r
409                 break;\r
410         }\r
411 }\r
412 \r
413 LRESULT CALLBACK CXkeymacsDll::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)\r
414 {\r
415 //      LogCallWndProcMessage(wParam, lParam);\r
416 \r
417         if (0 <= nCode) {\r
418                 CWPSTRUCT &cwps = *(CWPSTRUCT *)lParam;\r
419                 switch (cwps.message) {\r
420                 case WM_IME_STARTCOMPOSITION:\r
421                         InitKeyboardProc(TRUE);\r
422                         break;\r
423                 case WM_IME_ENDCOMPOSITION:\r
424                         InitKeyboardProc(FALSE);\r
425                         break;\r
426                 case WM_SETFOCUS:\r
427                         if (cwps.hwnd == GetForegroundWindow()) {\r
428                                 InitKeyboardProc(FALSE);\r
429                                 SetKeyboardHookFlag(m_bHook);\r
430                         }\r
431                         break;\r
432                 case WM_NCACTIVATE:\r
433                         if (cwps.wParam) {\r
434                                 if (cwps.hwnd == GetForegroundWindow()) {\r
435                                         InitKeyboardProc(FALSE);\r
436                                         SetKeyboardHookFlag(m_bHook);\r
437                                 }\r
438                         }\r
439                         break;\r
440                 case WM_POWERBROADCAST:\r
441                         switch (wParam) {\r
442                         case PBT_APMRESUMECRITICAL: // 0x0006\r
443                         case PBT_APMRESUMESUSPEND:  // 0x0007\r
444                         case PBT_APMRESUMESTANDBY:  // 0x0008\r
445                                 ReleaseHooks();\r
446                                 SetHooks();\r
447                                 break;\r
448                         default:\r
449                                 break;\r
450                         }\r
451                         break;\r
452                 default:\r
453                         break;\r
454                 }\r
455         }\r
456         return CallNextHookEx(m_hHookCallWnd, nCode, wParam, lParam);\r
457 }\r
458 \r
459 LRESULT CALLBACK CXkeymacsDll::CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)\r
460 {\r
461         if (0 <= nCode) {\r
462                 CWPRETSTRUCT &cwprets = *(CWPRETSTRUCT *)lParam;\r
463                 switch (cwprets.message) {\r
464                 case WM_SETTEXT:\r
465                         if (cwprets.hwnd == GetForegroundWindow()) {\r
466                                 InitKeyboardProc(FALSE);\r
467                         }\r
468                         break;\r
469                 case WM_SETCURSOR:\r
470                         DoSetCursor();\r
471                         break;\r
472                 default:\r
473                         break;\r
474                 }\r
475         }\r
476         return CallNextHookEx(m_hHookCallWndRet, nCode, wParam, lParam);\r
477 }\r
478 \r
479 LRESULT CALLBACK CXkeymacsDll::GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)\r
480 {\r
481         MSG &msg = (*(MSG *)lParam);\r
482 \r
483         switch (msg.message) {\r
484         case WM_IME_STARTCOMPOSITION:\r
485                 InitKeyboardProc(TRUE);\r
486                 break;\r
487         case WM_IME_ENDCOMPOSITION:\r
488                 InitKeyboardProc(FALSE);\r
489                 break;\r
490         }\r
491         return CallNextHookEx(m_hHookGetMessage, nCode, wParam, lParam);\r
492 }\r
493 \r
494 LRESULT CALLBACK CXkeymacsDll::ShellProc(int nCode, WPARAM wParam, LPARAM lParam)\r
495 {\r
496         switch (nCode) {\r
497         case HSHELL_WINDOWACTIVATED:\r
498         {\r
499                 TCHAR className[256];\r
500                 ::GetClassName((HWND)wParam, className, 255);\r
501                 if (!_tcsicmp(className, _T("ConsoleWindowClass"))) {\r
502                         InitKeyboardProc(FALSE);\r
503                         SetKeyboardHookFlag(m_bHook);\r
504                 }\r
505                 break;\r
506         }\r
507         default:\r
508                 break;\r
509         }\r
510         return CallNextHookEx( m_hHookShell, nCode, wParam, lParam );\r
511 }\r
512 \r
513 // return true if the key is down\r
514 BOOL CXkeymacsDll::IsDown(BYTE bVk, BOOL bPhysicalKey)\r
515 {\r
516         if (bPhysicalKey) {\r
517                 return GetKeyState(bVk) < 0;\r
518         } else {\r
519                 return GetAsyncKeyState(bVk) < 0;\r
520         }\r
521 }\r
522 \r
523 // Do keybd_event\r
524 void CXkeymacsDll::DoKeybd_event(BYTE bVk, DWORD dwFlags)\r
525 {\r
526         // Set KEYEVENTF_EXTENDEDKEY if needed\r
527         switch (bVk) {\r
528         case VK_CONTROL:\r
529                 if (m_bRightControl) {          // Right Ctrl\r
530                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
531                 }\r
532                 break;\r
533 \r
534         case VK_MENU:\r
535                 if (m_bRightAlt) {                      // Right Alt\r
536                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
537 //                      CUtils::Log("Right Alt %d", dwFlags);\r
538 //              } else {\r
539 //                      CUtils::Log("Left Alt %d", dwFlags);\r
540                 }\r
541                 break;\r
542 \r
543         case VK_SHIFT:\r
544                 if (m_bRightShift) {            // Right Shift\r
545                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
546                 }\r
547                 break;\r
548 \r
549         case VK_PAUSE:\r
550                 if (IsDown(VK_CONTROL)) {       // Break\r
551                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
552                 }\r
553                 break;\r
554 \r
555         case VK_INSERT:\r
556         case VK_DELETE:\r
557         case VK_HOME:\r
558         case VK_END:\r
559         case VK_NEXT:\r
560         case VK_PRIOR:\r
561         case VK_UP:\r
562         case VK_DOWN:\r
563         case VK_RIGHT:\r
564         case VK_LEFT:\r
565         case VK_NUMLOCK:\r
566         case VK_PRINT:\r
567                 dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
568                 break;\r
569 \r
570         default:\r
571                 break;\r
572         }\r
573 \r
574 //      CUtils::Log(_T("b: %x, %x, %x, %#x, %#x"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
575         keybd_event(bVk, 0, dwFlags, GetMessageExtraInfo());\r
576 //      CUtils::Log(_T("a: %x, %x, %x, %#x, %#x"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
577 }\r
578 \r
579 // the key is being depressed\r
580 void CXkeymacsDll::DepressKey(BYTE bVk, BOOL bOriginal) // bVk is virtual-key code, MSDN said\r
581 {\r
582         if (bOriginal) {\r
583 //              CUtils::Log(_T("i: %x, %d, %d, %d, %d, %d, %d, %d, %d"), bVk,\r
584 //                      IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),\r
585 //                      IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));\r
586 \r
587                 int nCommandType = NONE;\r
588                 if (IsDown(VK_CONTROL, FALSE)) {\r
589                         nCommandType |= CONTROL;\r
590                 }\r
591                 if (IsDown(VK_MENU, FALSE)) {\r
592                         nCommandType |= META;\r
593                 }\r
594                 Original(nCommandType, bVk, 1);\r
595         }\r
596 \r
597         DoKeybd_event(bVk, 0);\r
598 }\r
599 \r
600 // the key is being released\r
601 void CXkeymacsDll::ReleaseKey(BYTE bVk) // bVk is virtual-key code, MSDN said\r
602 {\r
603         DoKeybd_event(bVk, KEYEVENTF_KEYUP);\r
604 }\r
605 \r
606 // bVk down, bVk up\r
607 void CXkeymacsDll::Kdu(BYTE bVk, DWORD n, BOOL bOriginal)\r
608 {\r
609         while (n--) {\r
610                 DepressKey(bVk, bOriginal);\r
611                 ReleaseKey(bVk);\r
612         }\r
613 }\r
614 \r
615 void CXkeymacsDll::InitKeyboardProc(BOOL bImeComposition)\r
616 {\r
617         if (CUtils::IsFindDialog()) {\r
618                 static BOOL bImeCompositionOld = FALSE;\r
619                 if (!bImeComposition\r
620                  && bImeCompositionOld) {\r
621                         DepressKey(VK_END);\r
622                         ReleaseKey(VK_END);\r
623                 }\r
624                 bImeCompositionOld = bImeComposition;\r
625         }\r
626 \r
627         CUtils::SetApplicationName(bImeComposition);\r
628 \r
629         if (_tcsnicmp(m_szSpecialApp[m_nApplicationID], CUtils::GetApplicationName(), 0xF) || !IsMatchWindowText(m_szWindowText[m_nApplicationID])) {   // PROCESSENTRY32 has only 0xF bytes of Name\r
630                 m_nApplicationID = -1;\r
631 \r
632                 for (int nApplicationID = 0; nApplicationID < MAX_APP; ++nApplicationID) {\r
633                         if (!_tcsnicmp(m_szSpecialApp[nApplicationID], CUtils::GetApplicationName(), 0xF) && IsMatchWindowText(m_szWindowText[nApplicationID])) {\r
634 \r
635                                 if (m_nApplicationID < 0\r
636                                  || CUtils::GetWindowTextType(m_szWindowText[m_nApplicationID]) < CUtils::GetWindowTextType(m_szWindowText[nApplicationID])\r
637                                  || CUtils::GetWindowTextType(m_szWindowText[m_nApplicationID]) == CUtils::GetWindowTextType(m_szWindowText[nApplicationID])\r
638                                  && _tcscmp(m_szWindowText[m_nApplicationID], m_szWindowText[nApplicationID]) <= 0) {\r
639                                         m_nApplicationID = nApplicationID;\r
640                                 }\r
641                         }\r
642                 }\r
643 \r
644                 if (m_nApplicationID < 0) {\r
645                         for (int nApplicationID = 0; nApplicationID < MAX_APP; ++nApplicationID) {\r
646                                 if (!_tcsicmp(m_szSpecialApp[nApplicationID], _T("Default"))) {\r
647                                         m_nApplicationID = nApplicationID;\r
648                                         break;\r
649                                 }\r
650                         }\r
651 \r
652                         if (m_nApplicationID < 0) {\r
653                                 m_nApplicationID = 0;\r
654                         }\r
655                 }\r
656         }\r
657 \r
658         if (m_nSettingStyle[m_nApplicationID] != SETTING_DISABLE\r
659          && (_tcsicmp(m_szSpecialApp[m_nApplicationID], _T("Default")) || !CUtils::IsDefaultIgnoreApplication())\r
660          && !bImeComposition\r
661          && CUtils::IsDialog()) {\r
662                 // Use Dialog Setting\r
663                 if (m_bUseDialogSetting[m_nApplicationID]) {\r
664                         int nOriginalApplicationID = m_nApplicationID;\r
665                         for (m_nApplicationID = 0; m_nApplicationID < MAX_APP; ++m_nApplicationID) {\r
666                                 if (!_tcsicmp(m_szSpecialApp[m_nApplicationID], _T("Dialog"))) {\r
667                                         break;\r
668                                 }\r
669                         }\r
670                         if (m_nApplicationID == MAX_APP) {\r
671                                 m_nApplicationID = nOriginalApplicationID;\r
672                         }\r
673                 }\r
674         }\r
675 \r
676         ModifyShell_NotifyIcon(CX_ICON, FALSE);\r
677         ModifyShell_NotifyIcon(MX_ICON, FALSE);\r
678         ModifyShell_NotifyIcon(META_ICON, FALSE);\r
679         CCommands::SetMark(FALSE);\r
680         CCommands::SetTemporarilyDisableXKeymacs(FALSE);\r
681         CCommands::Reset();\r
682 }\r
683 \r
684 // emulate emacs        // cf virtual-key code\r
685 LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)\r
686 {\r
687         ASSERT(0 <= wParam && wParam <= UCHAR_MAX);\r
688 \r
689         int nCommandType = NONE;\r
690         BYTE nKey = (BYTE)wParam;\r
691 \r
692         static BOOL bLocked = FALSE;\r
693         static const BYTE RECURSIVE_KEY = 0x07;\r
694         static int (*fCommand)() = NULL;\r
695         static BYTE nOneShotModifier[MAX_KEY] = {'\0'};\r
696         static BOOL bCherryOneShotModifier = FALSE;\r
697 \r
698 //      CUtils::Log(_T("nCode = %#x, nKey = %#x, lParam = %#x"), nCode, nKey, lParam);\r
699 \r
700         if (!m_bEnableKeyboardHook)\r
701                 return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam);\r
702 \r
703         if (nCode < 0 || nCode == HC_NOREMOVE) {\r
704                 goto DO_NOTHING;\r
705         }\r
706 \r
707         if (nKey == RECURSIVE_KEY) {\r
708                 if (lParam & BEING_RELEASED) {\r
709                         goto HOOK_RECURSIVE_KEY;\r
710                 } else {\r
711                         goto RECURSIVE_COMMAND;\r
712                 }\r
713         }\r
714 \r
715         {\r
716                 static BOOL bShift = FALSE;\r
717                 if (IsDepressedShiftKeyOnly(nKey)) {\r
718                         if (lParam & BEING_RELEASED) {\r
719                                 if (bShift) {\r
720                                         CCommands::SetMark(FALSE);\r
721                                 }\r
722                         } else {\r
723                                 bShift = TRUE;\r
724                         }\r
725                 } else {\r
726                         bShift = FALSE;\r
727                 }\r
728         }\r
729 \r
730         if (CUtils::IsNT()) {\r
731                 switch (nKey) {\r
732                 case VK_CONTROL:\r
733                         if (lParam & EXTENDED_KEY) {\r
734                                 nKey = VK_RCONTROL;\r
735                         } else {\r
736                                 nKey = VK_LCONTROL;\r
737                         }\r
738                         break;\r
739                 case VK_MENU:\r
740                         if (lParam & EXTENDED_KEY) {\r
741                                 nKey = VK_RMENU;\r
742                         } else {\r
743                                 nKey = VK_LMENU;\r
744                         }\r
745                         break;\r
746                 case VK_SHIFT:\r
747                         if (lParam & EXTENDED_KEY) {\r
748                                 nKey = VK_RSHIFT;\r
749                         } else {\r
750                                 nKey = VK_LSHIFT;\r
751                         }\r
752                         break;\r
753                 default:\r
754                         break;\r
755                 }\r
756         }\r
757 \r
758         if (lParam & BEING_RELEASED) {\r
759                 if (nKey == VK_MENU\r
760                  || nKey == VK_LWIN\r
761                  || nKey == VK_RWIN\r
762                  || nKey == VK_APPS\r
763                  || nKey == VK_LMENU\r
764                  || nKey == VK_RMENU) {\r
765                         for (int i = 0; i < MAX_COMMAND_TYPE; ++i) {\r
766                                 if (Commands[m_nCommandID[m_nApplicationID][i][nKey]].fCommand\r
767                                  && (Commands[m_nCommandID[m_nApplicationID][i][nKey]].fCommand != CCommands::MetaAlt\r
768                                   || nKey != VK_MENU && nKey != VK_LMENU && nKey != VK_RMENU)) {\r
769                                         goto HOOK;\r
770                                 }\r
771                         }\r
772                 }\r
773 \r
774                 if (nOneShotModifier[nKey]) {\r
775                         ReleaseKey(nOneShotModifier[nKey]);\r
776                         nOneShotModifier[nKey] = 0;\r
777 \r
778                         if (bCherryOneShotModifier) {\r
779                                 bCherryOneShotModifier = FALSE;\r
780                                 Kdu(nKey);\r
781                         }\r
782                 }\r
783 \r
784                 goto DO_NOTHING;\r
785         }\r
786 \r
787         if (m_nSettingStyle[m_nApplicationID] == SETTING_DISABLE) {\r
788                 goto DO_NOTHING;\r
789         }\r
790 \r
791         // Do Nothing for Meadow, Mule for Win32, ... if those use default setting.\r
792         if (!_tcsicmp(m_szSpecialApp[m_nApplicationID], _T("Default"))\r
793          && CUtils::IsDefaultIgnoreApplication()) {\r
794                 goto DO_NOTHING;\r
795         }\r
796 \r
797         switch (IsPassThrough(nKey)) {\r
798         case GOTO_DO_NOTHING:\r
799                 goto DO_NOTHING;\r
800         case GOTO_HOOK:\r
801                 goto HOOK;\r
802         case CONTINUE:\r
803                 break;\r
804         default:\r
805                 ASSERT(0);\r
806                 break;\r
807         }\r
808 \r
809         // set command type\r
810         {\r
811                 nCommandType = NONE;\r
812                 if (IsDown(VK_SHIFT, FALSE)) {\r
813                         nCommandType |= SHIFT;\r
814                 }\r
815                 if (IsControl()) {\r
816                         nCommandType |= CONTROL;\r
817                 }\r
818                 if (IsMeta()) {\r
819                         nCommandType |= META;\r
820                 }\r
821                 if (CCommands::bC_x()) {\r
822                         nCommandType |= CONTROLX;\r
823                 }\r
824 \r
825                 // Ignore undefined C-x ?\r
826                 if (nCommandType & CONTROLX) {\r
827                         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == NULL\r
828                          && m_nFunctionID[m_nApplicationID][nCommandType][nKey] < 0) {\r
829                                 if (m_bIgnoreUndefinedC_x[m_nApplicationID]) {\r
830                                         CCommands::Reset(GOTO_HOOK);\r
831                                         goto HOOK;\r
832                                 }\r
833                                 nCommandType &= ~CONTROLX;\r
834                         }\r
835                 }\r
836 \r
837                 // Ignore undefined Meta Ctrl+?\r
838                 if (CCommands::bM_() && (nCommandType & CONTROL)) {\r
839                         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == NULL\r
840                          && m_nFunctionID[m_nApplicationID][nCommandType][nKey] < 0) {\r
841                                 if (m_bIgnoreUndefinedMetaCtrl[m_nApplicationID]) {\r
842                                         if (Original(CONTROL, nKey)) {\r
843                                                 Original(CONTROL, nKey, -1);\r
844                                                 goto DO_NOTHING;\r
845                                         }\r
846                                         CCommands::Reset(GOTO_HOOK);\r
847                                         goto HOOK;\r
848                                 }\r
849                                 nCommandType &= ~META;\r
850                         }\r
851                 }\r
852         }\r
853 \r
854         {\r
855 //              CUtils::Log(_T("o: %x, %d, %d, %d, %d, %d, %d, %d, %d"), (BYTE)wParam,\r
856 //                      IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),\r
857 //                      IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));\r
858 \r
859                 BYTE nKey = (BYTE)wParam; // VK_CONTROL is needed instead of VK_RCONTROL and VK_LCONTROL in this block just for Original()\r
860                 int nVirtualCommandType = NONE;\r
861                 if (IsDown(VK_CONTROL) && nKey != VK_CONTROL) {\r
862                         nVirtualCommandType |= CONTROL;\r
863                 }\r
864                 if (IsDown(VK_MENU) && nKey != VK_MENU) {\r
865                         nVirtualCommandType |= META;\r
866                 }\r
867                 if (Original(nVirtualCommandType, nKey)) {\r
868                         Original(nVirtualCommandType, nKey, -1);\r
869                         goto DO_NOTHING;\r
870                 }\r
871         }\r
872 \r
873         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EnableOrDisableXKeymacs) {\r
874                 SetKeyboardHookFlag(!m_bHook);\r
875                 goto HOOK;\r
876         }\r
877         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EnableXKeymacs) {\r
878                 if (!m_bHook) {\r
879                         SetKeyboardHookFlag(!m_bHook);\r
880                 }\r
881                 goto HOOK;\r
882         }\r
883         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DisableXKeymacs) {\r
884                 if (m_bHook) {\r
885                         SetKeyboardHookFlag(!m_bHook);\r
886                 }\r
887                 goto HOOK;\r
888         }\r
889         if (!m_bHook) {\r
890                 goto DO_NOTHING;\r
891         }\r
892 \r
893         if (CCommands::bM_x()) {\r
894                 static unsigned int index = 0;\r
895                 static TCHAR szPath[MAX_PATH] = {'\0'};\r
896 \r
897                 if (lParam & BEING_RELEASED) {\r
898                         // ignore\r
899                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::BackwardChar) {\r
900                         if (index) {\r
901                                 --index;\r
902                         }\r
903                         goto HOOKX;\r
904                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::BeginningOfLine) {\r
905                         index = 0;\r
906                         goto HOOKX;\r
907                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DeleteBackwardChar) {\r
908                         if (index) {\r
909                                 --index;\r
910                                 memmove(&szPath[index], &szPath[index + 1], _tcslen(szPath) - index);\r
911                                 ModifyM_xTip(szPath);\r
912                         }\r
913                         goto HOOKX;\r
914                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DeleteChar) {\r
915                         if (index < _tcslen(szPath)) {\r
916                                 memmove(&szPath[index], &szPath[index + 1], _tcslen(szPath) - index);\r
917                                 ModifyM_xTip(szPath);\r
918                         }\r
919                         goto HOOKX;\r
920                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EndOfLine) {\r
921                         index = _tcslen(szPath);\r
922                         goto HOOKX;\r
923                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::ForwardChar) {\r
924                         if (index < _tcslen(szPath)) {\r
925                                 ++index;\r
926                         }\r
927                         goto HOOKX;\r
928                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::KeyboardQuit) {\r
929                         CCommands::bM_x(FALSE);\r
930                         index = 0;\r
931                         memset(szPath, 0, sizeof(szPath));\r
932                         goto HOOK;\r
933                 } else if (nKey == VK_RETURN\r
934                                 || Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::Newline) {\r
935                         InvokeM_x(szPath);\r
936 \r
937                         CCommands::bM_x(FALSE);\r
938                         index = 0;\r
939                         memset(szPath, 0, sizeof(szPath));\r
940                         goto HOOK;\r
941                 } else if (index < MAX_PATH - 1) {\r
942                         const BOOL bIsShiftDown = CXkeymacsDll::IsDown(VK_SHIFT);\r
943                         for (TCHAR nAscii = 1; nAscii != 0; ++nAscii) { // repeat until overflow\r
944                                 if (nKey != 0 && a2v(nAscii) == nKey && bIsShiftDown == IsShift(nAscii)) {\r
945 //                                      CUtils::Log("M-x: %#X (%c), %#X (%c)", nKey, nKey, nAscii, nAscii);\r
946                                         if (index < _tcslen(szPath)) {\r
947                                                 memmove(&szPath[index + 1], &szPath[index], __min(_tcslen(szPath) - index, MAX_PATH - (index + 1) - 1));\r
948                                         }\r
949                                         szPath[index++] = nAscii;\r
950 //                                      CUtils::Log("M-x: %c(%#04x)", nAscii, nAscii);\r
951                                         ModifyM_xTip(szPath);\r
952                                         goto HOOKX;\r
953                                 }\r
954                         }\r
955                 }\r
956         }\r
957 \r
958         if (CCommands::bC_u()) {\r
959                 if ((nCommandType == NONE) && ('0' <= nKey) && (nKey <= '9')) {\r
960                         CCommands::NumericArgument(nKey - '0');\r
961                         goto HOOK0_9;\r
962                 }\r
963                 if ((nCommandType == NONE) && (nKey == 0xBD)) {\r
964                         CCommands::NumericArgumentMinus();\r
965                         goto HOOK0_9;\r
966                 }\r
967         }\r
968 \r
969         if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~CONTROL][nKey]].fCommand == CCommands::OneShotModifierCtrl) {\r
970                 nOneShotModifier[nKey] = VK_LCONTROL;\r
971                 DepressKey(nOneShotModifier[nKey]);\r
972                 bCherryOneShotModifier = TRUE;\r
973                 goto HOOK;\r
974         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierCtrlRepeat) {\r
975                 nOneShotModifier[nKey] = VK_LCONTROL;\r
976                 DepressKey(nOneShotModifier[nKey]);\r
977                 bCherryOneShotModifier = TRUE;\r
978                 goto HOOK;\r
979         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~CONTROL][nKey]].fCommand == CCommands::OneShotModifierCtrlRepeat) {\r
980                 ReleaseKey(nOneShotModifier[nKey]);\r
981                 bCherryOneShotModifier = FALSE;\r
982                 Kdu(nKey);\r
983                 goto HOOK;\r
984         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~META][nKey]].fCommand == CCommands::OneShotModifierAlt) {\r
985                 nOneShotModifier[nKey] = VK_LMENU;\r
986                 DepressKey(nOneShotModifier[nKey]);\r
987                 bCherryOneShotModifier = TRUE;\r
988                 goto HOOK;\r
989         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierAltRepeat) {\r
990                 nOneShotModifier[nKey] = VK_LMENU;\r
991                 DepressKey(nOneShotModifier[nKey]);\r
992                 bCherryOneShotModifier = TRUE;\r
993                 goto HOOK;\r
994         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~META][nKey]].fCommand == CCommands::OneShotModifierAltRepeat) {\r
995                 ReleaseKey(nOneShotModifier[nKey]);\r
996                 bCherryOneShotModifier = FALSE;\r
997                 Kdu(nKey);\r
998                 goto HOOK;\r
999         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~SHIFT][nKey]].fCommand == CCommands::OneShotModifierShift) {\r
1000                 nOneShotModifier[nKey] = VK_SHIFT;\r
1001                 DepressKey(nOneShotModifier[nKey]);\r
1002                 bCherryOneShotModifier = TRUE;\r
1003                 goto HOOK;\r
1004         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierShiftRepeat) {\r
1005                 nOneShotModifier[nKey] = VK_SHIFT;\r
1006                 DepressKey(nOneShotModifier[nKey]);\r
1007                 bCherryOneShotModifier = TRUE;\r
1008                 goto HOOK;\r
1009         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~SHIFT][nKey]].fCommand == CCommands::OneShotModifierShiftRepeat) {\r
1010                 ReleaseKey(nOneShotModifier[nKey]);\r
1011                 bCherryOneShotModifier = FALSE;\r
1012                 Kdu(nKey);\r
1013                 goto HOOK;\r
1014         } else {\r
1015                 for (int i = 0; i < MAX_KEY; ++i) {\r
1016                         if (nOneShotModifier[i] == nKey) {\r
1017                                 break;\r
1018                         }\r
1019                 }\r
1020                 if (i == MAX_KEY) {\r
1021                         bCherryOneShotModifier = FALSE;\r
1022                 }\r
1023         }\r
1024 \r
1025         if (0 <= m_nFunctionID[m_nApplicationID][nCommandType][nKey]\r
1026          && m_nFunctionID[m_nApplicationID][nCommandType][nKey] < MAX_FUNCTION\r
1027          && _tcslen(m_szFunctionDefinition[m_nFunctionID[m_nApplicationID][nCommandType][nKey]])) {\r
1028                 CallFunction(m_nFunctionID[m_nApplicationID][nCommandType][nKey]);\r
1029                 CCommands::Reset(GOTO_HOOK);\r
1030                 goto HOOK;\r
1031         }\r
1032 \r
1033         if (!Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand) {\r
1034                 if (nKey == VK_CONTROL\r
1035                  || nKey == VK_LCONTROL\r
1036                  || nKey == VK_RCONTROL\r
1037                  || nKey == VK_MENU\r
1038                  || nKey == VK_LMENU\r
1039                  || nKey == VK_RMENU\r
1040                  || nKey == VK_SHIFT\r
1041                  || nKey == VK_LSHIFT\r
1042                  || nKey == VK_RSHIFT) {\r
1043                         goto DO_NOTHING;\r
1044                 }\r
1045 \r
1046                 if (!(nCommandType & SHIFT)) {\r
1047                         if (CCommands::IsSetMark()) {\r
1048                                 if (CCommands::MoveCaret(nKey, nCommandType & CONTROL) != CONTINUE) {\r
1049                                         CCommands::ClearNumericArgument();\r
1050                                         goto HOOK;\r
1051                                 }\r
1052                                 CCommands::SetMark(FALSE);\r
1053                         }\r
1054                 }\r
1055 \r
1056                 if (1 < CCommands::GetNumericArgument()) {\r
1057                         Kdu(nKey, CCommands::GetNumericArgument());\r
1058                         CCommands::ClearNumericArgument();\r
1059                         goto HOOK;\r
1060                 }\r
1061 \r
1062                 goto DO_NOTHING;\r
1063         }\r
1064 \r
1065         if (CCommands::IsTemporarilyDisableXKeymacs()\r
1066          && Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand != CCommands::KeyboardQuit) {\r
1067                 CCommands::SetTemporarilyDisableXKeymacs(FALSE);\r
1068                 goto DO_NOTHING;\r
1069         }\r
1070 \r
1071         if (m_bAtIbeamCursorOnly[m_nApplicationID][nCommandType][nKey]) {\r
1072                 CURSORINFO cursorinfo = { sizeof(cursorinfo) };\r
1073                 if (GetCursorInfo(&cursorinfo) && cursorinfo.flags && cursorinfo.hCursor != LoadCursor(NULL, IDC_IBEAM)) {\r
1074                         goto DO_NOTHING;\r
1075                 }\r
1076         }\r
1077 \r
1078         m_bRightControl = IsDown(VK_RCONTROL);\r
1079         m_bRightAlt             = IsDown(VK_RMENU);\r
1080         m_bRightShift   = IsDown(VK_RSHIFT);\r
1081 \r
1082         if (!bLocked) {\r
1083                 bLocked = TRUE;\r
1084                 fCommand = Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand;\r
1085 RECURSIVE_COMMAND:\r
1086                 switch (fCommand()) {\r
1087                 case GOTO_DO_NOTHING:\r
1088                         bLocked = FALSE;\r
1089                         goto DO_NOTHING;\r
1090                 case GOTO_HOOK:\r
1091                         bLocked = FALSE;\r
1092                         goto HOOK;\r
1093                 case GOTO_RECURSIVE:\r
1094                         goto RECURSIVE;\r
1095                 case GOTO_HOOKX:\r
1096                         bLocked = FALSE;\r
1097                         goto HOOKX;\r
1098                 case GOTO_HOOK0_9:\r
1099                         bLocked = FALSE;\r
1100                         goto HOOK0_9;\r
1101                 default:\r
1102                         ASSERT(0);\r
1103                         bLocked = FALSE;\r
1104                         goto DO_NOTHING;\r
1105                 }\r
1106         } else {\r
1107                 goto HOOK_RECURSIVE_KEY;\r
1108         }\r
1109 \r
1110 DO_NOTHING:\r
1111         ModifyShell_NotifyIcon(SHIFT_ICON, IsDown(VK_SHIFT));\r
1112         ModifyShell_NotifyIcon(CTRL_ICON, IsControl());\r
1113         ModifyShell_NotifyIcon(ALT_ICON, IsDown(VK_MENU));\r
1114 \r
1115         {\r
1116                 static BOOL bDefiningMacro = FALSE;\r
1117                 if (m_bDefiningMacro) {\r
1118                         static BOOL bDown[MAX_KEY] = {'\0'};\r
1119 \r
1120                         if (!bDefiningMacro) {\r
1121                                 while (m_Macro.GetHeadPosition()) {\r
1122                                         void *p = m_Macro.GetAt(m_Macro.GetHeadPosition());\r
1123                                         m_Macro.RemoveHead();\r
1124                                         delete p;\r
1125                                         p = NULL;\r
1126                                 }\r
1127                                 memset(bDown, 0, sizeof(bDown));\r
1128                         }\r
1129 \r
1130                         if ((!(lParam & BEING_RELEASED)) || bDown[wParam]) {\r
1131                                 try {\r
1132                                         KbdMacro_t *pKbdMacro = new KbdMacro;\r
1133                                         if (pKbdMacro) {\r
1134                                                 pKbdMacro->nCode = nCode;\r
1135                                                 pKbdMacro->wParam = wParam;\r
1136                                                 pKbdMacro->lParam = lParam;\r
1137                                                 pKbdMacro->bOriginal = TRUE;\r
1138                                                 m_Macro.AddTail((CObject *)pKbdMacro);\r
1139                                         }\r
1140                                 }\r
1141                                 catch (CMemoryException* e) {\r
1142                                         e->Delete();\r
1143 //                                      CUtils::Log("KeyboardProc: 'new' threw an exception");\r
1144                                 }\r
1145                                 if (!(lParam & BEING_RELEASED)) {\r
1146                                         bDown[wParam] = TRUE;\r
1147                                 }\r
1148                         }\r
1149                 }\r
1150                 bDefiningMacro = m_bDefiningMacro;\r
1151         }\r
1152 \r
1153         return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam);\r
1154 \r
1155 RECURSIVE:\r
1156         Kdu(RECURSIVE_KEY, 1, FALSE);\r
1157         ModifyShell_NotifyIcon(SHIFT_ICON, IsDown(VK_SHIFT));\r
1158         ModifyShell_NotifyIcon(CTRL_ICON, IsControl());\r
1159         ModifyShell_NotifyIcon(ALT_ICON, IsDown(VK_MENU));\r
1160         return TRUE;\r
1161 \r
1162 HOOK:\r
1163         CCommands::SetLastCommand(fCommand);\r
1164 HOOK0_9:\r
1165 HOOKX:\r
1166         ModifyShell_NotifyIcon(SHIFT_ICON, IsDown(VK_SHIFT));\r
1167         ModifyShell_NotifyIcon(CTRL_ICON, IsControl());\r
1168         ModifyShell_NotifyIcon(ALT_ICON, IsDown(VK_MENU));\r
1169 HOOK_RECURSIVE_KEY:\r
1170         return TRUE;\r
1171 }\r
1172 \r
1173 //////////////////////////////////////////////////////////////////////\r
1174 // CXkeymacsData Class\r
1175 //////////////////////////////////////////////////////////////////////\r
1176 \r
1177 //////////////////////////////////////////////////////////////////////\r
1178 // Construction/Destruction\r
1179 //////////////////////////////////////////////////////////////////////\r
1180 \r
1181 CXkeymacsData::CXkeymacsData()\r
1182 {\r
1183         ClearAll();\r
1184 }\r
1185 \r
1186 CXkeymacsData::~CXkeymacsData()\r
1187 {\r
1188 \r
1189 }\r
1190 \r
1191 // set application name\r
1192 void CXkeymacsData::SetApplicationName(LPCTSTR lpszApplicationName)\r
1193 {\r
1194         m_strApplicationName.Format(lpszApplicationName);\r
1195 }\r
1196 \r
1197 // return application name\r
1198 CString CXkeymacsData::GetApplicationName()\r
1199 {\r
1200         return m_strApplicationName;\r
1201 }\r
1202 \r
1203 // set hook or not\r
1204 void CXkeymacsData::SetCommandID(int nCommandType, int nKey, int nCommandID)\r
1205 {\r
1206         ASSERT(0 <= nCommandType        || nCommandType < MAX_COMMAND_TYPE);\r
1207         ASSERT(0 <= nKey                        || nKey                 < MAX_KEY);\r
1208 \r
1209         m_nCommandID[nCommandType][nKey] = nCommandID;\r
1210 }\r
1211 \r
1212 // return hook or not\r
1213 int CXkeymacsData::GetCommandID(int nCommandType, int nKey)\r
1214 {\r
1215         ASSERT(0 <= nCommandType        || nCommandType < MAX_COMMAND_TYPE);\r
1216         ASSERT(0 <= nKey                        || nKey                 < MAX_KEY);\r
1217 \r
1218         return m_nCommandID[nCommandType][nKey];\r
1219 }\r
1220 \r
1221 // set hook at ibeam cursor only or not\r
1222 void CXkeymacsData::SetAtIbeamCursorOnly(int nCommandType, int nKey, BOOL bAtIbeamCursorOnly)\r
1223 {\r
1224         ASSERT(0 <= nCommandType        || nCommandType < MAX_COMMAND_TYPE);\r
1225         ASSERT(0 <= nKey                        || nKey                 < MAX_KEY);\r
1226 \r
1227         m_bAtIbeamCursorOnly[nCommandType][nKey] = bAtIbeamCursorOnly;\r
1228 }\r
1229 \r
1230 // get hook at ibeam cursor only or not\r
1231 BOOL CXkeymacsData::GetAtIbeamCursorOnly(int nCommandType, int nKey)\r
1232 {\r
1233         ASSERT(0 <= nCommandType        || nCommandType < MAX_COMMAND_TYPE);\r
1234         ASSERT(0 <= nKey                        || nKey                 < MAX_KEY);\r
1235 \r
1236         return m_bAtIbeamCursorOnly[nCommandType][nKey];\r
1237 }\r
1238 \r
1239 // clear all data\r
1240 void CXkeymacsData::ClearAll()\r
1241 {\r
1242         ZeroMemory(m_nCommandID, sizeof(m_nCommandID));\r
1243         ZeroMemory(m_bAtIbeamCursorOnly, sizeof(m_bAtIbeamCursorOnly));\r
1244         m_strApplicationName.Empty();\r
1245 }\r
1246 \r
1247 void CXkeymacsDll::SetApplicationName(int nApplicationID, CString szApplicationName)\r
1248 {\r
1249         ZeroMemory(m_szSpecialApp[nApplicationID], sizeof(m_szSpecialApp[nApplicationID]));\r
1250         _tcsncpy(m_szSpecialApp[nApplicationID], szApplicationName, sizeof(m_szSpecialApp[nApplicationID]));\r
1251 }\r
1252 \r
1253 void CXkeymacsDll::SetWindowText(int nApplicationID, CString szWindowText)\r
1254 {\r
1255         ZeroMemory(m_szWindowText[nApplicationID], sizeof(m_szWindowText[nApplicationID]));\r
1256         _tcsncpy(m_szWindowText[nApplicationID], szWindowText, sizeof(m_szWindowText[nApplicationID]));\r
1257 }\r
1258 \r
1259 void CXkeymacsDll::SetCommandID(int nApplicationID, int nCommandType, int nKey, int nCommandID)\r
1260 {\r
1261         m_nCommandID[nApplicationID][nCommandType][nKey] = nCommandID;\r
1262 }\r
1263 \r
1264 void CXkeymacsDll::SetAtIbeamCursorOnly(int nApplicationID, int nCommandType, int nKey, BOOL bAtIbeamCursorOnly)\r
1265 {\r
1266         m_bAtIbeamCursorOnly[nApplicationID][nCommandType][nKey] = bAtIbeamCursorOnly;\r
1267 }\r
1268 \r
1269 void CXkeymacsDll::SetKillRingMax(int nApplicationID, int nKillRingMax)\r
1270 {\r
1271         m_nKillRingMax[nApplicationID] = nKillRingMax;\r
1272 }\r
1273 \r
1274 void CXkeymacsDll::SetUseDialogSetting(int nApplicationID, BOOL bUseDialogSetting)\r
1275 {\r
1276         m_bUseDialogSetting[nApplicationID] = bUseDialogSetting;\r
1277 }\r
1278 \r
1279 // Clear data of nApplicationID\r
1280 void CXkeymacsDll::Clear(int nApplicationID)\r
1281 {\r
1282         if (0 <= nApplicationID && nApplicationID < MAX_APP) {\r
1283                 ZeroMemory(m_szSpecialApp[nApplicationID], sizeof(m_szSpecialApp[nApplicationID]));\r
1284                 ZeroMemory(m_nCommandID[nApplicationID], sizeof(m_nCommandID[nApplicationID]));\r
1285                 ZeroMemory(m_bAtIbeamCursorOnly[nApplicationID], sizeof(m_bAtIbeamCursorOnly[nApplicationID]));\r
1286                 m_nKillRingMax[nApplicationID] = 0;\r
1287                 m_bUseDialogSetting[nApplicationID] = FALSE;\r
1288                 m_nSettingStyle[nApplicationID] = 0;\r
1289         } else {\r
1290                 ASSERT(0);\r
1291         }\r
1292 }\r
1293 \r
1294 void CXkeymacsData::SetApplicationTitle(LPCTSTR lpszApplicationTitle)\r
1295 {\r
1296         m_strApplicationTitle.Format(lpszApplicationTitle);\r
1297 \r
1298         // delete white space at the end of the application title.\r
1299         while (!m_strApplicationTitle.IsEmpty()\r
1300                 && _istspace(m_strApplicationTitle.GetAt(m_strApplicationTitle.GetLength() - 1))) {\r
1301                 m_strApplicationTitle.Delete(m_strApplicationTitle.GetLength() - 1);\r
1302         }\r
1303 }\r
1304 \r
1305 CString CXkeymacsData::GetApplicationTitle()\r
1306 {\r
1307         return m_strApplicationTitle;\r
1308 }\r
1309 \r
1310 void CXkeymacsData::SetKillRingMax(int nKillRingMax)\r
1311 {\r
1312         m_nKillRingMax = nKillRingMax;\r
1313 }\r
1314 \r
1315 int CXkeymacsData::GetKillRingMax()\r
1316 {\r
1317         return m_nKillRingMax;\r
1318 }\r
1319 \r
1320 BOOL CXkeymacsDll::IsValidKey(BYTE bVk)\r
1321 {\r
1322         if (bVk == 0xf0) {      // 0xf0: Eisu key. GetAsyncKeyState returns the wrong state of Eisu key.\r
1323                 return FALSE;\r
1324         }\r
1325 \r
1326         if (CUtils::IsNT()) {\r
1327                 switch (bVk) {\r
1328                 case VK_CONTROL:\r
1329                 case VK_MENU:\r
1330                 case VK_SHIFT:\r
1331                         return FALSE;\r
1332                 default:\r
1333                         break;\r
1334                 }\r
1335         }\r
1336 \r
1337         return TRUE;\r
1338 }\r
1339 \r
1340 BOOL CXkeymacsDll::IsDepressedModifier(int (__cdecl *Modifier)(void), BOOL bPhysicalKey)\r
1341 {\r
1342         BYTE bVk = 0;\r
1343         do {\r
1344                 if (IsValidKey(bVk)\r
1345                  && IsDown(bVk, bPhysicalKey)\r
1346                  && Commands[m_nCommandID[m_nApplicationID][NONE][bVk]].fCommand == Modifier) {\r
1347                         return TRUE;\r
1348                 }\r
1349         } while (++bVk);\r
1350         return FALSE;\r
1351 }\r
1352 \r
1353 BOOL CXkeymacsDll::IsDepressedShiftKeyOnly(BYTE nKey)\r
1354 {\r
1355         if (nKey != VK_SHIFT\r
1356          && nKey != VK_LSHIFT\r
1357          && nKey != VK_RSHIFT) {\r
1358                 return FALSE;\r
1359         }\r
1360 \r
1361         BYTE bVk = 0;\r
1362         do {\r
1363                 if (bVk == VK_SHIFT\r
1364                  || bVk == VK_LSHIFT\r
1365                  || bVk == VK_RSHIFT) {\r
1366                         continue;\r
1367                 }\r
1368 \r
1369                 if (IsDown(bVk)) {\r
1370                         return FALSE;\r
1371                 }\r
1372         } while (++bVk);\r
1373         return TRUE;\r
1374 }\r
1375 \r
1376 BOOL CXkeymacsDll::IsControl()\r
1377 {\r
1378         return CCommands::bC_() || IsDepressedModifier(CCommands::C_, FALSE);\r
1379 }\r
1380 \r
1381 BOOL CXkeymacsDll::IsMeta()\r
1382 {\r
1383         return CCommands::bM_() || IsDepressedModifier(CCommands::MetaAlt, FALSE);\r
1384 }\r
1385 \r
1386 void CXkeymacsDll::AddKillRing(BOOL bNewData)\r
1387 {\r
1388         if (m_nKillRingMax[m_nApplicationID] == 0) {\r
1389                 return;\r
1390         }\r
1391 \r
1392         CClipboardSnap *pSnap = new CClipboardSnap;\r
1393         if( !pSnap ) return;\r
1394 \r
1395         BOOL bCapture = pSnap->Capture();\r
1396         bCapture = pSnap->Capture();    // for "office drawing shape format". Can CClipboardSnap care this problem?\r
1397 \r
1398         if( bCapture ) {\r
1399                 if (bNewData) {\r
1400                         m_oKillRing.AddHead(pSnap);\r
1401                 } else {\r
1402                         if (m_oKillRing.IsEmpty()) {\r
1403                                 m_oKillRing.AddHead(pSnap);\r
1404                         } else {\r
1405                                 for (CClipboardSnap *pParent = m_oKillRing.GetHead(); pParent->GetNext(); pParent = pParent->GetNext()) {\r
1406                                         ;\r
1407                                 }\r
1408                                 pParent->SetNext(pSnap);\r
1409                         }\r
1410                 }\r
1411         } else {\r
1412                 delete pSnap;\r
1413                 pSnap = NULL;\r
1414         }\r
1415 \r
1416         m_nKillRing = 0;\r
1417 \r
1418         if (m_nKillRingMax[m_nApplicationID] < m_oKillRing.GetCount()) {\r
1419                 CClipboardSnap *pSnap = m_oKillRing.GetTail();\r
1420                 delete pSnap;\r
1421                 pSnap = NULL;\r
1422                 m_oKillRing.RemoveTail();\r
1423         }\r
1424 }\r
1425 \r
1426 // Return TRUE if there is another data\r
1427 // Return FALSE if there is no more data\r
1428 CClipboardSnap* CXkeymacsDll::GetKillRing(CClipboardSnap* pSnap, BOOL bForce)\r
1429 {\r
1430         if (m_nKillRingMax[m_nApplicationID] == 0) {\r
1431                 return NULL;\r
1432         }\r
1433 \r
1434         if (m_oKillRing.IsEmpty()) {\r
1435                 return NULL;\r
1436         }\r
1437 \r
1438         m_nKillRing %= m_oKillRing.GetCount();\r
1439 \r
1440         if (!bForce) {\r
1441                 CClipboardSnap oCurrentSnap;\r
1442                 oCurrentSnap.Capture();\r
1443 \r
1444                 CClipboardSnap *pKillRing = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));\r
1445                 if (!pKillRing) {\r
1446                         return NULL;\r
1447                 }\r
1448                 for (; pKillRing->GetNext(); pKillRing = pKillRing->GetNext()) {\r
1449                         ;\r
1450                 }\r
1451                 if (*pKillRing != oCurrentSnap) {\r
1452                         return NULL;\r
1453                 }\r
1454         }\r
1455 \r
1456         if (!pSnap) {\r
1457                 pSnap = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));\r
1458         }\r
1459         pSnap->Restore();\r
1460 \r
1461         return pSnap->GetNext();\r
1462 }\r
1463 \r
1464 void CXkeymacsDll::Original(int nCommandType, BYTE bVk, int nOriginal)\r
1465 {\r
1466         nCommandType &= ~SHIFT;\r
1467 \r
1468         if (CUtils::IsNT()) {\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 \r
1484         m_nOriginal[nCommandType][bVk] += nOriginal;\r
1485 }\r
1486 \r
1487 int CXkeymacsDll::Original(int nCommandType, BYTE bVk)\r
1488 {\r
1489         nCommandType &= ~SHIFT;\r
1490 \r
1491         if (CUtils::IsNT()) {\r
1492                 switch (bVk) {\r
1493                 case VK_CONTROL:\r
1494                         bVk = VK_LCONTROL;\r
1495                         break;\r
1496                 case VK_MENU:\r
1497                         bVk = VK_LMENU;\r
1498                         break;\r
1499                 case VK_SHIFT:\r
1500                         bVk = VK_LSHIFT;\r
1501                         break;\r
1502                 default:\r
1503                         break;\r
1504                 }\r
1505         }\r
1506 \r
1507         return m_nOriginal[nCommandType][bVk];\r
1508 }\r
1509 \r
1510 void CXkeymacsDll::IncreaseKillRingIndex(int nKillRing)\r
1511 {\r
1512         m_nKillRing += nKillRing;\r
1513 }\r
1514 \r
1515 // move CCommands\r
1516 CString CXkeymacsData::GetCommandName(int nCommandID)\r
1517 {\r
1518         CString szCommandName(Commands[nCommandID].szCommandName);\r
1519         return szCommandName;\r
1520 }\r
1521 \r
1522 // move CCommands\r
1523 int CXkeymacsData::GetDefaultCommandType(int nCommandID, int nIndex)\r
1524 {\r
1525         if (nCommandID < 0 || sizeof(Commands) / sizeof(Commands[0]) <= nCommandID\r
1526          || nIndex < 0 || sizeof(Commands[nCommandID].keybind) / sizeof(Commands[nCommandID].keybind[0]) <= nIndex) {\r
1527                 ASSERT(0);\r
1528                 return NONE;\r
1529         }\r
1530 \r
1531         int nCommandType        = Commands[nCommandID].keybind[nIndex].nCommandType;\r
1532         int bVk                         = Commands[nCommandID].keybind[nIndex].bVk;\r
1533 \r
1534         if (m_b106Keyboard) {\r
1535                 if (nCommandType & SHIFT) {     // Shift\r
1536                         switch (bVk) {\r
1537                         case '2':\r
1538                         case '6':\r
1539                         case 0xBA:              // VK_OEM_1             Used for miscellaneous characters; it can vary by keyboard. \r
1540                                                         //                              Windows 2000/XP: For the US standard keyboard, the ';:' key\r
1541                                 nCommandType &= ~SHIFT;\r
1542                                 break;\r
1543                         default:\r
1544                                 break;\r
1545                         }\r
1546                 } else {                                        // Normal\r
1547                         switch (bVk) {\r
1548                         case 0xBB:              // VK_OEM_PLUS  Windows 2000/XP: For any country/region, the '+' key\r
1549                         case 0xC0:              // VK_OEM_3             Used for miscellaneous characters; it can vary by keyboard. \r
1550                                                         //                              Windows 2000/XP: For the US standard keyboard, the '`~' key\r
1551                         case 0xDE:              // VK_OEM_7             Used for miscellaneous characters; it can vary by keyboard. \r
1552                                                         //                              Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key\r
1553                                 nCommandType |= SHIFT;\r
1554                                 break;\r
1555                         default:\r
1556                                 break;\r
1557                         }\r
1558                 }\r
1559         }\r
1560 \r
1561         return nCommandType;\r
1562 }\r
1563 \r
1564 // move CCommands\r
1565 int CXkeymacsData::GetDefaultCommandKey(int nCommandID, int nIndex)\r
1566 {\r
1567         if (nCommandID < 0 || sizeof(Commands) / sizeof(Commands[0]) <= nCommandID\r
1568          || nIndex < 0 || sizeof(Commands[nCommandID].keybind) / sizeof(Commands[nCommandID].keybind[0]) <= nIndex) {\r
1569                 ASSERT(0);\r
1570                 return 0;\r
1571         }\r
1572 \r
1573         int nCommandType        = Commands[nCommandID].keybind[nIndex].nCommandType;\r
1574         int bVk                         = Commands[nCommandID].keybind[nIndex].bVk;\r
1575 \r
1576         if (m_b106Keyboard) {\r
1577                 if (nCommandType & SHIFT) {     // Shift\r
1578                         switch (bVk) {\r
1579                         case '0':\r
1580                                 bVk = '9';\r
1581                                 break;\r
1582                         case '2':\r
1583                                 bVk = 0xC0;     // VK_OEM_3             Used for miscellaneous characters; it can vary by keyboard. \r
1584                                                         //                              Windows 2000/XP: For the US standard keyboard, the '`~' key\r
1585                                 break;\r
1586                         case '6':\r
1587                                 bVk = 0xDE;     // VK_OEM_7             Used for miscellaneous characters; it can vary by keyboard. \r
1588                                                         //                              Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key\r
1589                                 break;\r
1590                         case '7':\r
1591                                 bVk = '6';\r
1592                                 break;\r
1593                         case '8':\r
1594                                 bVk = 0xBA;     // VK_OEM_1             Used for miscellaneous characters; it can vary by keyboard. \r
1595                                                         //                              Windows 2000/XP: For the US standard keyboard, the ';:' key\r
1596                                 break;\r
1597                         case '9':\r
1598                                 bVk = '8';\r
1599                                 break;\r
1600                         case 0xBD:              // VK_OEM_MINUS Windows 2000/XP: For any country/region, the '-' key\r
1601                                 bVk = 0xE2;     // VK_OEM_102   Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard\r
1602                                 break;\r
1603                         case 0xC0:\r
1604                                 bVk = 0xDE;     // VK_OEM_7             Used for miscellaneous characters; it can vary by keyboard. \r
1605                                                         //                              Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key\r
1606                                 break;\r
1607                         case 0xDE:              // VK_OEM_7             Used for miscellaneous characters; it can vary by keyboard. \r
1608                                                         //                              Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key\r
1609                                 bVk = '2';\r
1610                                 break;\r
1611                         default:\r
1612                                 break;\r
1613                         }\r
1614                 } else {                                        // Normal\r
1615                         switch (bVk) {\r
1616                         case 0xBA:              // VK_OEM_1             Used for miscellaneous characters; it can vary by keyboard. \r
1617                                                         //                              Windows 2000/XP: For the US standard keyboard, the ';:' key\r
1618                                 bVk = 0xBB;     // VK_OEM_PLUS  Windows 2000/XP: For any country/region, the '+' key\r
1619                                 break;\r
1620                         case 0xBB:              // VK_OEM_PLUS  Windows 2000/XP: For any country/region, the '+' key\r
1621                                 bVk = 0xBD;     // VK_OEM_MINUS Windows 2000/XP: For any country/region, the '-' key\r
1622                                 break;\r
1623                         case 0xDE:              // VK_OEM_7             Used for miscellaneous characters; it can vary by keyboard. \r
1624                                                         //                              Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key\r
1625                                 bVk = '7';\r
1626                                 break;\r
1627                         default:\r
1628                                 break;\r
1629                         }\r
1630                 }\r
1631         }\r
1632 \r
1633         return bVk;\r
1634 }\r
1635 \r
1636 // move CCommands\r
1637 int CXkeymacsData::GetDefaultControlID(int nCommandID, int nIndex)\r
1638 {\r
1639         if (nCommandID < 0 || sizeof(Commands) / sizeof(Commands[0]) <= nCommandID\r
1640          || nIndex < 0 || sizeof(Commands[nCommandID].keybind) / sizeof(Commands[nCommandID].keybind[0]) <= nIndex) {\r
1641                 ASSERT(0);\r
1642                 return 0;\r
1643         }\r
1644 \r
1645         return Commands[nCommandID].keybind[nIndex].nControlID;\r
1646 }\r
1647 \r
1648 // nobody use\r
1649 int CXkeymacsDll::GetMickey(int nDifferential, int nThreshold1, int nThreshold2, int nAcceleration, int nSpeed)\r
1650 {\r
1651         nDifferential = nDifferential * 10 / nSpeed;\r
1652 \r
1653         switch (nAcceleration) {\r
1654         case 2:\r
1655                 if (nThreshold2 < fabs((double)(nDifferential / 4))) {\r
1656                         nDifferential /= 4;\r
1657                         break;\r
1658                 }\r
1659                 // Do NOT write break; here.\r
1660         case 1:\r
1661                 if (nThreshold1 < fabs((double)(nDifferential / 2))) {\r
1662                         nDifferential /= 2;\r
1663                 }\r
1664                 break;\r
1665         case 0:\r
1666                 break;\r
1667         default:\r
1668                 ASSERT(0);\r
1669                 break;\r
1670         }\r
1671 \r
1672         return nDifferential;\r
1673 }\r
1674 \r
1675 \r
1676 int CXkeymacsData::GetSettingStyle()\r
1677 {\r
1678         return m_nSettingStyle;\r
1679 }\r
1680 \r
1681 void CXkeymacsData::SetSettingStyle(int nSettingStyle)\r
1682 {\r
1683         m_nSettingStyle = nSettingStyle;\r
1684 }\r
1685 \r
1686 void CXkeymacsDll::SetSettingStyle(int nApplicationID, int nSettingStyle)\r
1687 {\r
1688         m_nSettingStyle[nApplicationID] = nSettingStyle;\r
1689 }\r
1690 \r
1691 int CXkeymacsData::GetCategoryID(int nCommandID)\r
1692 {\r
1693         return Commands[nCommandID].nCategoryID;\r
1694 }\r
1695 \r
1696 void CXkeymacsData::SetIgnoreUndefinedMetaCtrl(BOOL bIgnoreUndefinedMetaCtrl)\r
1697 {\r
1698         m_bIgnoreUndefinedMetaCtrl = bIgnoreUndefinedMetaCtrl;\r
1699 }\r
1700 \r
1701 BOOL CXkeymacsData::GetIgnoreUndefinedMetaCtrl()\r
1702 {\r
1703         return m_bIgnoreUndefinedMetaCtrl;\r
1704 }\r
1705 \r
1706 void CXkeymacsDll::SetIgnoreUndefinedMetaCtrl(int nApplicationID, BOOL bIgnoreUndefinedMetaCtrl)\r
1707 {\r
1708         m_bIgnoreUndefinedMetaCtrl[nApplicationID] = bIgnoreUndefinedMetaCtrl;\r
1709 }\r
1710 \r
1711 void CXkeymacsData::SetIgnoreUndefinedC_x(BOOL bIgnoreUndefinedC_x)\r
1712 {\r
1713         m_bIgnoreUndefinedC_x = bIgnoreUndefinedC_x;\r
1714 }\r
1715 \r
1716 BOOL CXkeymacsData::GetIgnoreUndefinedC_x()\r
1717 {\r
1718         return m_bIgnoreUndefinedC_x;\r
1719 }\r
1720 \r
1721 void CXkeymacsDll::SetIgnoreUndefinedC_x(int nApplicationID, BOOL bIgnoreUndefinedC_x)\r
1722 {\r
1723         m_bIgnoreUndefinedC_x[nApplicationID] = bIgnoreUndefinedC_x;\r
1724 }\r
1725 \r
1726 void CXkeymacsData::SetEnableCUA(BOOL bEnableCUA)\r
1727 {\r
1728         m_bEnableCUA = bEnableCUA;\r
1729 }\r
1730 \r
1731 BOOL CXkeymacsData::GetEnableCUA()\r
1732 {\r
1733         return m_bEnableCUA;\r
1734 }\r
1735 \r
1736 void CXkeymacsDll::SetEnableCUA(int nApplicationID, BOOL bEnableCUA)\r
1737 {\r
1738         m_bEnableCUA[nApplicationID] = bEnableCUA;\r
1739 }\r
1740 \r
1741 BOOL CXkeymacsDll::GetEnableCUA()\r
1742 {\r
1743         return m_bEnableCUA[m_nApplicationID];\r
1744 }\r
1745 \r
1746 void CXkeymacsData::SetUseDialogSetting(BOOL bUseDialogSetting)\r
1747 {\r
1748         m_bUseDialogSetting = bUseDialogSetting;\r
1749 }\r
1750 \r
1751 BOOL CXkeymacsData::GetUseDialogSetting()\r
1752 {\r
1753         return m_bUseDialogSetting;\r
1754 }\r
1755 \r
1756 int CXkeymacsData::GetDescriptionID(int nCommandID)\r
1757 {\r
1758         return Commands[nCommandID].nDescriptionID;\r
1759 }\r
1760 \r
1761 int CXkeymacsData::GetToolTipID(int nCommandID)\r
1762 {\r
1763         return Commands[nCommandID].nToolTipID;\r
1764 }\r
1765 \r
1766 void CXkeymacsDll::DefiningMacro(BOOL bDefiningMacro)\r
1767 {\r
1768         m_bDefiningMacro = bDefiningMacro;\r
1769 \r
1770         if (bDefiningMacro) {   // start-kbd-macro\r
1771                 if (CCommands::bC_u()) {\r
1772                         ReleaseKey(VK_SHIFT);\r
1773                         CallMacro();\r
1774                 }\r
1775         } else {                                // end-kbd-macro\r
1776                 while (!m_Macro.IsEmpty()) {\r
1777                         KbdMacro_t *pKbdMacro = (KbdMacro_t *)m_Macro.GetTail();\r
1778                         if (pKbdMacro->lParam & BEING_RELEASED) {\r
1779                                 break;\r
1780                         } else {\r
1781                                 m_Macro.RemoveTail();\r
1782                                 delete pKbdMacro;\r
1783                                 pKbdMacro = NULL;\r
1784                         }\r
1785                 }\r
1786 \r
1787 //              CUtils::Log(_T("Macro MemMap: start"));\r
1788                 if (!m_Macro.IsEmpty()) {\r
1789                         static HANDLE hMacro = NULL;\r
1790                         if (!hMacro) {\r
1791                                 hMacro = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x3000, _T("macro"));\r
1792                         }\r
1793                         if (hMacro) {\r
1794 //                              CUtils::Log(_T("Macro MemMap: 1"));\r
1795                                 PVOID pView = MapViewOfFile(hMacro, FILE_MAP_ALL_ACCESS, 0, 0, 0);\r
1796 //                              CUtils::Log(_T("Macro MemMap: 2"));\r
1797                                 if (pView) {\r
1798 //                                      CUtils::Log(_T("Macro MemMap: 2.5"));\r
1799                                         for (int i = 0; i < m_Macro.GetCount(); ++i) {\r
1800 //                                              CUtils::Log(_T("Macro MemMap: 3-1 %d"), i);\r
1801                                                 KbdMacro_t *pKbdMacro = (KbdMacro_t *)m_Macro.GetAt(m_Macro.FindIndex(i));\r
1802 //                                              CUtils::Log(_T("Macro MemMap: 3-2 %d"), i);\r
1803                                                 memcpy((LPTSTR) pView + i * sizeof(KbdMacro_t), pKbdMacro, sizeof(KbdMacro_t));\r
1804 //                                              CUtils::Log(_T("Macro MemMap: 3-3 %d"), i);\r
1805                                         }\r
1806 //                                      CUtils::Log(_T("Macro MemMap: 4"));\r
1807                                         UnmapViewOfFile(pView);\r
1808 //                                      CUtils::Log(_T("Macro MemMap: 5"));\r
1809                                 } else {\r
1810 //                                      CUtils::Log(_T("Macro MemMpa: error: %d"), GetLastError());\r
1811                                 }\r
1812                         } else {\r
1813 //                              CUtils::Log(_T("Macro MemMap: 6"));\r
1814                                 ASSERT(0);\r
1815                         }\r
1816                 }\r
1817         }\r
1818 }\r
1819 \r
1820 BOOL CXkeymacsDll::DefiningMacro()\r
1821 {\r
1822         return m_bDefiningMacro;\r
1823 }\r
1824 \r
1825 /**/ \r
1826 void CXkeymacsDll::CallMacro()\r
1827 {\r
1828         BOOL bIsCtrlDown = IsDown(VK_CONTROL);\r
1829         if (bIsCtrlDown) {\r
1830                 ReleaseKey(VK_CONTROL);\r
1831         }\r
1832         BOOL bIsAltDown = IsDown(VK_MENU);\r
1833         if (bIsAltDown) {\r
1834                 ReleaseKey(VK_MENU);\r
1835         }\r
1836         BOOL bIsShiftDown = IsDown(VK_SHIFT);\r
1837         if (bIsShiftDown) {\r
1838                 ReleaseKey(VK_SHIFT);\r
1839         }\r
1840 \r
1841         for (POSITION pos = m_Macro.GetHeadPosition(); pos; ) {\r
1842                 KbdMacro_t *pKbdMacro = (KbdMacro_t *)m_Macro.GetNext(pos);\r
1843                 if (pKbdMacro->lParam & BEING_RELEASED) {\r
1844                         ReleaseKey((BYTE)pKbdMacro->wParam);\r
1845                 } else {\r
1846                         DepressKey((BYTE)pKbdMacro->wParam, pKbdMacro->bOriginal);\r
1847                 }\r
1848         }\r
1849 \r
1850         if (bIsCtrlDown) {\r
1851                 DepressKey(VK_CONTROL);\r
1852         }\r
1853         if (bIsAltDown) {\r
1854                 DepressKey(VK_MENU);\r
1855         }\r
1856         if (bIsShiftDown) {\r
1857                 DepressKey(VK_SHIFT);\r
1858         }\r
1859 }\r
1860 \r
1861 /*\r
1862 void CXkeymacsDll::CallMacro()  // for debug\r
1863 {\r
1864         CString sz;\r
1865         for (POSITION pos = m_Macro.GetHeadPosition(); pos; ) {\r
1866                 KbdMacro_t *pKbdMacro = (KbdMacro_t *)m_Macro.GetNext(pos);\r
1867                 if (pKbdMacro->lParam & BEING_RELEASED) {\r
1868                         CString t;\r
1869                         t.Format(_T("0x%xu "), pKbdMacro->wParam);\r
1870                         sz += t;\r
1871                 } else {\r
1872                         CString t;\r
1873                         t.Format(_T("0x%xd "), pKbdMacro->wParam);\r
1874                         sz += t;\r
1875                 }\r
1876         }\r
1877 //      CUtils::Log(sz);\r
1878 }\r
1879 */\r
1880 \r
1881 void CXkeymacsData::Set106Keyboard(BOOL b106Keyboard)\r
1882 {\r
1883         m_b106Keyboard = b106Keyboard;\r
1884 }\r
1885 \r
1886 BOOL CXkeymacsData::Is106Keyboard()\r
1887 {\r
1888         return m_b106Keyboard;\r
1889 }\r
1890 \r
1891 int CXkeymacsDll::IsPassThrough(BYTE nKey)\r
1892 {\r
1893         BYTE bVk = 0;\r
1894         do {\r
1895                 if (IsDown(bVk)\r
1896                  && (Commands[m_nCommandID[m_nApplicationID][NONE][bVk]].fCommand == CCommands::PassThrough)) {\r
1897                         if (bVk == nKey) {\r
1898                                 return GOTO_HOOK;\r
1899                         }\r
1900 \r
1901                         return GOTO_DO_NOTHING;\r
1902                 }\r
1903         } while (++bVk);\r
1904         return CONTINUE;\r
1905 }\r
1906 \r
1907 void CXkeymacsDll::SetKeyboardHookFlag()\r
1908 {\r
1909         SetKeyboardHookFlag(m_bHook);\r
1910 }\r
1911 \r
1912 void CXkeymacsDll::SetFunctionKey(int nFunctionID, int nApplicationID, int nCommandType, int nKey)\r
1913 {\r
1914         if (nApplicationID      < 0 || MAX_APP                  <= nApplicationID\r
1915          || nCommandType        < 0 || MAX_COMMAND_TYPE <= nCommandType\r
1916          || nKey                        < 0 || MAX_KEY                  <= nKey) {\r
1917                 return;\r
1918         }\r
1919 \r
1920         m_nFunctionID[nApplicationID][nCommandType][nKey] = nFunctionID;\r
1921 }\r
1922 \r
1923 void CXkeymacsDll::ClearFunctionDefinition()\r
1924 {\r
1925         memset(m_nFunctionID, -1, sizeof(m_nFunctionID));\r
1926         memset(m_szFunctionDefinition, 0, sizeof(m_szFunctionDefinition));\r
1927 }\r
1928 \r
1929 void CXkeymacsDll::SetFunctionDefinition(int nFunctionID, CString szDefinition)\r
1930 {\r
1931         if (nFunctionID < 0 || MAX_FUNCTION <= nFunctionID) {\r
1932                 return;\r
1933         }\r
1934 \r
1935         memset(m_szFunctionDefinition[nFunctionID], 0, sizeof(m_szFunctionDefinition[nFunctionID]));\r
1936         _stprintf(m_szFunctionDefinition[nFunctionID], _T("%s"), szDefinition);\r
1937 \r
1938         return;\r
1939 \r
1940 }\r
1941 \r
1942 // call an original command which is defined in dot.xkeymacs\r
1943 void CXkeymacsDll::CallFunction(int nFunctionID)\r
1944 {\r
1945         CArray<KeyBind_t, KeyBind_t> keybinds;\r
1946 \r
1947         if (nFunctionID < 0 || MAX_FUNCTION <= nFunctionID || !_tcslen(m_szFunctionDefinition[nFunctionID])) {\r
1948                 return;\r
1949         }\r
1950 \r
1951         BOOL bIsCtrlDown = CXkeymacsDll::IsDown(VK_CONTROL);\r
1952         BOOL bIsAltDown = CXkeymacsDll::IsDown(VK_MENU);\r
1953         BOOL bIsShiftDown = CXkeymacsDll::IsDown(VK_SHIFT);\r
1954 \r
1955         if (m_szFunctionDefinition[nFunctionID][0] == _T('"') && m_szFunctionDefinition[nFunctionID][_tcslen(m_szFunctionDefinition[nFunctionID]) - 1] == _T('"')) {\r
1956                 for (unsigned int i = 1; i < _tcslen(m_szFunctionDefinition[nFunctionID]) - 1; ++i) {   // skip '"'\r
1957                         keybinds.Add(ParseKey(nFunctionID, i));\r
1958                 }\r
1959         } else if (m_szFunctionDefinition[nFunctionID][0] == _T('[') && m_szFunctionDefinition[nFunctionID][_tcslen(m_szFunctionDefinition[nFunctionID]) - 1] == _T(']')) {\r
1960                 for (unsigned int i = 1; i < _tcslen(m_szFunctionDefinition[nFunctionID]) - 1; ++i) {   // skip '[' and ']'\r
1961                         if (m_szFunctionDefinition[nFunctionID][i] == _T('?')) {        // [?f ?o ?o]\r
1962                                 ++i;\r
1963                                 keybinds.Add(ParseKey(nFunctionID, i));\r
1964                         } else {                                                                                                // [ControlCharacter]\r
1965                                 for (int nKeyID = 0; nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0]); ++nKeyID) {\r
1966                                         if (!_tcsncmp(m_szFunctionDefinition[nFunctionID] + i, ControlCharacters[nKeyID].name, _tcslen(ControlCharacters[nKeyID].name))) {\r
1967                                                 KeyBind_t keybind = {NONE, ControlCharacters[nKeyID].bVk};\r
1968                                                 keybinds.Add(keybind);\r
1969                                                 i += _tcslen(ControlCharacters[nKeyID].name);\r
1970                                                 break;\r
1971                                         }\r
1972                                 }\r
1973                         }\r
1974                 }\r
1975         } else {\r
1976                 return;\r
1977         }\r
1978 \r
1979         BOOL bM_x = FALSE;\r
1980         TCHAR szPath[MAX_PATH] = {'\0'};\r
1981         unsigned int index = 0;\r
1982         BOOL bInitialized = FALSE;\r
1983 \r
1984         for (int i = 0; i < keybinds.GetSize(); ++i) {\r
1985                 const int nCommandType = keybinds.GetAt(i).nCommandType;\r
1986                 const BYTE bVk = keybinds.GetAt(i).bVk;\r
1987 \r
1988                 if (nCommandType < MAX_COMMAND_TYPE && Commands[m_nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand) {\r
1989                         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand == CCommands::ExecuteExtendedCommand) {\r
1990                                 bM_x = TRUE;\r
1991                         } else if (!bInitialized) {\r
1992                                 if (bIsCtrlDown) {\r
1993                                         CUtils::UpdateKeyboardState(VK_CONTROL, 0);\r
1994                                         ReleaseKey(VK_CONTROL);\r
1995                                 }\r
1996 \r
1997                                 if (bIsAltDown) {\r
1998                                         ReleaseKey(VK_MENU);\r
1999                                 }\r
2000 \r
2001                                 if (bIsShiftDown) {\r
2002                                         ReleaseKey(VK_SHIFT);\r
2003                                 }\r
2004 \r
2005                                 bInitialized = TRUE;\r
2006                         }\r
2007 //                      CUtils::Log("CallFunction: Command Name: %s", Commands[m_nCommandID[m_nApplicationID][nCommandType][bVk]].szCommandName);\r
2008                         while (Commands[m_nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand() == GOTO_RECURSIVE) {\r
2009                                 ;\r
2010                         }\r
2011                 } else if (bM_x) {\r
2012                         if (bVk == VK_RETURN) {\r
2013                                 InvokeM_x(szPath);\r
2014                         } else {\r
2015                                 for (TCHAR nAscii = 1; nAscii != 0; ++nAscii) { // repeat until overflow\r
2016                                         if (bVk != 0 && a2v(nAscii) == bVk && ((nCommandType & SHIFT) != 0) == IsShift(nAscii)) {\r
2017 //                                              CUtils::Log("M-x: %#X (%c), %#X (%c)", bVk, bVk, nAscii, nAscii);\r
2018                                                 szPath[index++] = nAscii;\r
2019                                                 break;\r
2020                                         }\r
2021                                 }\r
2022                         }\r
2023                 } else {\r
2024                         if (!bInitialized) {\r
2025                                 if (bIsCtrlDown) {\r
2026                                         CUtils::UpdateKeyboardState(VK_CONTROL, 0);\r
2027                                         ReleaseKey(VK_CONTROL);\r
2028                                 }\r
2029 \r
2030                                 if (bIsAltDown) {\r
2031                                         ReleaseKey(VK_MENU);\r
2032                                 }\r
2033 \r
2034                                 if (bIsShiftDown) {\r
2035                                         ReleaseKey(VK_SHIFT);\r
2036                                 }\r
2037 \r
2038                                 bInitialized = TRUE;\r
2039                         }\r
2040                         if (nCommandType & WIN_WIN) {\r
2041                                 DepressKey(VK_LWIN);\r
2042                         }\r
2043                         if (nCommandType & WIN_CTRL) {\r
2044                                 DepressKey(VK_CONTROL);\r
2045                         }\r
2046                         if (nCommandType & WIN_ALT) {\r
2047                                 DepressKey(VK_MENU);\r
2048                         }\r
2049                         if (nCommandType & SHIFT) {\r
2050                                 DepressKey(VK_SHIFT);\r
2051                         }\r
2052 \r
2053                         Kdu(bVk);\r
2054 \r
2055                         if (nCommandType & SHIFT && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & SHIFT))) {\r
2056                                 ReleaseKey(VK_SHIFT);\r
2057                         }\r
2058                         if (nCommandType & WIN_ALT && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_ALT))) {\r
2059                                 ReleaseKey(VK_MENU);\r
2060                         }\r
2061                         if (nCommandType & WIN_CTRL && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_CTRL))) {\r
2062                                 ReleaseKey(VK_CONTROL);\r
2063                         }\r
2064                         if (nCommandType & WIN_WIN && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_WIN))) {\r
2065                                 ReleaseKey(VK_LWIN);\r
2066                         }\r
2067                 }\r
2068         }\r
2069 \r
2070         keybinds.RemoveAll();\r
2071 \r
2072         if (bInitialized) {\r
2073                 // If these lines are invoked at M-x, a window transition does not work well.\r
2074 \r
2075                 if (bIsShiftDown) {\r
2076                         DepressKey(VK_SHIFT);\r
2077                 }\r
2078 \r
2079                 if (bIsAltDown) {\r
2080                         DepressKey(VK_MENU);\r
2081                 }\r
2082 \r
2083                 if (bIsCtrlDown) {\r
2084                         DepressKey(VK_CONTROL);\r
2085                         CUtils::UpdateKeyboardState(VK_CONTROL, 1);\r
2086                 }\r
2087         }\r
2088         return;\r
2089 }\r
2090 \r
2091 KeyBind_t CXkeymacsDll::ParseKey(const int nFunctionID, unsigned int &i)\r
2092 {\r
2093         KeyBind keybind = {NONE};\r
2094 \r
2095         if (m_szFunctionDefinition[nFunctionID][i] == _T('\\')) {\r
2096                 ++i;\r
2097                 BOOL bFound = FALSE;\r
2098                 do {\r
2099                         bFound = FALSE;\r
2100                         for (int ModifierID = 0; ModifierID < sizeof(Modifiers) / sizeof(Modifiers[0]); ++ModifierID) {\r
2101                                 if (!_tcsncmp(m_szFunctionDefinition[nFunctionID] + i, Modifiers[ModifierID].name, _tcslen(Modifiers[ModifierID].name))\r
2102                                  && _tcslen(Modifiers[ModifierID].name) < _tcslen(m_szFunctionDefinition[nFunctionID] + i)) {\r
2103                                         keybind.nCommandType |= Modifiers[ModifierID].id;\r
2104                                         i+= _tcslen(Modifiers[ModifierID].name);\r
2105                                         bFound = TRUE;\r
2106                                 }\r
2107                         }\r
2108                 } while (bFound);\r
2109         }\r
2110         if (IsShift(m_szFunctionDefinition[nFunctionID][i]) && !(keybind.nCommandType & (WIN_CTRL | WIN_ALT | WIN_WIN))) {\r
2111                 keybind.nCommandType |= SHIFT;\r
2112         }\r
2113 \r
2114         for (int nKeyID = 0; nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0]); ++nKeyID) {\r
2115                 if (!_tcsncmp(m_szFunctionDefinition[nFunctionID] + i, ControlCharacters[nKeyID].name, _tcslen(ControlCharacters[nKeyID].name))) {\r
2116                         i += _tcslen(ControlCharacters[nKeyID].name);\r
2117                         break;\r
2118                 }\r
2119         }\r
2120         if (nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0])) {\r
2121                 keybind.bVk = ControlCharacters[nKeyID].bVk;\r
2122         } else {\r
2123                 keybind.bVk = a2v(m_szFunctionDefinition[nFunctionID][i]);\r
2124         }\r
2125 \r
2126         return keybind;\r
2127 }\r
2128 \r
2129 BOOL CXkeymacsDll::IsShift(TCHAR nAscii)\r
2130 {\r
2131         switch (nAscii) {\r
2132         case _T(' '):\r
2133                 return FALSE;\r
2134         case _T('!'):\r
2135         case _T('"'):\r
2136         case _T('#'):\r
2137         case _T('$'):\r
2138         case _T('%'):\r
2139         case _T('&'):\r
2140                 return TRUE;\r
2141         case _T('\''):\r
2142                 return CXkeymacsData::Is106Keyboard();\r
2143         case _T('('):\r
2144         case _T(')'):\r
2145         case _T('*'):\r
2146         case _T('+'):\r
2147                 return TRUE;\r
2148         case _T(','):\r
2149         case _T('-'):\r
2150         case _T('.'):\r
2151         case _T('/'):\r
2152         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
2153                 return FALSE;\r
2154         case _T(':'):\r
2155                 return !CXkeymacsData::Is106Keyboard();\r
2156         case _T(';'):\r
2157                 return FALSE;\r
2158         case _T('<'):\r
2159                 return TRUE;\r
2160         case _T('='):\r
2161                 return CXkeymacsData::Is106Keyboard();\r
2162         case _T('>'):\r
2163         case _T('?'):\r
2164                 return TRUE;\r
2165         case _T('@'):\r
2166                 return !CXkeymacsData::Is106Keyboard();\r
2167         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
2168         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
2169         case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
2170                 return TRUE;\r
2171         case _T('['):\r
2172         case _T('\\'):\r
2173         case _T(']'):\r
2174                 return FALSE;\r
2175         case _T('^'):\r
2176                 return !CXkeymacsData::Is106Keyboard();\r
2177         case _T('_'):\r
2178                 return TRUE;\r
2179         case _T('`'):\r
2180                 return CXkeymacsData::Is106Keyboard();\r
2181         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
2182         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
2183         case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
2184                 return FALSE;\r
2185         case _T('{'):\r
2186         case _T('|'):\r
2187         case _T('}'):\r
2188         case _T('~'):\r
2189                 return TRUE;\r
2190         default:\r
2191                 return FALSE;\r
2192         }\r
2193 }\r
2194 \r
2195 BYTE CXkeymacsDll::a2v(TCHAR nAscii)\r
2196 {\r
2197         switch (nAscii) {\r
2198         case _T(' '):\r
2199                 return VK_SPACE;\r
2200         case _T('!'):\r
2201                 return '1';\r
2202         case _T('"'):\r
2203                 return CXkeymacsData::Is106Keyboard() ? '2' : (BYTE) 0xde;      // VK_OEM_7\r
2204         case _T('#'):\r
2205                 return '3';\r
2206         case _T('$'):\r
2207                 return '4';\r
2208         case _T('%'):\r
2209                 return '5';\r
2210         case _T('&'):\r
2211                 return CXkeymacsData::Is106Keyboard() ? '6' : '7';\r
2212         case _T('\''):\r
2213                 return CXkeymacsData::Is106Keyboard() ? '7' : (BYTE) 0xde;      // VK_OEM_7\r
2214         case _T('('):\r
2215                 return CXkeymacsData::Is106Keyboard() ? '8' : '9';\r
2216         case _T(')'):\r
2217                 return CXkeymacsData::Is106Keyboard() ? '9' : '0';\r
2218         case _T('*'):\r
2219                 return CXkeymacsData::Is106Keyboard() ? (BYTE) 0xba : '8';      // VK_OEM_1\r
2220         case _T('+'):\r
2221                 return 0xbb;    // VK_OEM_PLUS\r
2222         case _T(','):\r
2223                 return 0xbc;    // VK_OEM_COMMA\r
2224         case _T('-'):\r
2225                 return 0xbd;    // VK_OEM_MINUS\r
2226         case _T('.'):\r
2227                 return 0xbe;    // VK_OEM_PERIOD\r
2228         case _T('/'):\r
2229                 return 0xbf;    // VK_OEM_2\r
2230         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
2231                 return nAscii;\r
2232         case _T(':'):\r
2233                 return 0xba;    // VK_OEM_1\r
2234         case _T(';'):\r
2235                 return CXkeymacsData::Is106Keyboard() ? (BYTE) 0xbb : (BYTE) 0xba;      // VK_OEM_PLUS  VK_OEM_1\r
2236         case _T('<'):\r
2237                 return 0xbc;    // VK_OEM_COMMA\r
2238         case _T('='):\r
2239                 return CXkeymacsData::Is106Keyboard() ? (BYTE) 0xbd : (BYTE) 0xbb;      // VK_OEM_MINUS VK_OEM_PLUS\r
2240         case _T('>'):\r
2241                 return 0xbe;    // VK_OEM_PERIOD\r
2242         case _T('?'):\r
2243                 return 0xbf;    // VK_OEM_2\r
2244         case _T('@'):\r
2245                 return CXkeymacsData::Is106Keyboard() ? (BYTE) 0xc0 : '2';\r
2246         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
2247         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
2248         case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
2249                 return nAscii;\r
2250         case _T('['):\r
2251                 return 0xdb;    // VK_OEM_4\r
2252         case _T('\\'):\r
2253                 return 0xdc;    // VK_OEM_5\r
2254         case _T(']'):\r
2255                 return 0xdd;    // VK_OEM_6\r
2256         case _T('^'):\r
2257                 return CXkeymacsData::Is106Keyboard() ? (BYTE) 0xde : '6';      // VK_OEM_7\r
2258         case _T('_'):\r
2259                 return CXkeymacsData::Is106Keyboard() ? (BYTE) 0xe2 : (BYTE) 0xbd;      // VK_OEM_102   VK_OEM_MINUS\r
2260         case _T('`'):\r
2261                 return 0xc0;    // VK_OEM_3\r
2262         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
2263         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
2264         case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
2265                 return (BYTE) (nAscii - (_T('a') - _T('A')));\r
2266         case _T('{'):\r
2267                 return 0xdb;    // VK_OEM_4\r
2268         case _T('|'):\r
2269                 return 0xdc;    // VK_OEM_5\r
2270         case _T('}'):\r
2271                 return 0xdd;    // VK_OEM_6\r
2272         case _T('~'):\r
2273                 return CXkeymacsData::Is106Keyboard() ? (BYTE) 0xde : (BYTE) 0xc0;      // VK_OEM_7     VK_OEM_3\r
2274         default:\r
2275                 return 0;\r
2276         }\r
2277 }\r
2278 \r
2279 void CXkeymacsDll::DeleteAllShell_NotifyIcon()\r
2280 {\r
2281         for (int icon = 0; icon < MAX_ICON_TYPE; ++icon) {\r
2282                 DeleteShell_NotifyIcon((ICON_TYPE)icon);\r
2283         }\r
2284 }\r
2285 \r
2286 void CXkeymacsDll::AddAllShell_NotifyIcon()\r
2287 {\r
2288         for (int icon = 0; icon < MAX_ICON_TYPE; ++icon) {\r
2289                 AddShell_NotifyIcon((ICON_TYPE)icon);\r
2290         }\r
2291 }\r
2292 \r
2293 void CXkeymacsData::SetWindowText(LPCTSTR lpszWindowText)\r
2294 {\r
2295         m_nWindowTextType = CUtils::GetWindowTextType(lpszWindowText);\r
2296         if (m_nWindowTextType == IDS_WINDOW_TEXT_IGNORE) {\r
2297                 m_strWindowText = _T('*');\r
2298         } else {\r
2299                 m_strWindowText.Format(lpszWindowText);\r
2300         }\r
2301 }\r
2302 \r
2303 CString CXkeymacsData::GetWindowText()\r
2304 {\r
2305         return m_strWindowText;\r
2306 }\r
2307 \r
2308 void CXkeymacsData::SetWindowTextType(int nWindowTextType)\r
2309 {\r
2310         m_nWindowTextType = nWindowTextType;\r
2311 }\r
2312 \r
2313 int CXkeymacsData::GetWindowTextType()\r
2314 {\r
2315         return m_nWindowTextType;\r
2316 }\r
2317 \r
2318 BOOL CXkeymacsDll::IsMatchWindowText(CString szWindowText)\r
2319 {\r
2320         BOOL bIsMatchWindowText = TRUE;\r
2321 \r
2322         TCHAR szCurrentWindowText[0x100] = {'\0'};\r
2323         GetWindowText(GetForegroundWindow(), szCurrentWindowText, sizeof(szCurrentWindowText));\r
2324 \r
2325         switch (CUtils::GetWindowTextType(szWindowText)) {\r
2326         case IDS_WINDOW_TEXT_MATCH:                                                             // *foo*\r
2327                 szWindowText.Delete(0);                                                         // Delete first '*'\r
2328                 szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
2329                 bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText);\r
2330                 break;\r
2331         case IDS_WINDOW_TEXT_MATCH_FORWARD:                                             // foo*\r
2332                 szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
2333                 bIsMatchWindowText = 0 == CString(szCurrentWindowText).Find(szWindowText);\r
2334                 break;\r
2335         case IDS_WINDOW_TEXT_MATCH_BACKWARD:                                    // *foo\r
2336                 szWindowText.Delete(0);                                                         // Delete first '*'\r
2337                 bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText, CString(szCurrentWindowText).GetLength() - szWindowText.GetLength());\r
2338                 break;\r
2339         case IDS_WINDOW_TEXT_MATCH_FULL:                                                // foo\r
2340                 bIsMatchWindowText = szWindowText == CString(szCurrentWindowText);\r
2341                 break;\r
2342         case IDS_WINDOW_TEXT_IGNORE:                                                    // *\r
2343                 bIsMatchWindowText = TRUE;\r
2344                 break;\r
2345         default:\r
2346                 ASSERT(0);\r
2347                 break;\r
2348         }\r
2349 \r
2350 //      CUtils::Log(_T("IsMatchWindowText: %d, _%s_, _%s_"), bIsMatchWindowText, szCurrentWindowText, szWindowText);\r
2351         return bIsMatchWindowText;\r
2352 }\r
2353 \r
2354 void CXkeymacsDll::SetAccelerate(int nAccelerate)\r
2355 {\r
2356         m_nAccelerate = nAccelerate;\r
2357 }\r
2358 \r
2359 int CXkeymacsDll::GetAccelerate()\r
2360 {\r
2361         return m_nAccelerate;\r
2362 }\r
2363 \r
2364 void CXkeymacsDll::SetKeyboardSpeed(int nKeyboardSpeed)\r
2365 {\r
2366         m_nKeyboardSpeed = nKeyboardSpeed;\r
2367 }\r
2368 \r
2369 unsigned int CXkeymacsDll::GetMaxKeyInterval()\r
2370 {\r
2371         // m_nKeyboardSpeed == 0:       slowest repeat rate; approximately  2 characters per second\r
2372         // m_nKeyboardSpeed == 31:      fastest repeat rate; approximately 30 characters per second\r
2373         // 47 ms is max on my machine w/ KeyboardSpeed 31.\r
2374         // 1000 /  2 + 50 = 550\r
2375         // 1000 / 30 + 50 = 83\r
2376         return (unsigned int) (1000.0 / (2.0 + m_nKeyboardSpeed % 32 * 28.0 / 31.0) + 50.0);\r
2377 }\r
2378 \r
2379 void CXkeymacsDll::SetCursorData(HCURSOR hEnable, HCURSOR hDisableTMP, HCURSOR hDisableWOCQ, HICON hDisable, BOOL bEnable)\r
2380 {\r
2381         m_hCursor[STATUS_ENABLE] = hEnable;\r
2382         m_hCursor[STATUS_DISABLE_TMP] = hDisableTMP;\r
2383         m_hCursor[STATUS_DISABLE_WOCQ] = hDisableWOCQ;\r
2384         m_hCursor[STATUS_DISABLE] = hDisable;\r
2385         m_bCursor = bEnable;\r
2386 }\r
2387 \r
2388 void CXkeymacsDll::DoSetCursor()\r
2389 {\r
2390         if (m_bCursor && m_hCurrentCursor) {\r
2391                 ::SetCursor(m_hCurrentCursor);\r
2392         }\r
2393 }\r
2394 \r
2395 BOOL CXkeymacsData::Get326Compatible()\r
2396 {\r
2397         return m_b326Compatible;\r
2398 }\r
2399 \r
2400 void CXkeymacsData::Set326Compatible(BOOL b326Compatible)\r
2401 {\r
2402         m_b326Compatible = b326Compatible;\r
2403 }\r
2404 \r
2405 void CXkeymacsDll::Set326Compatible(int nApplicationID, BOOL b326Compatible)\r
2406 {\r
2407         m_b326Compatible[nApplicationID] = b326Compatible;\r
2408 }\r
2409 \r
2410 BOOL CXkeymacsDll::Get326Compatible()\r
2411 {\r
2412         return m_b326Compatible[m_nApplicationID];\r
2413 }\r
2414 \r
2415 void CXkeymacsDll::InvokeM_x(const TCHAR *const szPath)\r
2416 {\r
2417 //      CUtils::Log("M-x: szPath=_%s_", szPath);\r
2418         int (*fCommand)() = NULL;\r
2419 \r
2420         for (int i = 0; i < sizeof(Commands) / sizeof(Commands[0]); ++i) {\r
2421                 if (_tcsicmp(szPath, Commands[i].szCommandName) == 0) {\r
2422                         fCommand = Commands[i].fCommand;\r
2423                         break;\r
2424                 }\r
2425         }\r
2426 \r
2427         if (fCommand) {\r
2428 //              CUtils::Log("M-x: Command: _%s_", Commands[i].szCommandName);\r
2429                 fCommand();\r
2430         } else {\r
2431 //              CUtils::Log("M-x: Path: _%s_", szPath);\r
2432                 ShellExecute(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);\r
2433         }\r
2434 }\r
2435 \r
2436 void CXkeymacsDll::ModifyM_xTip(const TCHAR *const szPath)\r
2437 {\r
2438         if (szPath) {\r
2439                 if (_tcslen(szPath) < sizeof(m_stNtfyIcon[MX_ICON].szTip) / sizeof(m_stNtfyIcon[MX_ICON].szTip[0]) - 5) {\r
2440                         memset(m_stNtfyIcon[MX_ICON].szTip, 0, sizeof(m_stNtfyIcon[MX_ICON].szTip));\r
2441                         _stprintf(m_stNtfyIcon[MX_ICON].szTip, "M-x %s", szPath);\r
2442                 }\r
2443         } else {\r
2444                 memset(m_stNtfyIcon[MX_ICON].szTip, 0, sizeof(m_stNtfyIcon[MX_ICON].szTip));\r
2445                 _stprintf(m_stNtfyIcon[MX_ICON].szTip, "M-x LED");\r
2446         }\r
2447 \r
2448         ModifyShell_NotifyIcon(MX_ICON, CCommands::bM_x(), TRUE);\r
2449 }\r