OSDN Git Service

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