OSDN Git Service

change EOL style to CRLF to adjust to default setting of Visual Studio
[yamy/yamy.git] / hook.cpp
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
2 // hook.cpp\r
3 \r
4 \r
5 #define _HOOK_CPP\r
6 \r
7 #include "misc.h"\r
8 \r
9 #include "hook.h"\r
10 #include "stringtool.h"\r
11 \r
12 #include <locale.h>\r
13 #include <imm.h>\r
14 #include <richedit.h>\r
15 \r
16 \r
17 ///\r
18 #define HOOK_DATA_NAME _T("{08D6E55C-5103-4e00-8209-A1C4AB13BBEF}") _T(VERSION)\r
19 #ifdef _WIN64\r
20 #define HOOK_DATA_NAME_ARCH _T("{290C0D51-8AEE-403d-9172-E43D46270996}") _T(VERSION)\r
21 #else // !_WIN64\r
22 #define HOOK_DATA_NAME_ARCH _T("{716A5DEB-CB02-4438-ABC8-D00E48673E45}") _T(VERSION)\r
23 #endif // !_WIN64\r
24 \r
25 // Some applications use different values for below messages\r
26 // when double click of title bar.\r
27 #define SC_MAXIMIZE2 (SC_MAXIMIZE + 2)\r
28 #define SC_MINIMIZE2 (SC_MINIMIZE + 2)\r
29 #define SC_RESTORE2 (SC_RESTORE + 2)\r
30 \r
31 // Debug Macros\r
32 #ifdef NDEBUG\r
33 #define HOOK_RPT0(msg)\r
34 #define HOOK_RPT1(msg, arg1)\r
35 #define HOOK_RPT2(msg, arg1, arg2)\r
36 #else\r
37 #define HOOK_RPT0(msg) if (g.m_isLogging) { _RPT0(_CRT_WARN, msg); }\r
38 #define HOOK_RPT1(msg, arg1) if (g.m_isLogging) { _RPT1(_CRT_WARN, msg, arg1); }\r
39 #define HOOK_RPT2(msg, arg1, arg2) if (g.m_isLogging) { _RPT2(_CRT_WARN, msg, arg1, arg2); }\r
40 #endif\r
41 \r
42 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
43 // Global Variables\r
44 \r
45 \r
46 DllExport HookData *g_hookData;                 ///\r
47 \r
48 ///\r
49 class HookDataArch\r
50 {\r
51 public:\r
52   HHOOK m_hHookGetMessage;                      ///\r
53   HHOOK m_hHookCallWndProc;                     ///\r
54 };\r
55 \r
56 static HookDataArch *s_hookDataArch;\r
57 \r
58 struct Globals\r
59 {\r
60   HANDLE m_hHookData;                           ///\r
61   HANDLE m_hHookDataArch;                       ///\r
62   HWND m_hwndFocus;                             /// \r
63   HINSTANCE m_hInstDLL;                         ///\r
64   bool m_isInMenu;                              ///\r
65   UINT m_WM_MAYU_MESSAGE;                       ///\r
66   bool m_isImeLock;                             ///\r
67   bool m_isImeCompositioning;                   ///\r
68   HHOOK m_hHookMouseProc;                       ///\r
69 #ifdef NO_DRIVER\r
70   HHOOK m_hHookKeyboardProc;                    ///\r
71   KEYBOARD_DETOUR m_keyboardDetour;\r
72   Engine *m_engine;\r
73 #endif // NO_DRIVER\r
74   DWORD m_hwndTaskTray;                         ///\r
75   HANDLE m_hMailslot;\r
76   bool m_isInitialized;\r
77 #ifndef NDEBUG\r
78   bool m_isLogging;\r
79   _TCHAR m_moduleName[GANA_MAX_PATH];\r
80 #endif // !NDEBUG\r
81 };\r
82 \r
83 static Globals g;\r
84 \r
85 \r
86 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
87 // Prototypes\r
88 \r
89 \r
90 static void notifyThreadDetach();\r
91 static void notifyShow(NotifyShow::Show i_show, bool i_isMDI);\r
92 static void notifyLog(_TCHAR *i_msg);\r
93 static bool mapHookData();\r
94 static void unmapHookData();\r
95 static bool initialize();\r
96 \r
97 \r
98 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
99 // Functions\r
100 \r
101 bool initialize()\r
102 {\r
103 #ifndef NDEBUG\r
104   _TCHAR path[GANA_MAX_PATH];\r
105   GetModuleFileName(NULL, path, GANA_MAX_PATH);\r
106   _tsplitpath_s(path, NULL, 0, NULL, 0, g.m_moduleName, GANA_MAX_PATH, NULL, 0);\r
107   if (_tcsncmp(g.m_moduleName, _T("Dbgview"), sizeof(_T("Dbgview"))/sizeof(_TCHAR)) != 0 &&\r
108       _tcsncmp(g.m_moduleName, _T("windbg"), sizeof(_T("windbg"))/sizeof(_TCHAR)) != 0)\r
109   {\r
110         g.m_isLogging = true;\r
111   }\r
112 #endif // !NDEBUG\r
113 #ifdef USE_MAILSLOT\r
114   g.m_hMailslot =\r
115           CreateFile(NOTIFY_MAILSLOT_NAME, GENERIC_WRITE,\r
116                      FILE_SHARE_READ | FILE_SHARE_WRITE,\r
117                      (SECURITY_ATTRIBUTES *)NULL, OPEN_EXISTING,\r
118                      FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);\r
119   if (g.m_hMailslot == INVALID_HANDLE_VALUE)\r
120   {\r
121     HOOK_RPT2("MAYU: %S create mailslot failed(0x%08x)\r\n", g.m_moduleName, GetLastError());\r
122   }\r
123   else\r
124   {\r
125     HOOK_RPT1("MAYU: %S create mailslot successed\r\n", g.m_moduleName);\r
126   }\r
127 #endif //USE_MAILSLOT\r
128   if (!mapHookData())\r
129     return false;\r
130   _tsetlocale(LC_ALL, _T(""));\r
131   g.m_WM_MAYU_MESSAGE =\r
132     RegisterWindowMessage(addSessionId(WM_MAYU_MESSAGE_NAME).c_str());\r
133   g.m_hwndTaskTray = g_hookData->m_hwndTaskTray;\r
134   g.m_isInitialized = true;\r
135   return true;\r
136 }\r
137 \r
138 /// EntryPoint\r
139 BOOL WINAPI DllMain(HINSTANCE i_hInstDLL, DWORD i_fdwReason,\r
140                     LPVOID /* i_lpvReserved */)\r
141 {\r
142   switch (i_fdwReason)\r
143   {\r
144     case DLL_PROCESS_ATTACH:\r
145     {\r
146 #ifndef NDEBUG\r
147       g.m_isLogging = false;\r
148 #endif // !NDEBUG\r
149       g.m_isInitialized = false;\r
150       g.m_hInstDLL = i_hInstDLL;\r
151       break;\r
152     }\r
153     case DLL_THREAD_ATTACH:\r
154       break;\r
155     case DLL_PROCESS_DETACH:\r
156       notifyThreadDetach();\r
157       unmapHookData();\r
158 #ifdef USE_MAILSLOT\r
159       if (g.m_hMailslot != INVALID_HANDLE_VALUE)\r
160       {\r
161         CloseHandle(g.m_hMailslot);\r
162         g.m_hMailslot = INVALID_HANDLE_VALUE;\r
163       }\r
164 #endif //USE_MAILSLOT\r
165       break;\r
166     case DLL_THREAD_DETACH:\r
167       notifyThreadDetach();\r
168       break;\r
169     default:\r
170       break;\r
171   }\r
172   return TRUE;\r
173 }\r
174 \r
175 \r
176 /// map hook data\r
177 static bool mapHookData()\r
178 {\r
179   g.m_hHookData = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,\r
180                                     0, sizeof(HookData),\r
181                                     addSessionId(HOOK_DATA_NAME).c_str());\r
182   if (!g.m_hHookData)\r
183   {\r
184     unmapHookData();\r
185     return false;\r
186   }\r
187   \r
188   g_hookData =\r
189     (HookData *)MapViewOfFile(g.m_hHookData, FILE_MAP_READ | FILE_MAP_WRITE,\r
190                               0, 0, sizeof(HookData));\r
191   if (!g_hookData)\r
192   {\r
193     unmapHookData();\r
194     return false;\r
195   }\r
196 \r
197   g.m_hHookDataArch = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,\r
198                                     0, sizeof(HookDataArch),\r
199                                     addSessionId(HOOK_DATA_NAME_ARCH).c_str());\r
200   if (!g.m_hHookDataArch)\r
201   {\r
202     unmapHookData();\r
203     return false;\r
204   }\r
205   \r
206   s_hookDataArch =\r
207     (HookDataArch *)MapViewOfFile(g.m_hHookDataArch, FILE_MAP_READ | FILE_MAP_WRITE,\r
208                               0, 0, sizeof(HookDataArch));\r
209   if (!s_hookDataArch)\r
210   {\r
211     unmapHookData();\r
212     return false;\r
213   }\r
214 \r
215   return true;\r
216 }\r
217 \r
218 \r
219 /// unmap hook data\r
220 static void unmapHookData()\r
221 {\r
222   if (g_hookData)\r
223     UnmapViewOfFile(g_hookData);\r
224   g_hookData = NULL;\r
225   if (g.m_hHookData)\r
226     CloseHandle(g.m_hHookData);\r
227   g.m_hHookData = NULL;\r
228   if (s_hookDataArch)\r
229     UnmapViewOfFile(s_hookDataArch);\r
230   s_hookDataArch = NULL;\r
231   if (g.m_hHookDataArch)\r
232     CloseHandle(g.m_hHookDataArch);\r
233   g.m_hHookDataArch = NULL;\r
234 }\r
235 \r
236 \r
237 /// notify\r
238 DllExport bool notify(void *i_data, size_t i_dataSize)\r
239 {\r
240   COPYDATASTRUCT cd;\r
241 #ifdef MAYU64\r
242   DWORD_PTR result;\r
243 #else  // MAYU64\r
244   DWORD result;\r
245 #endif // MAYU64\r
246 \r
247 #ifdef USE_MAILSLOT\r
248   DWORD len;\r
249   if (g.m_hMailslot != INVALID_HANDLE_VALUE)\r
250   {\r
251     BOOL ret;\r
252     ret = WriteFile(g.m_hMailslot, i_data, i_dataSize, &len, NULL);\r
253 #ifndef NDEBUG\r
254     if (ret == 0)\r
255     {\r
256       HOOK_RPT2("MAYU: %S WriteFile to mailslot failed(0x%08x)\r\n", g.m_moduleName, GetLastError());\r
257     }\r
258     else\r
259     {\r
260       HOOK_RPT1("MAYU: %S WriteFile to mailslot successed\r\n", g.m_moduleName);\r
261     }\r
262 #endif // !NDEBUG\r
263   }\r
264 #else // !USE_MAILSLOT\r
265   cd.dwData = reinterpret_cast<Notify *>(i_data)->m_type;\r
266   cd.cbData = i_dataSize;\r
267   cd.lpData = i_data;\r
268   if (g.m_hwndTaskTray == 0)\r
269     return false;\r
270   if (!SendMessageTimeout(reinterpret_cast<HWND>(g.m_hwndTaskTray),\r
271                           WM_COPYDATA, NULL, reinterpret_cast<LPARAM>(&cd),\r
272                           SMTO_ABORTIFHUNG | SMTO_NORMAL, 5000, &result))\r
273   {\r
274     _RPT0(_CRT_WARN, "MAYU: SendMessageTimeout() timeouted\r\n");\r
275     return false;\r
276   }\r
277 #endif // !USE_MAILSLOT\r
278   return true;\r
279 }\r
280 \r
281 \r
282 /// get class name and title name\r
283 static void getClassNameTitleName(HWND i_hwnd, bool i_isInMenu, \r
284                                   tstringi *o_className,\r
285                                   tstring *o_titleName)\r
286 {\r
287   tstringi &className = *o_className;\r
288   tstring &titleName = *o_titleName;\r
289   \r
290   bool isTheFirstTime = true;\r
291   \r
292   if (i_isInMenu)\r
293   {\r
294     className = titleName = _T("MENU");\r
295     isTheFirstTime = false;\r
296   }\r
297 \r
298   while (true)\r
299   {\r
300     _TCHAR buf[MAX(GANA_MAX_PATH, GANA_MAX_ATOM_LENGTH)];\r
301 \r
302     // get class name\r
303     if (i_hwnd)\r
304       GetClassName(i_hwnd, buf, NUMBER_OF(buf));\r
305     else\r
306       GetModuleFileName(GetModuleHandle(NULL), buf, NUMBER_OF(buf));\r
307     buf[NUMBER_OF(buf) - 1] = _T('\0');\r
308     if (isTheFirstTime)\r
309       className = buf;\r
310     else\r
311       className = tstringi(buf) + _T(":") + className;\r
312     \r
313     // get title name\r
314     if (i_hwnd)\r
315     {\r
316       GetWindowText(i_hwnd, buf, NUMBER_OF(buf));\r
317       buf[NUMBER_OF(buf) - 1] = _T('\0');\r
318       for (_TCHAR *b = buf; *b; ++ b)\r
319         if (_istlead(*b) && b[1])\r
320           b ++;\r
321         else if (_istcntrl(*b))\r
322           *b = _T('?');\r
323     }\r
324     if (isTheFirstTime)\r
325       titleName = buf;\r
326     else\r
327       titleName = tstring(buf) + _T(":") + titleName;\r
328 \r
329     // next loop or exit\r
330     if (!i_hwnd)\r
331       break;\r
332     i_hwnd = GetParent(i_hwnd);\r
333     isTheFirstTime = false;\r
334   }\r
335 }\r
336 \r
337 \r
338 /// update show\r
339 static void updateShow(HWND i_hwnd, NotifyShow::Show i_show)\r
340 {\r
341   bool isMDI = false;\r
342 \r
343   if (!i_hwnd)\r
344     return;\r
345 \r
346 #ifdef MAYU64\r
347   LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);\r
348 #else\r
349   LONG style = GetWindowLong(i_hwnd, GWL_STYLE);\r
350 #endif\r
351   if (!(style & WS_MAXIMIZEBOX) && !(style & WS_MAXIMIZEBOX))\r
352     return; // ignore window that has neither maximize or minimize button\r
353 \r
354   if (style & WS_CHILD)\r
355   {\r
356 #ifdef MAYU64\r
357     LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);\r
358 #else\r
359     LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);\r
360 #endif\r
361     if (exStyle & WS_EX_MDICHILD)\r
362     {\r
363       isMDI = true;\r
364     }\r
365     else\r
366       return; // ignore non-MDI child window case\r
367   }\r
368 \r
369   notifyShow(i_show, isMDI);\r
370 }\r
371 \r
372 \r
373 /// notify WM_Targetted\r
374 static void notifyName(HWND i_hwnd, Notify::Type i_type = Notify::Type_name)\r
375 {\r
376   tstringi className;\r
377   tstring titleName;\r
378   getClassNameTitleName(i_hwnd, g.m_isInMenu, &className, &titleName);\r
379   \r
380   NotifySetFocus *nfc = new NotifySetFocus;\r
381   nfc->m_type = i_type;\r
382   nfc->m_threadId = GetCurrentThreadId();\r
383   nfc->m_hwnd = reinterpret_cast<DWORD>(i_hwnd);\r
384   tcslcpy(nfc->m_className, className.c_str(), NUMBER_OF(nfc->m_className));\r
385   tcslcpy(nfc->m_titleName, titleName.c_str(), NUMBER_OF(nfc->m_titleName));\r
386 \r
387   notify(nfc, sizeof(*nfc));\r
388   delete nfc;\r
389 }\r
390 \r
391 \r
392 /// notify WM_SETFOCUS\r
393 static void notifySetFocus(bool i_doesForce = false)\r
394 {\r
395   HWND hwnd = GetFocus();\r
396   if (i_doesForce || hwnd != g.m_hwndFocus)\r
397   {\r
398     g.m_hwndFocus = hwnd;\r
399     notifyName(hwnd, Notify::Type_setFocus);\r
400   }\r
401 }\r
402 \r
403 \r
404 /// notify sync\r
405 static void notifySync()\r
406 {\r
407   Notify n;\r
408   n.m_type = Notify::Type_sync;\r
409   notify(&n, sizeof(n));\r
410 }\r
411 \r
412 \r
413 /// notify DLL_THREAD_DETACH\r
414 static void notifyThreadDetach()\r
415 {\r
416   NotifyThreadDetach ntd;\r
417   ntd.m_type = Notify::Type_threadDetach;\r
418   ntd.m_threadId = GetCurrentThreadId();\r
419   notify(&ntd, sizeof(ntd));\r
420 }\r
421 \r
422 \r
423 /// notify WM_COMMAND, WM_SYSCOMMAND\r
424 static void notifyCommand(\r
425   HWND i_hwnd, UINT i_message, WPARAM i_wParam, LPARAM i_lParam)\r
426 {\r
427 #ifndef _WIN64\r
428   if (g_hookData->m_doesNotifyCommand)\r
429   {\r
430     NotifyCommand ntc;\r
431     ntc.m_type = Notify::Type_command;\r
432     ntc.m_hwnd = i_hwnd;\r
433     ntc.m_message = i_message;\r
434     ntc.m_wParam = i_wParam;\r
435     ntc.m_lParam = i_lParam;\r
436     notify(&ntc, sizeof(ntc));\r
437   }\r
438 #endif\r
439 }\r
440 \r
441 \r
442 /// notify show of current window\r
443 static void notifyShow(NotifyShow::Show i_show, bool i_isMDI)\r
444 {\r
445   NotifyShow ns;\r
446   ns.m_type = Notify::Type_show;\r
447   ns.m_show = i_show;\r
448   ns.m_isMDI = i_isMDI;\r
449   notify(&ns, sizeof(ns));\r
450 }\r
451 \r
452 \r
453 /// notify log\r
454 static void notifyLog(_TCHAR *i_msg)\r
455 {\r
456   NotifyLog nl;\r
457   nl.m_type = Notify::Type_log;\r
458   tcslcpy(nl.m_msg, i_msg, NUMBER_OF(nl.m_msg));\r
459   notify(&nl, sizeof(nl));\r
460 }\r
461 \r
462 \r
463 /// &Recenter\r
464 static void funcRecenter(HWND i_hwnd)\r
465 {\r
466   _TCHAR buf[MAX(GANA_MAX_PATH, GANA_MAX_ATOM_LENGTH)];\r
467   GetClassName(i_hwnd, buf, NUMBER_OF(buf));\r
468   bool isEdit;\r
469   if (_tcsicmp(buf, _T("Edit")) == 0)\r
470     isEdit = true;\r
471   else if (_tcsnicmp(buf, _T("RichEdit"), 8) == 0)\r
472     isEdit = false;\r
473   else\r
474     return;     // this function only works for Edit control\r
475 \r
476 #ifdef MAYU64\r
477   LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);\r
478 #else\r
479   LONG style = GetWindowLong(i_hwnd, GWL_STYLE);\r
480 #endif\r
481   if (!(style & ES_MULTILINE))\r
482     return;     // this function only works for multi line Edit control\r
483 \r
484   RECT rc;\r
485   GetClientRect(i_hwnd, &rc);\r
486   POINTL p = { (rc.right + rc.left) / 2, (rc.top + rc.bottom) / 2 };\r
487   int line;\r
488   if (isEdit)\r
489   {\r
490     line = SendMessage(i_hwnd, EM_CHARFROMPOS, 0, MAKELPARAM(p.x, p.y));\r
491     line = HIWORD(line);\r
492   }\r
493   else\r
494   {\r
495     int ci = SendMessage(i_hwnd, EM_CHARFROMPOS, 0, (LPARAM)&p);\r
496     line = SendMessage(i_hwnd, EM_EXLINEFROMCHAR, 0, ci);\r
497   }\r
498   int caretLine = SendMessage(i_hwnd, EM_LINEFROMCHAR, -1, 0);\r
499   SendMessage(i_hwnd, EM_LINESCROLL, 0, caretLine - line);\r
500 }\r
501 \r
502 \r
503 // &SetImeStatus\r
504 static void funcSetImeStatus(HWND i_hwnd, int i_status)\r
505 {\r
506   HIMC hIMC;\r
507 \r
508   hIMC = ImmGetContext(i_hwnd);\r
509   if (hIMC == INVALID_HANDLE_VALUE)\r
510     return;\r
511 \r
512   if (i_status < 0)\r
513     i_status = !ImmGetOpenStatus(hIMC);\r
514 \r
515   ImmSetOpenStatus(hIMC, i_status);\r
516   ImmReleaseContext(i_hwnd, hIMC);\r
517 }\r
518 \r
519 \r
520 // &SetImeString\r
521 static void funcSetImeString(HWND i_hwnd, int i_size)\r
522 {\r
523   _TCHAR *buf = new _TCHAR(i_size);\r
524   DWORD len = 0;\r
525   _TCHAR ImeDesc[GANA_MAX_ATOM_LENGTH];\r
526   UINT ImeDescLen;\r
527   DWORD error;\r
528   DWORD denom = 1;\r
529   HANDLE hPipe\r
530     = CreateFile(addSessionId(HOOK_PIPE_NAME).c_str(), GENERIC_READ,\r
531                  FILE_SHARE_READ, (SECURITY_ATTRIBUTES *)NULL,\r
532                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);\r
533   error = ReadFile(hPipe, buf, i_size, &len, NULL);\r
534   CloseHandle(hPipe);\r
535 \r
536   ImeDescLen = ImmGetDescription(GetKeyboardLayout(0),\r
537                                  ImeDesc, sizeof(ImeDesc));\r
538   if (_tcsncmp(ImeDesc, _T("SKKIME"), ImeDescLen) > 0)\r
539     denom = sizeof(_TCHAR);\r
540 \r
541   HIMC hIMC = ImmGetContext(i_hwnd);\r
542   if (hIMC == INVALID_HANDLE_VALUE)\r
543     return;\r
544 \r
545   int status = ImmGetOpenStatus(hIMC);\r
546   ImmSetCompositionString(hIMC, SCS_SETSTR, buf, len / denom, NULL, 0);\r
547   delete buf;\r
548   ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);\r
549   if (!status)\r
550     ImmSetOpenStatus(hIMC, status);\r
551   ImmReleaseContext(i_hwnd, hIMC);\r
552 }\r
553 \r
554 /// notify lock state\r
555 /*DllExport*/ void notifyLockState(int i_cause)\r
556 {\r
557   NotifyLockState n;\r
558   n.m_type = Notify::Type_lockState;\r
559   n.m_isNumLockToggled = !!(GetKeyState(VK_NUMLOCK) & 1);\r
560   n.m_isCapsLockToggled = !!(GetKeyState(VK_CAPITAL) & 1);\r
561   n.m_isScrollLockToggled = !!(GetKeyState(VK_SCROLL) & 1);\r
562   n.m_isKanaLockToggled = !!(GetKeyState(VK_KANA) & 1);\r
563   n.m_isImeLockToggled = g.m_isImeLock;\r
564   n.m_isImeCompToggled = g.m_isImeCompositioning;\r
565   n.m_debugParam = i_cause;\r
566   notify(&n, sizeof(n));\r
567 }\r
568 \r
569 DllExport void notifyLockState()\r
570 {\r
571   notifyLockState(9);\r
572 }\r
573 \r
574 \r
575 /// hook of GetMessage\r
576 LRESULT CALLBACK getMessageProc(int i_nCode, WPARAM i_wParam, LPARAM i_lParam)\r
577 {\r
578   if (!g.m_isInitialized)\r
579     initialize();\r
580 \r
581   if (!g_hookData)\r
582     return 0;\r
583   \r
584   MSG &msg = (*(MSG *)i_lParam);\r
585 \r
586   if (i_wParam != PM_REMOVE)\r
587     goto finally;\r
588 \r
589   switch (msg.message)\r
590   {\r
591     case WM_COMMAND:\r
592     case WM_SYSCOMMAND:\r
593       notifyCommand(msg.hwnd, msg.message, msg.wParam, msg.lParam);\r
594       break;\r
595     case WM_KEYDOWN:\r
596     case WM_KEYUP:\r
597     case WM_SYSKEYDOWN:\r
598     case WM_SYSKEYUP:\r
599     {\r
600       if (HIMC hIMC = ImmGetContext(msg.hwnd))\r
601       {\r
602         bool prev = g.m_isImeLock;\r
603         g.m_isImeLock = !!ImmGetOpenStatus(hIMC);\r
604         ImmReleaseContext(msg.hwnd, hIMC);\r
605         if (prev != g.m_isImeLock) {\r
606           notifyLockState(1);\r
607         }\r
608       }\r
609       int nVirtKey = (int)msg.wParam;\r
610       // int repeatCount = (msg.lParam & 0xffff);\r
611       BYTE scanCode   = (BYTE)((msg.lParam >> 16) & 0xff);\r
612       bool isExtended = !!(msg.lParam & (1 << 24));\r
613       // bool isAltDown  = !!(msg.lParam & (1 << 29));\r
614       // bool isKeyup    = !!(msg.lParam & (1 << 31));\r
615       \r
616       if (nVirtKey == VK_CAPITAL ||\r
617           nVirtKey == VK_NUMLOCK ||\r
618           nVirtKey == VK_KANA ||\r
619           nVirtKey == VK_SCROLL)\r
620         notifyLockState(2);\r
621       else if (scanCode == g_hookData->m_syncKey &&\r
622                isExtended == g_hookData->m_syncKeyIsExtended)\r
623         notifySync();\r
624       break;\r
625     }\r
626     case WM_IME_STARTCOMPOSITION:\r
627       g.m_isImeCompositioning = true;\r
628       notifyLockState(3);\r
629       break;\r
630     case WM_IME_ENDCOMPOSITION:\r
631       g.m_isImeCompositioning = false;\r
632       notifyLockState(4);\r
633       break;\r
634     default:\r
635       if (i_wParam == PM_REMOVE && msg.message == g.m_WM_MAYU_MESSAGE)\r
636       {\r
637         switch (msg.wParam)\r
638         {\r
639           case MayuMessage_notifyName:\r
640             notifyName(msg.hwnd);\r
641             break;\r
642           case MayuMessage_funcRecenter:\r
643             funcRecenter(msg.hwnd);\r
644             break;\r
645           case MayuMessage_funcSetImeStatus:\r
646             funcSetImeStatus(msg.hwnd, msg.lParam);\r
647             break;\r
648           case MayuMessage_funcSetImeString:\r
649             funcSetImeString(msg.hwnd, msg.lParam);\r
650             break;\r
651         }\r
652       }\r
653       break;\r
654   }\r
655  finally:\r
656   return CallNextHookEx(s_hookDataArch->m_hHookGetMessage,\r
657                         i_nCode, i_wParam, i_lParam);\r
658 }\r
659 \r
660 \r
661 /// hook of SendMessage\r
662 LRESULT CALLBACK callWndProc(int i_nCode, WPARAM i_wParam, LPARAM i_lParam)\r
663 {\r
664   if (!g.m_isInitialized)\r
665     initialize();\r
666 \r
667   if (!g_hookData)\r
668     return 0;\r
669   \r
670   CWPSTRUCT &cwps = *(CWPSTRUCT *)i_lParam;\r
671   \r
672   if (0 <= i_nCode)\r
673   {\r
674     switch (cwps.message)\r
675     {\r
676       case WM_ACTIVATEAPP:\r
677       case WM_NCACTIVATE:\r
678         if (i_wParam)\r
679           notifySetFocus();\r
680         break;\r
681       case WM_SYSCOMMAND:\r
682         switch (cwps.wParam)\r
683         {\r
684           case SC_MAXIMIZE:\r
685           case SC_MAXIMIZE2:\r
686             updateShow(cwps.hwnd, NotifyShow::Show_Maximized);\r
687             break;\r
688           case SC_MINIMIZE:\r
689           case SC_MINIMIZE2:\r
690             updateShow(cwps.hwnd, NotifyShow::Show_Minimized);\r
691             break;\r
692           case SC_RESTORE:\r
693           case SC_RESTORE2:\r
694             updateShow(cwps.hwnd, NotifyShow::Show_Normal);\r
695             break;\r
696           default:\r
697             break;\r
698         }\r
699         /* through below */\r
700       case WM_COMMAND:\r
701         notifyCommand(cwps.hwnd, cwps.message, cwps.wParam, cwps.lParam);\r
702         break;\r
703       case WM_SIZE:\r
704         switch (cwps.wParam)\r
705         {\r
706           case SIZE_MAXIMIZED:\r
707             updateShow(cwps.hwnd, NotifyShow::Show_Maximized);\r
708             break;\r
709           case SIZE_MINIMIZED:\r
710             updateShow(cwps.hwnd, NotifyShow::Show_Minimized);\r
711             break;\r
712           case SIZE_RESTORED:\r
713             updateShow(cwps.hwnd, NotifyShow::Show_Normal);\r
714             break;\r
715           default:\r
716             break;\r
717         }\r
718         break;\r
719       case WM_MOUSEACTIVATE:\r
720         notifySetFocus();\r
721         break;\r
722       case WM_ACTIVATE:\r
723         if (LOWORD(cwps.wParam) != WA_INACTIVE)\r
724         {\r
725           notifySetFocus();\r
726           if (HIWORD(cwps.wParam)) // check minimized flag\r
727           {\r
728             // minimized flag on\r
729             notifyShow(NotifyShow::Show_Minimized, false);\r
730             //notifyShow(NotifyShow::Show_Normal, true);\r
731           }\r
732         }\r
733         break;\r
734       case WM_ENTERMENULOOP:\r
735         g.m_isInMenu = true;\r
736         notifySetFocus(true);\r
737         break;\r
738       case WM_EXITMENULOOP:\r
739         g.m_isInMenu = false;\r
740         notifySetFocus(true);\r
741         break;\r
742       case WM_SETFOCUS:\r
743         g.m_isInMenu = false;\r
744         // for kana\r
745         if (g_hookData->m_correctKanaLockHandling) {\r
746           if (HIMC hIMC = ImmGetContext(cwps.hwnd)) {\r
747             bool status = !!ImmGetOpenStatus(hIMC);\r
748             // this code set the VK_KANA state correctly.\r
749             ImmSetOpenStatus(hIMC, !status);\r
750             ImmSetOpenStatus(hIMC, status);\r
751             ImmReleaseContext(cwps.hwnd, hIMC);\r
752           }\r
753         }\r
754         notifySetFocus();\r
755         notifyLockState(5);\r
756         break;\r
757       case WM_IME_STARTCOMPOSITION:\r
758         g.m_isImeCompositioning = true;\r
759         notifyLockState(6);\r
760         break;\r
761       case WM_IME_ENDCOMPOSITION:\r
762         g.m_isImeCompositioning = false;\r
763         notifyLockState(7);\r
764         break;\r
765       case WM_IME_NOTIFY:\r
766         if (cwps.wParam == IMN_SETOPENSTATUS)\r
767           if (HIMC hIMC = ImmGetContext(cwps.hwnd))\r
768           {\r
769             g.m_isImeLock = !!ImmGetOpenStatus(hIMC);\r
770             ImmReleaseContext(cwps.hwnd, hIMC);\r
771             notifyLockState(8);\r
772           }\r
773         break;\r
774     }\r
775   }\r
776   return CallNextHookEx(s_hookDataArch->m_hHookCallWndProc, i_nCode,\r
777                         i_wParam, i_lParam);\r
778 }\r
779 \r
780 \r
781 static LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)\r
782 {\r
783   MSLLHOOKSTRUCT *pMsll = (MSLLHOOKSTRUCT*)lParam;\r
784   LONG dx = pMsll->pt.x - g_hookData->m_mousePos.x;\r
785   LONG dy = pMsll->pt.y - g_hookData->m_mousePos.y;\r
786   HWND target = reinterpret_cast<HWND>(g_hookData->m_hwndMouseHookTarget);\r
787 \r
788   if (!g.m_isInitialized)\r
789     initialize();\r
790 \r
791   if (!g_hookData || nCode < 0 || wParam != WM_MOUSEMOVE)\r
792     goto through;\r
793 \r
794   switch (g_hookData->m_mouseHookType)\r
795   {\r
796     case MouseHookType_Wheel:\r
797       // For this type, g_hookData->m_mouseHookParam means\r
798       // translate rate mouse move to wheel.\r
799       mouse_event(MOUSEEVENTF_WHEEL, 0, 0,\r
800                   g_hookData->m_mouseHookParam * dy, 0);\r
801       return 1;\r
802       break;\r
803     case MouseHookType_WindowMove:\r
804     {\r
805       RECT curRect;\r
806 \r
807       if (!GetWindowRect(target, &curRect))\r
808         goto through;\r
809 \r
810       // g_hookData->m_mouseHookParam < 0 means\r
811       // target window to move is MDI.\r
812       if (g_hookData->m_mouseHookParam < 0)\r
813       {\r
814         HWND parent = GetParent(target);\r
815         POINT p = {curRect.left, curRect.top};\r
816 \r
817         if (parent == NULL || !ScreenToClient(parent, &p))\r
818           goto through;\r
819 \r
820         curRect.left = p.x;\r
821         curRect.top = p.y;\r
822       }\r
823         \r
824       SetWindowPos(target, NULL,\r
825                    curRect.left + dx,\r
826                    curRect.top + dy,\r
827                    0, 0,\r
828                    SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE |\r
829                    SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);\r
830       g_hookData->m_mousePos = pMsll->pt;\r
831       goto through;\r
832       break;\r
833     }\r
834     case MouseHookType_None:\r
835     default:\r
836       goto through;\r
837       break;\r
838   }\r
839     \r
840  through:\r
841   return CallNextHookEx(g.m_hHookMouseProc,\r
842                         nCode, wParam, lParam);\r
843 }\r
844 \r
845 \r
846 #ifdef NO_DRIVER\r
847 static LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)\r
848 {\r
849   KBDLLHOOKSTRUCT *pKbll = (KBDLLHOOKSTRUCT*)lParam;\r
850 \r
851   if (!g.m_isInitialized)\r
852     initialize();\r
853 \r
854   if (!g_hookData || nCode < 0)\r
855     goto through;\r
856 \r
857   if (g.m_keyboardDetour && g.m_engine)\r
858   {\r
859     unsigned int result;\r
860     result = g.m_keyboardDetour(g.m_engine, pKbll);\r
861     if (result)\r
862     {\r
863       return 1;\r
864     }\r
865   }\r
866  through:\r
867   return CallNextHookEx(g.m_hHookKeyboardProc,\r
868                         nCode, wParam, lParam);\r
869 }\r
870 #endif // NO_DRIVER\r
871 \r
872 \r
873 /// install hooks\r
874 DllExport int installHooks(KEYBOARD_DETOUR i_keyboardDetour, Engine *i_engine)\r
875 {\r
876   if (!g.m_isInitialized)\r
877     initialize();\r
878 \r
879   g.m_hwndTaskTray = g_hookData->m_hwndTaskTray;\r
880   s_hookDataArch->m_hHookGetMessage =\r
881     SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)getMessageProc,\r
882                      g.m_hInstDLL, 0);\r
883   s_hookDataArch->m_hHookCallWndProc =\r
884     SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)callWndProc, g.m_hInstDLL, 0);\r
885   g_hookData->m_mouseHookType = MouseHookType_None;\r
886   if (i_engine != NULL)\r
887   {\r
888 #ifdef NO_DRIVER\r
889     g.m_keyboardDetour = i_keyboardDetour;\r
890     g.m_engine = i_engine;\r
891     g.m_hHookKeyboardProc =\r
892       SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)lowLevelKeyboardProc,\r
893                        g.m_hInstDLL, 0);\r
894 #endif // NO_DRIVER\r
895     g.m_hHookMouseProc =\r
896       SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)lowLevelMouseProc,\r
897                        g.m_hInstDLL, 0);\r
898   }\r
899   return 0;\r
900 }\r
901 \r
902 \r
903 /// uninstall hooks\r
904 DllExport int uninstallHooks()\r
905 {\r
906   if (s_hookDataArch->m_hHookGetMessage)\r
907     UnhookWindowsHookEx(s_hookDataArch->m_hHookGetMessage);\r
908   s_hookDataArch->m_hHookGetMessage = NULL;\r
909   if (s_hookDataArch->m_hHookCallWndProc)\r
910     UnhookWindowsHookEx(s_hookDataArch->m_hHookCallWndProc);\r
911   s_hookDataArch->m_hHookCallWndProc = NULL;\r
912   if (g.m_hHookMouseProc)\r
913     UnhookWindowsHookEx(g.m_hHookMouseProc);\r
914   g.m_hHookMouseProc = NULL;\r
915 #ifdef NO_DRIVER\r
916   if (g.m_hHookKeyboardProc)\r
917     UnhookWindowsHookEx(g.m_hHookKeyboardProc);\r
918   g.m_hHookKeyboardProc = NULL;\r
919 #endif // NO_DRIVER\r
920   g.m_hwndTaskTray = 0;\r
921   return 0;\r
922 }\r