OSDN Git Service

fe7f9598faf289a084c64aea60c759e65f406970
[yamy/yamy.git] / engine.cpp
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
2 // engine.cpp\r
3 \r
4 \r
5 #include "misc.h"\r
6 \r
7 #include "engine.h"\r
8 #include "errormessage.h"\r
9 #include "hook.h"\r
10 #include "mayurc.h"\r
11 #include "windowstool.h"\r
12 \r
13 #include <iomanip>\r
14 \r
15 #include <process.h>\r
16 \r
17 \r
18 // check focus window\r
19 void Engine::checkFocusWindow()\r
20 {\r
21   int count = 0;\r
22   \r
23   restart:\r
24   count ++;\r
25   \r
26   HWND hwndFore = GetForegroundWindow();\r
27   DWORD threadId = GetWindowThreadProcessId(hwndFore, NULL);\r
28 \r
29   if (hwndFore)\r
30   {\r
31     {\r
32       Acquire a(&m_cs);\r
33       if (m_currentFocusOfThread &&\r
34           m_currentFocusOfThread->m_threadId == threadId &&\r
35           m_currentFocusOfThread->m_hwndFocus == m_hwndFocus)\r
36         return;\r
37 \r
38       m_emacsEditKillLine.reset();\r
39       \r
40       // erase dead thread\r
41       if (!m_detachedThreadIds.empty())\r
42       {\r
43         for (DetachedThreadIds::iterator i = m_detachedThreadIds.begin();\r
44              i != m_detachedThreadIds.end(); i ++)\r
45         {\r
46           FocusOfThreads::iterator j = m_focusOfThreads.find((*i));\r
47           if (j != m_focusOfThreads.end())\r
48           {\r
49             FocusOfThread *fot = &((*j).second);\r
50             Acquire a(&m_log, 1);\r
51             m_log << _T("RemoveThread") << std::endl;\r
52             m_log << _T("\tHWND:\t") << std::hex << (int)fot->m_hwndFocus\r
53                   << std::dec << std::endl;\r
54             m_log << _T("\tTHREADID:") << fot->m_threadId << std::endl;\r
55             m_log << _T("\tCLASS:\t") << fot->m_className << std::endl;\r
56             m_log << _T("\tTITLE:\t") << fot->m_titleName << std::endl;\r
57             m_log << std::endl;\r
58             m_focusOfThreads.erase(j);\r
59           }\r
60         }\r
61         m_detachedThreadIds.erase\r
62           (m_detachedThreadIds.begin(), m_detachedThreadIds.end());\r
63       }\r
64       \r
65       FocusOfThreads::iterator i = m_focusOfThreads.find(threadId);\r
66       if (i != m_focusOfThreads.end())\r
67       {\r
68         m_currentFocusOfThread = &((*i).second);\r
69         if (!m_currentFocusOfThread->m_isConsole || 2 <= count)\r
70         {\r
71           if (m_currentFocusOfThread->m_keymaps.empty())\r
72             setCurrentKeymap(NULL);\r
73           else\r
74             setCurrentKeymap(*m_currentFocusOfThread->m_keymaps.begin());\r
75           m_hwndFocus = m_currentFocusOfThread->m_hwndFocus;\r
76           checkShow(m_hwndFocus);\r
77         \r
78           Acquire a(&m_log, 1);\r
79           m_log << _T("FocusChanged") << std::endl;\r
80           m_log << _T("\tHWND:\t")\r
81                 << std::hex << (int)m_currentFocusOfThread->m_hwndFocus\r
82                 << std::dec << std::endl;\r
83           m_log << _T("\tTHREADID:")\r
84                 << m_currentFocusOfThread->m_threadId << std::endl;\r
85           m_log << _T("\tCLASS:\t")\r
86                 << m_currentFocusOfThread->m_className << std::endl;\r
87           m_log << _T("\tTITLE:\t")\r
88                 << m_currentFocusOfThread->m_titleName << std::endl;\r
89           m_log << std::endl;\r
90           return;\r
91         }\r
92       }\r
93     }\r
94     \r
95     _TCHAR className[GANA_MAX_ATOM_LENGTH];\r
96     if (GetClassName(hwndFore, className, NUMBER_OF(className)))\r
97     {\r
98       if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0)\r
99       {\r
100         _TCHAR titleName[1024];\r
101         if (GetWindowText(hwndFore, titleName, NUMBER_OF(titleName)) == 0)\r
102           titleName[0] = _T('\0');\r
103         setFocus(hwndFore, threadId, className, titleName, true);\r
104         Acquire a(&m_log, 1);\r
105         m_log << _T("HWND:\t") << std::hex << reinterpret_cast<int>(hwndFore)\r
106               << std::dec << std::endl;\r
107         m_log << _T("THREADID:") << threadId << std::endl;\r
108         m_log << _T("CLASS:\t") << className << std::endl;\r
109         m_log << _T("TITLE:\t") << titleName << std::endl << std::endl;\r
110         goto restart;\r
111       }\r
112     }\r
113   }\r
114   \r
115   Acquire a(&m_cs);\r
116   if (m_globalFocus.m_keymaps.empty())\r
117   {\r
118     Acquire a(&m_log, 1);\r
119     m_log << _T("NO GLOBAL FOCUS") << std::endl;\r
120     m_currentFocusOfThread = NULL;\r
121     setCurrentKeymap(NULL);\r
122   }\r
123   else\r
124   {\r
125     if (m_currentFocusOfThread != &m_globalFocus)\r
126     {\r
127       Acquire a(&m_log, 1);\r
128       m_log << _T("GLOBAL FOCUS") << std::endl;\r
129       m_currentFocusOfThread = &m_globalFocus;\r
130       setCurrentKeymap(m_globalFocus.m_keymaps.front());\r
131     }\r
132   }\r
133   m_hwndFocus = NULL;\r
134 }\r
135 \r
136 \r
137 \r
138 // is modifier pressed ?\r
139 bool Engine::isPressed(Modifier::Type i_mt)\r
140 {\r
141   const Keymap::ModAssignments &ma = m_currentKeymap->getModAssignments(i_mt);\r
142   for (Keymap::ModAssignments::const_iterator i = ma.begin();\r
143        i != ma.end(); ++ i)\r
144     if ((*i).m_key->m_isPressed)\r
145       return true;\r
146   return false;\r
147 }\r
148 \r
149 \r
150 // fix modifier key (if fixed, return true)\r
151 bool Engine::fixModifierKey(ModifiedKey *io_mkey, Keymap::AssignMode *o_am)\r
152 {\r
153   // for all modifier ...\r
154   for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i)\r
155   {\r
156     // get modifier assignments (list of modifier keys)\r
157     const Keymap::ModAssignments &ma =\r
158       m_currentKeymap->getModAssignments(static_cast<Modifier::Type>(i));\r
159     \r
160     for (Keymap::ModAssignments::const_iterator\r
161            j = ma.begin(); j != ma.end(); ++ j)\r
162       if (io_mkey->m_key == (*j).m_key) // is io_mkey a modifier ?\r
163       {\r
164         {\r
165           Acquire a(&m_log, 1);\r
166           m_log << _T("* Modifier Key") << std::endl;\r
167         }\r
168         // set dontcare for this modifier\r
169         io_mkey->m_modifier.dontcare(static_cast<Modifier::Type>(i));\r
170         *o_am = (*j).m_assignMode;\r
171         return true;\r
172       }\r
173   }\r
174   *o_am = Keymap::AM_notModifier;\r
175   return false;\r
176 }\r
177 \r
178 \r
179 // output to m_log\r
180 void Engine::outputToLog(const Key *i_key, const ModifiedKey &i_mkey,\r
181                          int i_debugLevel)\r
182 {\r
183   size_t i;\r
184   Acquire a(&m_log, i_debugLevel);\r
185 \r
186   // output scan codes\r
187   for (i = 0; i < i_key->getScanCodesSize(); ++ i)\r
188   {\r
189     if (i_key->getScanCodes()[i].m_flags & ScanCode::E0) m_log << _T("E0-");\r
190     if (i_key->getScanCodes()[i].m_flags & ScanCode::E1) m_log << _T("E1-");\r
191     if (!(i_key->getScanCodes()[i].m_flags & ScanCode::E0E1))\r
192       m_log << _T("   ");\r
193     m_log << _T("0x") << std::hex << std::setw(2) << std::setfill(_T('0'))\r
194           << static_cast<int>(i_key->getScanCodes()[i].m_scan)\r
195           << std::dec << _T(" ");\r
196   }\r
197   \r
198   if (!i_mkey.m_key) // key corresponds to no phisical key\r
199   {\r
200     m_log << std::endl;\r
201     return;\r
202   }\r
203   \r
204   m_log << _T("  ") << i_mkey << std::endl;\r
205 }\r
206 \r
207 \r
208 // describe bindings\r
209 void Engine::describeBindings()\r
210 {\r
211   Acquire a(&m_log, 0);\r
212 \r
213   Keymap::DescribeParam dp;\r
214   for (KeymapPtrList::iterator i = m_currentFocusOfThread->m_keymaps.begin();\r
215        i != m_currentFocusOfThread->m_keymaps.end(); ++ i)\r
216     (*i)->describe(m_log, &dp);\r
217   m_log << std::endl;\r
218 }\r
219 \r
220 \r
221 // update m_lastPressedKey\r
222 void Engine::updateLastPressedKey(Key *i_key)\r
223 {\r
224   m_lastPressedKey[1] = m_lastPressedKey[0];\r
225   m_lastPressedKey[0] = i_key;\r
226 }\r
227 \r
228 // set current keymap\r
229 void Engine::setCurrentKeymap(const Keymap *i_keymap, bool i_doesAddToHistory)\r
230 {\r
231   if (i_doesAddToHistory)\r
232   {\r
233     m_keymapPrefixHistory.push_back(const_cast<Keymap *>(m_currentKeymap));\r
234     if (MAX_KEYMAP_PREFIX_HISTORY < m_keymapPrefixHistory.size())\r
235       m_keymapPrefixHistory.pop_front();\r
236   }\r
237   else\r
238     m_keymapPrefixHistory.clear();\r
239   m_currentKeymap = i_keymap;\r
240 }\r
241 \r
242 \r
243 // get current modifiers\r
244 Modifier Engine::getCurrentModifiers(Key *i_key, bool i_isPressed)\r
245 {\r
246   Modifier cmods;\r
247   cmods.add(m_currentLock);\r
248 \r
249   cmods.press(Modifier::Type_Shift  , isPressed(Modifier::Type_Shift  ));\r
250   cmods.press(Modifier::Type_Alt    , isPressed(Modifier::Type_Alt    ));\r
251   cmods.press(Modifier::Type_Control, isPressed(Modifier::Type_Control));\r
252   cmods.press(Modifier::Type_Windows, isPressed(Modifier::Type_Windows));\r
253   cmods.press(Modifier::Type_Up     , !i_isPressed);\r
254   cmods.press(Modifier::Type_Down   , i_isPressed);\r
255 \r
256   cmods.press(Modifier::Type_Repeat , false);\r
257   if (m_lastPressedKey[0] == i_key)\r
258   {\r
259     if (i_isPressed)\r
260       cmods.press(Modifier::Type_Repeat, true);\r
261     else\r
262       if (m_lastPressedKey[1] == i_key)\r
263         cmods.press(Modifier::Type_Repeat, true);\r
264   }\r
265 \r
266   for (int i = Modifier::Type_Mod0; i <= Modifier::Type_Mod9; ++ i)\r
267     cmods.press(static_cast<Modifier::Type>(i),\r
268                 isPressed(static_cast<Modifier::Type>(i)));\r
269   \r
270   return cmods;\r
271 }\r
272 \r
273 \r
274 // generate keyboard event for a key\r
275 void Engine::generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign)\r
276 {\r
277   // check if key is event\r
278   bool isEvent = false;\r
279   for (Key **e = Event::events; *e; ++ e)\r
280     if (*e == i_key)\r
281     {\r
282       isEvent = true;\r
283       break;\r
284     }\r
285 \r
286   bool isAlreadyReleased = false;\r
287     \r
288   if (!isEvent)\r
289   {\r
290     if (i_doPress && !i_key->m_isPressedOnWin32)\r
291       ++ m_currentKeyPressCountOnWin32;\r
292     else if (!i_doPress)\r
293     {\r
294       if (i_key->m_isPressedOnWin32)\r
295         -- m_currentKeyPressCountOnWin32;\r
296       else\r
297         isAlreadyReleased = true;\r
298     }\r
299     i_key->m_isPressedOnWin32 = i_doPress;\r
300     \r
301     if (i_isByAssign)\r
302       i_key->m_isPressedByAssign = i_doPress;\r
303 \r
304     Key *sync = m_setting->m_keyboard.getSyncKey();\r
305     \r
306     if (!isAlreadyReleased || i_key == sync)\r
307     {\r
308       KEYBOARD_INPUT_DATA kid = { 0, 0, 0, 0, 0 };\r
309       const ScanCode *sc = i_key->getScanCodes();\r
310       for (size_t i = 0; i < i_key->getScanCodesSize(); ++ i)\r
311       {\r
312         kid.MakeCode = sc[i].m_scan;\r
313         kid.Flags = sc[i].m_flags;\r
314         if (!i_doPress)\r
315           kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
316 #ifdef NO_DRIVER\r
317         injectInput(&kid, NULL);\r
318 #else // !NO_DRIVER\r
319         DWORD len;\r
320         WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
321         CHECK_TRUE( GetOverlappedResult(m_device, &m_ol, &len, TRUE) );\r
322 #endif // !NO_DRIVER\r
323       }\r
324       \r
325       m_lastGeneratedKey = i_doPress ? i_key : NULL;\r
326     }\r
327   }\r
328   \r
329   {\r
330     Acquire a(&m_log, 1);\r
331     m_log << _T("\t\t    =>\t");\r
332     if (isAlreadyReleased)\r
333       m_log << _T("(already released) ");\r
334   }\r
335   ModifiedKey mkey(i_key);\r
336   mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);\r
337   mkey.m_modifier.on(Modifier::Type_Down, i_doPress);\r
338   outputToLog(i_key, mkey, 1);\r
339 }\r
340 \r
341 \r
342 // genete event\r
343 void Engine::generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event)\r
344 {\r
345   // generate\r
346   i_c.m_keymap = i_keymap;\r
347   i_c.m_mkey.m_key = i_event;\r
348   if (const Keymap::KeyAssignment *keyAssign =\r
349       i_c.m_keymap->searchAssignment(i_c.m_mkey))\r
350   {\r
351     {\r
352       Acquire a(&m_log, 1);\r
353       m_log << std::endl << _T("           ")\r
354             << i_event->getName() << std::endl;\r
355     }\r
356     generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);\r
357   }\r
358 }\r
359 \r
360 \r
361 // genete modifier events\r
362 void Engine::generateModifierEvents(const Modifier &i_mod)\r
363 {\r
364   {\r
365     Acquire a(&m_log, 1);\r
366     m_log << _T("* Gen Modifiers\t{") << std::endl;\r
367   }\r
368 \r
369   for (int i = Modifier::Type_begin; i < Modifier::Type_BASIC; ++ i)\r
370   {\r
371     Keyboard::Mods &mods =\r
372       m_setting->m_keyboard.getModifiers(static_cast<Modifier::Type>(i));\r
373 \r
374     if (i_mod.isDontcare(static_cast<Modifier::Type>(i)))\r
375       // no need to process\r
376       ;\r
377     else if (i_mod.isPressed(static_cast<Modifier::Type>(i)))\r
378       // we have to press this modifier\r
379     {\r
380       bool noneIsPressed = true;\r
381       bool noneIsPressedByAssign = true;\r
382       for (Keyboard::Mods::iterator i = mods.begin(); i != mods.end(); ++ i)\r
383       {\r
384         if ((*i)->m_isPressedOnWin32)\r
385           noneIsPressed = false;\r
386         if ((*i)->m_isPressedByAssign)\r
387           noneIsPressedByAssign = false;\r
388       }\r
389       if (noneIsPressed)\r
390       {\r
391         if (noneIsPressedByAssign)\r
392           generateKeyEvent(mods.front(), true, false);\r
393         else\r
394           for (Keyboard::Mods::iterator\r
395                  i = mods.begin(); i != mods.end(); ++ i)\r
396             if ((*i)->m_isPressedByAssign)\r
397               generateKeyEvent((*i), true, false);\r
398       }\r
399     }\r
400 \r
401     else\r
402       // we have to release this modifier\r
403     {\r
404       // avoid such sequences as  "Alt U-ALt" or "Windows U-Windows"\r
405       if (i == Modifier::Type_Alt || i == Modifier::Type_Windows)\r
406       {\r
407         for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)\r
408           if ((*j) == m_lastGeneratedKey)\r
409           {\r
410             Keyboard::Mods *mods =\r
411               &m_setting->m_keyboard.getModifiers(Modifier::Type_Shift);\r
412             if (mods->size() == 0)\r
413               mods = &m_setting->m_keyboard.getModifiers(\r
414                 Modifier::Type_Control);\r
415             if (0 < mods->size())\r
416             {\r
417               generateKeyEvent(mods->front(), true, false);\r
418               generateKeyEvent(mods->front(), false, false);\r
419             }\r
420             break;\r
421           }\r
422       }\r
423       \r
424       for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)\r
425       {\r
426         if ((*j)->m_isPressedOnWin32)\r
427           generateKeyEvent((*j), false, false);\r
428       }\r
429     }\r
430   }\r
431   \r
432   {\r
433     Acquire a(&m_log, 1);\r
434     m_log << _T("\t\t}") << std::endl;\r
435   }\r
436 }\r
437 \r
438 \r
439 // generate keyboard events for action\r
440 void Engine::generateActionEvents(const Current &i_c, const Action *i_a,\r
441                                   bool i_doPress)\r
442 {\r
443   switch (i_a->getType())\r
444   {\r
445     // key\r
446     case Action::Type_key:\r
447     {\r
448       const ModifiedKey &mkey\r
449         = reinterpret_cast<ActionKey *>(\r
450           const_cast<Action *>(i_a))->m_modifiedKey;\r
451 \r
452       // release\r
453       if (!i_doPress &&\r
454           (mkey.m_modifier.isOn(Modifier::Type_Up) ||\r
455            mkey.m_modifier.isDontcare(Modifier::Type_Up)))\r
456         generateKeyEvent(mkey.m_key, false, true);\r
457 \r
458       // press\r
459       else if (i_doPress &&\r
460                (mkey.m_modifier.isOn(Modifier::Type_Down) ||\r
461                 mkey.m_modifier.isDontcare(Modifier::Type_Down)))\r
462       {\r
463         Modifier modifier = mkey.m_modifier;\r
464         modifier.add(i_c.m_mkey.m_modifier);\r
465         generateModifierEvents(modifier);\r
466         generateKeyEvent(mkey.m_key, true, true);\r
467       }\r
468       break;\r
469     }\r
470 \r
471     // keyseq\r
472     case Action::Type_keySeq:\r
473     {\r
474       const ActionKeySeq *aks = reinterpret_cast<const ActionKeySeq *>(i_a);\r
475       generateKeySeqEvents(i_c, aks->m_keySeq,\r
476                            i_doPress ? Part_down : Part_up);\r
477       break;\r
478     }\r
479 \r
480     // function\r
481     case Action::Type_function:\r
482     {\r
483       const ActionFunction *af = reinterpret_cast<const ActionFunction *>(i_a);\r
484       bool is_up = (!i_doPress &&\r
485                     (af->m_modifier.isOn(Modifier::Type_Up) ||\r
486                      af->m_modifier.isDontcare(Modifier::Type_Up)));\r
487       bool is_down = (i_doPress &&\r
488                       (af->m_modifier.isOn(Modifier::Type_Down) ||\r
489                        af->m_modifier.isDontcare(Modifier::Type_Down)));\r
490 \r
491       if (!is_down && !is_up)\r
492         break;\r
493       \r
494       {\r
495         Acquire a(&m_log, 1);\r
496         m_log << _T("\t\t     >\t") << af->m_functionData;\r
497       }\r
498       \r
499       FunctionParam param;\r
500       param.m_isPressed = i_doPress;\r
501       param.m_hwnd = m_currentFocusOfThread->m_hwndFocus;\r
502       param.m_c = i_c;\r
503       param.m_doesNeedEndl = true;\r
504       param.m_af = af;\r
505       \r
506       param.m_c.m_mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);\r
507       param.m_c.m_mkey.m_modifier.on(Modifier::Type_Down, i_doPress);\r
508 \r
509       af->m_functionData->exec(this, &param);\r
510       \r
511       if (param.m_doesNeedEndl)\r
512       {\r
513         Acquire a(&m_log, 1);\r
514         m_log << std::endl;\r
515       }\r
516       break;\r
517     }\r
518   }\r
519 }\r
520 \r
521 \r
522 // generate keyboard events for keySeq\r
523 void Engine::generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,\r
524                                   Part i_part)\r
525 {\r
526   const KeySeq::Actions &actions = i_keySeq->getActions();\r
527   if (actions.empty())\r
528     return;\r
529   if (i_part == Part_up)\r
530     generateActionEvents(i_c, actions[actions.size() - 1], false);\r
531   else\r
532   {\r
533     size_t i;\r
534     for (i = 0 ; i < actions.size() - 1; ++ i)\r
535     {\r
536       generateActionEvents(i_c, actions[i], true);\r
537       generateActionEvents(i_c, actions[i], false);\r
538     }\r
539     generateActionEvents(i_c, actions[i], true);\r
540     if (i_part == Part_all)\r
541       generateActionEvents(i_c, actions[i], false);\r
542   }\r
543 }\r
544 \r
545 \r
546 // generate keyboard events for current key\r
547 void Engine::generateKeyboardEvents(const Current &i_c)\r
548 {\r
549   if (++ m_generateKeyboardEventsRecursionGuard ==\r
550       MAX_GENERATE_KEYBOARD_EVENTS_RECURSION_COUNT)\r
551   {\r
552     Acquire a(&m_log);\r
553     m_log << _T("error: too deep keymap recursion.  there may be a loop.")\r
554           << std::endl;\r
555     return;\r
556   }\r
557 \r
558   const Keymap::KeyAssignment *keyAssign\r
559     = i_c.m_keymap->searchAssignment(i_c.m_mkey);\r
560   if (!keyAssign)\r
561   {\r
562     const KeySeq *keySeq = i_c.m_keymap->getDefaultKeySeq();\r
563     ASSERT( keySeq );\r
564     generateKeySeqEvents(i_c, keySeq, i_c.isPressed() ? Part_down : Part_up);\r
565   }\r
566   else\r
567   {\r
568     if (keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Up) ||\r
569         keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Down))\r
570       generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);\r
571     else\r
572       generateKeySeqEvents(i_c, keyAssign->m_keySeq,\r
573                            i_c.isPressed() ? Part_down : Part_up);\r
574   }\r
575   m_generateKeyboardEventsRecursionGuard --;\r
576 }\r
577 \r
578 \r
579 // generate keyboard events for current key\r
580 void Engine::beginGeneratingKeyboardEvents(\r
581   const Current &i_c, bool i_isModifier)\r
582 {\r
583   //             (1)             (2)             (3)  (4)   (1)\r
584   // up/down:    D-              U-              D-   U-    D-\r
585   // keymap:     m_currentKeymap m_currentKeymap X    X     m_currentKeymap\r
586   // memo:       &Prefix(X)      ...             ...  ...   ...\r
587   // m_isPrefix: false           true            true false false\r
588 \r
589   Current cnew(i_c);\r
590 \r
591   bool isPhysicallyPressed\r
592     = cnew.m_mkey.m_modifier.isPressed(Modifier::Type_Down);\r
593   \r
594   // substitute\r
595   ModifiedKey mkey = m_setting->m_keyboard.searchSubstitute(cnew.m_mkey);\r
596   if (mkey.m_key)\r
597   {\r
598     cnew.m_mkey = mkey;\r
599     if (isPhysicallyPressed)\r
600     {\r
601       cnew.m_mkey.m_modifier.off(Modifier::Type_Up);\r
602       cnew.m_mkey.m_modifier.on(Modifier::Type_Down);\r
603     }\r
604     else\r
605     {\r
606       cnew.m_mkey.m_modifier.on(Modifier::Type_Up);\r
607       cnew.m_mkey.m_modifier.off(Modifier::Type_Down);\r
608     }\r
609     for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i)\r
610     {\r
611       Modifier::Type type = static_cast<Modifier::Type>(i);\r
612       if (cnew.m_mkey.m_modifier.isDontcare(type) &&\r
613           !i_c.m_mkey.m_modifier.isDontcare(type))\r
614         cnew.m_mkey.m_modifier.press(\r
615           type, i_c.m_mkey.m_modifier.isPressed(type));\r
616     }\r
617     \r
618     {\r
619       Acquire a(&m_log, 1);\r
620       m_log << _T("* substitute") << std::endl;\r
621     }\r
622     outputToLog(mkey.m_key, cnew.m_mkey, 1);\r
623   }\r
624   \r
625   // for prefix key\r
626   const Keymap *tmpKeymap = m_currentKeymap;\r
627   if (i_isModifier || !m_isPrefix) ; \r
628   else if (isPhysicallyPressed)                 // when (3)\r
629     m_isPrefix = false;\r
630   else if (!isPhysicallyPressed)                // when (2)\r
631     m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();\r
632   \r
633   // for m_emacsEditKillLine function\r
634   m_emacsEditKillLine.m_doForceReset = !i_isModifier;\r
635 \r
636   // generate key event !\r
637   m_generateKeyboardEventsRecursionGuard = 0;\r
638   if (isPhysicallyPressed)\r
639     generateEvents(cnew, cnew.m_keymap, &Event::before_key_down);\r
640   generateKeyboardEvents(cnew);\r
641   if (!isPhysicallyPressed)\r
642     generateEvents(cnew, cnew.m_keymap, &Event::after_key_up);\r
643       \r
644   // for m_emacsEditKillLine function\r
645   if (m_emacsEditKillLine.m_doForceReset)\r
646     m_emacsEditKillLine.reset();\r
647 \r
648   // for prefix key\r
649   if (i_isModifier)\r
650     ;\r
651   else if (!m_isPrefix)                         // when (1), (4)\r
652     m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();\r
653   else if (!isPhysicallyPressed)                // when (2)\r
654     m_currentKeymap = tmpKeymap;\r
655 }\r
656 \r
657 \r
658 #ifdef NO_DRIVER\r
659 unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw)\r
660 {\r
661   INPUT kid;\r
662   kid.type = INPUT_KEYBOARD;\r
663   kid.ki.wVk = 0;\r
664   kid.ki.wScan = i_kid->MakeCode;\r
665   kid.ki.dwFlags = KEYEVENTF_SCANCODE;\r
666   kid.ki.time = i_kidRaw ? i_kidRaw->time : 0;\r
667   kid.ki.dwExtraInfo = i_kidRaw ? i_kidRaw->dwExtraInfo : 0;\r
668   if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK)\r
669   {\r
670     kid.ki.dwFlags |= KEYEVENTF_KEYUP;\r
671   }\r
672   if (i_kid->Flags & KEYBOARD_INPUT_DATA::E0)\r
673   {\r
674     kid.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
675   }\r
676   SendInput(1, &kid, sizeof(kid));\r
677   return 1;\r
678 }\r
679 #endif // NO_DRIVER\r
680 \r
681 \r
682 // pop all pressed key on win32\r
683 void Engine::keyboardResetOnWin32()\r
684 {\r
685   for (Keyboard::KeyIterator\r
686          i = m_setting->m_keyboard.getKeyIterator();  *i; ++ i)\r
687   {\r
688     if ((*i)->m_isPressedOnWin32)\r
689       generateKeyEvent((*i), false, true);\r
690   }\r
691 }\r
692 \r
693 \r
694 #ifdef NO_DRIVER\r
695 unsigned int WINAPI Engine::keyboardDetour(Engine *i_this, KBDLLHOOKSTRUCT *i_kid)\r
696 {\r
697   return i_this->keyboardDetour(i_kid);\r
698 }\r
699 \r
700 unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)\r
701 {\r
702 #if 0\r
703   Acquire a(&m_log, 1);\r
704   m_log << std::hex\r
705         << _T("keyboardDetour: vkCode=") << i_kid->vkCode\r
706         << _T(" scanCode=") << i_kid->scanCode\r
707         << _T(" flags=") << i_kid->flags << std::endl;\r
708 #endif\r
709   if (i_kid->flags & LLKHF_INJECTED)\r
710   {\r
711     return 0;\r
712   }\r
713   else\r
714   {\r
715     Key key;\r
716     KEYBOARD_INPUT_DATA kid;\r
717 \r
718     kid.UnitId = 0;\r
719     kid.MakeCode = i_kid->scanCode;\r
720     kid.Flags = 0;\r
721     if (i_kid->flags & LLKHF_UP)\r
722     {\r
723       kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
724     }\r
725     if (i_kid->flags & LLKHF_EXTENDED)\r
726     {\r
727           kid.Flags |= KEYBOARD_INPUT_DATA::E0;\r
728     }\r
729     kid.Reserved = 0;\r
730     kid.ExtraInformation = 0;\r
731 \r
732     Acquire a(&m_cskidq);\r
733     m_kidq.push_back(kid);\r
734     SetEvent(m_readEvent);\r
735     return 1;\r
736   }\r
737 }\r
738 #endif // NO_DRIVER\r
739 \r
740 // keyboard handler thread\r
741 unsigned int WINAPI Engine::keyboardHandler(void *i_this)\r
742 {\r
743   reinterpret_cast<Engine *>(i_this)->keyboardHandler();\r
744   _endthreadex(0);\r
745   return 0;\r
746 }\r
747 void Engine::keyboardHandler()\r
748 {\r
749   // initialize ok\r
750   CHECK_TRUE( SetEvent(m_threadEvent) );\r
751     \r
752   // loop\r
753   Key key;\r
754   while (!m_doForceTerminate)\r
755   {\r
756     KEYBOARD_INPUT_DATA kid;\r
757     \r
758 #ifndef NO_DRIVER\r
759     DWORD len;\r
760 #endif // !NO_DRIVER\r
761     {\r
762       Acquire a(&m_log, 1);\r
763       m_log << _T("begin ReadFile();") << std::endl;\r
764     }\r
765 #ifdef NO_DRIVER\r
766     if (1)\r
767     {\r
768 #else // !NO_DRIVER\r
769     if (!ReadFile(m_device, &kid, sizeof(kid), &len, &m_ol))\r
770     {\r
771       if (GetLastError() != ERROR_IO_PENDING)\r
772         continue;\r
773 #endif // !NO_DRIVER\r
774       \r
775       HANDLE handles[] = { m_readEvent, m_interruptThreadEvent };\r
776     rewait:\r
777       switch (MsgWaitForMultipleObjects(NUMBER_OF(handles), &handles[0],\r
778                                      FALSE, INFINITE, QS_POSTMESSAGE))\r
779       {\r
780         case WAIT_OBJECT_0:                     // m_readEvent\r
781 #ifdef NO_DRIVER\r
782         {\r
783           Acquire a(&m_cskidq);\r
784           if (m_kidq.empty())\r
785           {\r
786             goto rewait;\r
787           }\r
788           kid = m_kidq.front();\r
789           m_kidq.pop_front();\r
790           if (!m_kidq.empty())\r
791           {\r
792             SetEvent(m_readEvent);\r
793           }\r
794         }\r
795 #else // !NO_DRIVER\r
796           if (!GetOverlappedResult(m_device, &m_ol, &len, FALSE))\r
797             continue;\r
798 #endif // !NO_DRIVER\r
799           break;\r
800           \r
801         case WAIT_OBJECT_0 + 1:                 // m_interruptThreadEvent\r
802           CancelIo(m_device);\r
803           switch (m_interruptThreadReason) {\r
804             default: {\r
805               ASSERT( false );\r
806               Acquire a(&m_log, 0);\r
807               m_log << _T("internal error: m_interruptThreadReason == ")\r
808                     << m_interruptThreadReason << std::endl;\r
809               break;\r
810             }\r
811               \r
812             case InterruptThreadReason_Terminate:\r
813               goto break_while;\r
814               \r
815             case InterruptThreadReason_Pause: {\r
816               CHECK_TRUE( SetEvent(m_threadEvent) );\r
817               while (WaitForMultipleObjects(1, &m_interruptThreadEvent,\r
818                                             FALSE, INFINITE) != WAIT_OBJECT_0)\r
819                 ;\r
820               switch (m_interruptThreadReason) {\r
821                 case InterruptThreadReason_Terminate:\r
822                   goto break_while;\r
823 \r
824                 case InterruptThreadReason_Resume:\r
825                   break;\r
826 \r
827                 default:\r
828                   ASSERT( false );\r
829                   break;\r
830               }\r
831               CHECK_TRUE( SetEvent(m_threadEvent) );\r
832               break;\r
833             }\r
834           }\r
835           break;\r
836           \r
837         case WAIT_OBJECT_0 + NUMBER_OF(handles):\r
838         {\r
839           MSG message;\r
840 \r
841           while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))\r
842           {\r
843             switch (message.message)\r
844             {\r
845               case WM_APP + 201:\r
846               {\r
847                 if (message.wParam)\r
848                 {\r
849                   m_currentLock.on(Modifier::Type_Touchpad);\r
850                   m_currentLock.on(Modifier::Type_TouchpadSticky);\r
851                 }\r
852                 else\r
853                   m_currentLock.off(Modifier::Type_Touchpad);\r
854                 Acquire a(&m_log, 1);\r
855                 m_log << _T("touchpad: ") << message.wParam\r
856                       << _T(".") << (message.lParam & 0xffff)\r
857                       << _T(".") << (message.lParam >> 16 & 0xffff)\r
858                       << std::endl;\r
859                 break;\r
860               }\r
861               default:\r
862                 break;\r
863             }\r
864           }\r
865           goto rewait;\r
866         }\r
867 \r
868         default:\r
869           ASSERT( false );\r
870           continue;\r
871       }\r
872     }\r
873     {\r
874       Acquire a(&m_log, 1);\r
875       m_log << _T("end ReadFile();") << std::endl;\r
876     }\r
877 \r
878     checkFocusWindow();\r
879 \r
880     if (!m_setting ||   // m_setting has not been loaded\r
881         !m_isEnabled)   // disabled\r
882     {\r
883       if (m_isLogMode)\r
884       {\r
885         Key key;\r
886         key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));\r
887         outputToLog(&key, ModifiedKey(), 0);\r
888       }\r
889       else\r
890       {\r
891 #ifdef NO_DRIVER\r
892         injectInput(&kid, NULL);\r
893 #else // !NO_DRIVER\r
894         WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
895         GetOverlappedResult(m_device, &m_ol, &len, TRUE);\r
896 #endif // !NO_DRIVER\r
897       }\r
898       updateLastPressedKey(NULL);\r
899       continue;\r
900     }\r
901     \r
902     Acquire a(&m_cs);\r
903 \r
904     if (!m_currentFocusOfThread ||\r
905         !m_currentKeymap)\r
906     {\r
907 #ifndef NO_DRIVER\r
908       WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
909       GetOverlappedResult(m_device, &m_ol, &len, TRUE);\r
910 #endif // !NO_DRIVER\r
911       Acquire a(&m_log, 0);\r
912       if (!m_currentFocusOfThread)\r
913         m_log << _T("internal error: m_currentFocusOfThread == NULL")\r
914               << std::endl;\r
915       if (!m_currentKeymap)\r
916         m_log << _T("internal error: m_currentKeymap == NULL")\r
917               << std::endl;\r
918       updateLastPressedKey(NULL);\r
919       continue;\r
920     }\r
921     \r
922     Current c;\r
923     c.m_keymap = m_currentKeymap;\r
924     c.m_i = m_currentFocusOfThread->m_keymaps.begin();\r
925     \r
926     // search key\r
927     key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));\r
928     c.m_mkey = m_setting->m_keyboard.searchKey(key);\r
929     if (!c.m_mkey.m_key)\r
930     {\r
931       c.m_mkey.m_key = m_setting->m_keyboard.searchPrefixKey(key);\r
932       if (c.m_mkey.m_key)\r
933         continue;\r
934     }\r
935 \r
936     // press the key and update counter\r
937     bool isPhysicallyPressed\r
938       = !(key.getScanCodes()[0].m_flags & ScanCode::BREAK);\r
939     if (c.m_mkey.m_key)\r
940     {\r
941       if (!c.m_mkey.m_key->m_isPressed && isPhysicallyPressed)\r
942         ++ m_currentKeyPressCount;\r
943       else if (c.m_mkey.m_key->m_isPressed && !isPhysicallyPressed)\r
944         -- m_currentKeyPressCount;\r
945       c.m_mkey.m_key->m_isPressed = isPhysicallyPressed;\r
946     }\r
947     \r
948     // create modifiers\r
949     c.m_mkey.m_modifier = getCurrentModifiers(c.m_mkey.m_key,\r
950                                               isPhysicallyPressed);\r
951     Keymap::AssignMode am;\r
952     bool isModifier = fixModifierKey(&c.m_mkey, &am);\r
953     if (m_isPrefix)\r
954     {\r
955       if (isModifier && m_doesIgnoreModifierForPrefix)\r
956         am = Keymap::AM_true;\r
957       if (m_doesEditNextModifier)\r
958       {\r
959         Modifier modifier = m_modifierForNextKey;\r
960         modifier.add(c.m_mkey.m_modifier);\r
961         c.m_mkey.m_modifier = modifier;\r
962       }\r
963     }\r
964     \r
965     if (m_isLogMode)\r
966       outputToLog(&key, c.m_mkey, 0);\r
967     else if (am == Keymap::AM_true)\r
968     {\r
969       {\r
970         Acquire a(&m_log, 1);\r
971         m_log << _T("* true modifier") << std::endl;\r
972       }\r
973       // true modifier doesn't generate scan code\r
974       outputToLog(&key, c.m_mkey, 1);\r
975     }\r
976     else if (am == Keymap::AM_oneShot || am == Keymap::AM_oneShotRepeatable)\r
977     {\r
978       {\r
979         Acquire a(&m_log, 1);\r
980         if (am == Keymap::AM_oneShot)\r
981           m_log << _T("* one shot modifier") << std::endl;\r
982         else\r
983           m_log << _T("* one shot repeatable modifier") << std::endl;\r
984       }\r
985       // oneShot modifier doesn't generate scan code\r
986       outputToLog(&key, c.m_mkey, 1);\r
987       if (isPhysicallyPressed)\r
988       {\r
989         if (am == Keymap::AM_oneShotRepeatable  // the key is repeating\r
990             && m_oneShotKey.m_key == c.m_mkey.m_key)\r
991         {\r
992           if (m_oneShotRepeatableRepeatCount <\r
993               m_setting->m_oneShotRepeatableDelay) {\r
994             ; // delay\r
995           } else {\r
996             Current cnew = c;\r
997             beginGeneratingKeyboardEvents(cnew, false);\r
998           }\r
999           ++ m_oneShotRepeatableRepeatCount;\r
1000         } else {\r
1001           m_oneShotKey = c.m_mkey;\r
1002           m_oneShotRepeatableRepeatCount = 0;\r
1003         }\r
1004       }\r
1005       else\r
1006       {\r
1007         if (m_oneShotKey.m_key)\r
1008         {\r
1009           Current cnew = c;\r
1010           cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;\r
1011           cnew.m_mkey.m_modifier.off(Modifier::Type_Up);\r
1012           cnew.m_mkey.m_modifier.on(Modifier::Type_Down);\r
1013           beginGeneratingKeyboardEvents(cnew, false);\r
1014           \r
1015           cnew = c;\r
1016           cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;\r
1017           cnew.m_mkey.m_modifier.on(Modifier::Type_Up);\r
1018           cnew.m_mkey.m_modifier.off(Modifier::Type_Down);\r
1019           beginGeneratingKeyboardEvents(cnew, false);\r
1020         }\r
1021         m_oneShotKey.m_key = NULL;\r
1022         m_oneShotRepeatableRepeatCount = 0;\r
1023       }\r
1024     }\r
1025     else if (c.m_mkey.m_key)\r
1026       // normal key\r
1027     {\r
1028       outputToLog(&key, c.m_mkey, 1);\r
1029       if (isPhysicallyPressed)\r
1030         m_oneShotKey.m_key = NULL;\r
1031       beginGeneratingKeyboardEvents(c, isModifier);\r
1032     }\r
1033     \r
1034     // if counter is zero, reset modifiers and keys on win32\r
1035     if (m_currentKeyPressCount <= 0)\r
1036     {\r
1037       {\r
1038         Acquire a(&m_log, 1);\r
1039         m_log << _T("* No key is pressed") << std::endl;\r
1040       }\r
1041       generateModifierEvents(Modifier());\r
1042       if (0 < m_currentKeyPressCountOnWin32)\r
1043         keyboardResetOnWin32();\r
1044       m_currentKeyPressCount = 0;\r
1045       m_currentKeyPressCountOnWin32 = 0;\r
1046       m_oneShotKey.m_key = NULL;\r
1047       if (m_currentLock.isOn(Modifier::Type_Touchpad) == false)\r
1048         m_currentLock.off(Modifier::Type_TouchpadSticky);\r
1049     }\r
1050     \r
1051     key.initialize();\r
1052     updateLastPressedKey(isPhysicallyPressed ? c.m_mkey.m_key : NULL);\r
1053   }\r
1054   break_while:\r
1055   CHECK_TRUE( SetEvent(m_threadEvent) );\r
1056 }\r
1057   \r
1058 \r
1059 Engine::Engine(tomsgstream &i_log)\r
1060   : m_hwndAssocWindow(NULL),\r
1061     m_setting(NULL),\r
1062     m_device(INVALID_HANDLE_VALUE),\r
1063     m_didMayuStartDevice(false),\r
1064     m_threadEvent(NULL),\r
1065     m_mayudVersion(_T("unknown")),\r
1066     m_readEvent(NULL),\r
1067     m_interruptThreadEvent(NULL),\r
1068     m_sts4mayu(NULL),\r
1069     m_cts4mayu(NULL),\r
1070     m_doForceTerminate(false),\r
1071     m_isLogMode(false),\r
1072     m_isEnabled(true),\r
1073     m_isSynchronizing(false),\r
1074     m_eSync(NULL),\r
1075     m_generateKeyboardEventsRecursionGuard(0),\r
1076     m_currentKeyPressCount(0),\r
1077     m_currentKeyPressCountOnWin32(0),\r
1078     m_lastGeneratedKey(NULL),\r
1079     m_oneShotRepeatableRepeatCount(0),\r
1080     m_isPrefix(false),\r
1081     m_currentKeymap(NULL),\r
1082     m_currentFocusOfThread(NULL),\r
1083     m_hwndFocus(NULL),\r
1084     m_afShellExecute(NULL),\r
1085     m_variable(0),\r
1086     m_log(i_log)\r
1087 {\r
1088   for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)\r
1089     m_lastPressedKey[i] = NULL;\r
1090     \r
1091   // set default lock state\r
1092   for (int i = 0; i < Modifier::Type_end; ++ i)\r
1093     m_currentLock.dontcare(static_cast<Modifier::Type>(i));\r
1094   for (int i = Modifier::Type_Lock0; i <= Modifier::Type_Lock9; ++ i)\r
1095     m_currentLock.release(static_cast<Modifier::Type>(i));\r
1096 \r
1097 #ifndef NO_DRIVER\r
1098   if (!open()) {\r
1099       throw ErrorMessage() << loadString(IDS_driverNotInstalled);\r
1100   }\r
1101 #endif // !NO_DRIVER\r
1102   \r
1103 #ifndef NO_DRIVER\r
1104   {\r
1105     TCHAR versionBuf[256];\r
1106     DWORD length = 0;\r
1107 \r
1108     if (DeviceIoControl(m_device, IOCTL_MAYU_GET_VERSION, NULL, 0,\r
1109                         versionBuf, sizeof(versionBuf), &length, NULL)\r
1110         && length\r
1111         && length < sizeof(versionBuf))                 // fail safe\r
1112         m_mayudVersion = tstring(versionBuf, length / 2);\r
1113   }\r
1114 #endif // !NO_DRIVER\r
1115   // create event for sync\r
1116   CHECK_TRUE( m_eSync = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1117   // create named pipe for &SetImeString\r
1118   m_hookPipe = CreateNamedPipe(addSessionId(HOOK_PIPE_NAME).c_str(),\r
1119                                PIPE_ACCESS_OUTBOUND,\r
1120                                PIPE_TYPE_BYTE, 1,\r
1121                                0, 0, 0, NULL);\r
1122   StrExprArg::setEngine(this);\r
1123 }\r
1124 \r
1125 \r
1126 // open mayu device\r
1127 bool Engine::open()\r
1128 {\r
1129   // open mayu m_device\r
1130 #ifndef NO_DRIVER\r
1131   m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,\r
1132                         0, NULL, OPEN_EXISTING,\r
1133                         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);\r
1134 #endif // !NO_DRIVER\r
1135 \r
1136   if (m_device != INVALID_HANDLE_VALUE) {\r
1137     return true;\r
1138   }\r
1139 \r
1140 #ifndef NO_DRIVER\r
1141   // start mayud\r
1142   SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\r
1143   if (hscm)\r
1144   {\r
1145     SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_START);\r
1146     if (hs)\r
1147     {\r
1148       StartService(hs, 0, NULL);\r
1149       CloseServiceHandle(hs);\r
1150       m_didMayuStartDevice = true;\r
1151     }\r
1152     CloseServiceHandle(hscm);\r
1153   }\r
1154   \r
1155   // open mayu m_device\r
1156   m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,\r
1157                         0, NULL, OPEN_EXISTING,\r
1158                         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);\r
1159 #endif // !NO_DRIVER\r
1160   return (m_device != INVALID_HANDLE_VALUE);\r
1161 }\r
1162 \r
1163 \r
1164 // close mayu device\r
1165 void Engine::close()\r
1166 {\r
1167   if (m_device != INVALID_HANDLE_VALUE) {\r
1168 #ifndef NO_DRIVER\r
1169     CHECK_TRUE( CloseHandle(m_device) );\r
1170 #endif // !NO_DRIVER\r
1171   }\r
1172   m_device = INVALID_HANDLE_VALUE;\r
1173 }\r
1174 \r
1175 \r
1176 // start keyboard handler thread\r
1177 void Engine::start()\r
1178 {\r
1179   CHECK_TRUE( m_threadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1180   \r
1181   CHECK_TRUE( m_readEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1182   CHECK_TRUE( m_interruptThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1183   m_ol.Offset = 0;\r
1184   m_ol.OffsetHigh = 0;\r
1185   m_ol.hEvent = m_readEvent;\r
1186   \r
1187   CHECK_TRUE( m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, keyboardHandler, this, 0, &m_threadId) );\r
1188   CHECK( WAIT_OBJECT_0 ==, WaitForSingleObject(m_threadEvent, INFINITE) );\r
1189 }\r
1190 \r
1191 \r
1192 // stop keyboard handler thread\r
1193 void Engine::stop()\r
1194 {\r
1195   if (m_threadEvent)\r
1196   {\r
1197     m_doForceTerminate = true;\r
1198     do\r
1199     {\r
1200       m_interruptThreadReason = InterruptThreadReason_Terminate;\r
1201       SetEvent(m_interruptThreadEvent);\r
1202       //DWORD buf;\r
1203       //M_DeviceIoControl(m_device, IOCTL_MAYU_DETOUR_CANCEL,\r
1204       //                &buf, sizeof(buf), &buf, sizeof(buf), &buf, NULL);\r
1205       \r
1206       // wait for message handler thread terminate\r
1207     } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
1208     CHECK_TRUE( CloseHandle(m_threadEvent) );\r
1209     m_threadEvent = NULL;\r
1210     WaitForSingleObject(m_threadHandle, 100);\r
1211     CHECK_TRUE( CloseHandle(m_threadHandle) );\r
1212     m_threadHandle = NULL;\r
1213 \r
1214     // stop mayud\r
1215     if (m_didMayuStartDevice)\r
1216     {\r
1217       SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\r
1218       if (hscm)\r
1219       {\r
1220         SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_STOP);\r
1221         if (hs)\r
1222         {\r
1223           SERVICE_STATUS ss;\r
1224           ControlService(hs, SERVICE_CONTROL_STOP, &ss);\r
1225           CloseServiceHandle(hs);\r
1226         }\r
1227         CloseServiceHandle(hscm);\r
1228       }\r
1229     }\r
1230     \r
1231     CHECK_TRUE( CloseHandle(m_readEvent) );\r
1232     m_readEvent = NULL;\r
1233     CHECK_TRUE( CloseHandle(m_interruptThreadEvent) );\r
1234     m_interruptThreadEvent = NULL;\r
1235   }\r
1236 }\r
1237 \r
1238 bool Engine::pause()\r
1239 {\r
1240   if (m_device != INVALID_HANDLE_VALUE) {\r
1241     do {\r
1242       m_interruptThreadReason = InterruptThreadReason_Pause;\r
1243       SetEvent(m_interruptThreadEvent);\r
1244     } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
1245 #ifndef NO_DRIVER\r
1246     close();\r
1247 #endif // !NO_DRIVER\r
1248   }\r
1249   return true;\r
1250 }\r
1251 \r
1252 \r
1253 bool Engine::resume()\r
1254 {\r
1255   if (m_device == INVALID_HANDLE_VALUE) {\r
1256 #ifndef NO_DRIVER\r
1257     if (!open()) {\r
1258       return false;                             // FIXME\r
1259     }\r
1260 #endif // !NO_DRIVER\r
1261     do {\r
1262       m_interruptThreadReason = InterruptThreadReason_Resume;\r
1263       SetEvent(m_interruptThreadEvent);\r
1264     } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
1265   }\r
1266   return true;\r
1267 }\r
1268 \r
1269 \r
1270 bool Engine::prepairQuit()\r
1271 {\r
1272   // terminate and unload DLL for ThumbSense support if loaded\r
1273   manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),\r
1274                 false, &m_sts4mayu);\r
1275   manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),\r
1276                 false, &m_cts4mayu);\r
1277   return true;\r
1278 }\r
1279 \r
1280 \r
1281 Engine::~Engine()\r
1282 {\r
1283   stop();\r
1284   CHECK_TRUE( CloseHandle(m_eSync) );\r
1285   \r
1286   // close m_device\r
1287 #ifndef NO_DRIVER\r
1288   close();\r
1289 #endif // !NO_DRIVER\r
1290   // destroy named pipe for &SetImeString\r
1291   if (m_hookPipe && m_hookPipe != INVALID_HANDLE_VALUE)\r
1292   {\r
1293     DisconnectNamedPipe(m_hookPipe);\r
1294     CHECK_TRUE( CloseHandle(m_hookPipe) );\r
1295   }\r
1296 }\r
1297 \r
1298 \r
1299 void Engine::manageTs4mayu(TCHAR *i_ts4mayuDllName,\r
1300                            TCHAR *i_dependDllName,\r
1301                            bool i_load, HMODULE *i_pTs4mayu)\r
1302 {\r
1303   Acquire a(&m_log, 0);\r
1304 \r
1305   if (i_load == false)\r
1306   {\r
1307     if (*i_pTs4mayu)\r
1308     {\r
1309       bool (WINAPI *pTs4mayuTerm)();\r
1310 \r
1311       pTs4mayuTerm = (bool (WINAPI*)())GetProcAddress(*i_pTs4mayu, "ts4mayuTerm");\r
1312       if (pTs4mayuTerm() == true)\r
1313         FreeLibrary(*i_pTs4mayu);\r
1314       *i_pTs4mayu = NULL;\r
1315       m_log << i_ts4mayuDllName <<_T(" unloaded") << std::endl;\r
1316     }\r
1317   }\r
1318   else\r
1319   {\r
1320     if (*i_pTs4mayu)\r
1321     {\r
1322       m_log << i_ts4mayuDllName << _T(" already loaded") << std::endl;\r
1323     }\r
1324     else\r
1325     {\r
1326       if (SearchPath(NULL, i_dependDllName, NULL, 0, NULL, NULL) == 0)\r
1327       {\r
1328         m_log << _T("load ") << i_ts4mayuDllName\r
1329               << _T(" failed: can't find ") << i_dependDllName\r
1330               << std::endl;\r
1331       }\r
1332       else\r
1333       {\r
1334         *i_pTs4mayu = LoadLibrary(i_ts4mayuDllName);\r
1335         if (*i_pTs4mayu == NULL)\r
1336         {\r
1337           m_log << _T("load ") << i_ts4mayuDllName\r
1338                 << _T(" failed: can't find it") << std::endl;\r
1339         }\r
1340         else\r
1341         {\r
1342           bool (WINAPI *pTs4mayuInit)(UINT);    \r
1343 \r
1344           pTs4mayuInit = (bool (WINAPI*)(UINT))GetProcAddress(*i_pTs4mayu, "ts4mayuInit");\r
1345           if (pTs4mayuInit(m_threadId) == true)\r
1346             m_log << i_ts4mayuDllName <<_T(" loaded") << std::endl;\r
1347           else\r
1348             m_log << i_ts4mayuDllName\r
1349                   <<_T(" load failed: can't initialize") << std::endl;\r
1350         }\r
1351       }\r
1352     }\r
1353   }\r
1354 }\r
1355 \r
1356 \r
1357 // set m_setting\r
1358 bool Engine::setSetting(Setting *i_setting)\r
1359 {\r
1360   Acquire a(&m_cs);\r
1361   if (m_isSynchronizing)\r
1362     return false;\r
1363 \r
1364   if (m_setting)\r
1365   {\r
1366     for (Keyboard::KeyIterator i = m_setting->m_keyboard.getKeyIterator();\r
1367          *i; ++ i)\r
1368     {\r
1369       Key *key = i_setting->m_keyboard.searchKey(*(*i));\r
1370       if (key)\r
1371       {\r
1372         key->m_isPressed = (*i)->m_isPressed;\r
1373         key->m_isPressedOnWin32 = (*i)->m_isPressedOnWin32;\r
1374         key->m_isPressedByAssign = (*i)->m_isPressedByAssign;\r
1375       }\r
1376     }\r
1377     if (m_lastGeneratedKey)\r
1378       m_lastGeneratedKey =\r
1379         i_setting->m_keyboard.searchKey(*m_lastGeneratedKey);\r
1380     for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)\r
1381       if (m_lastPressedKey[i])\r
1382         m_lastPressedKey[i] =\r
1383           i_setting->m_keyboard.searchKey(*m_lastPressedKey[i]);\r
1384   }\r
1385   \r
1386   m_setting = i_setting;\r
1387 \r
1388   manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),\r
1389                 m_setting->m_sts4mayu, &m_sts4mayu);\r
1390   manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),\r
1391                 m_setting->m_cts4mayu, &m_cts4mayu);\r
1392 \r
1393   g_hookData->m_correctKanaLockHandling = m_setting->m_correctKanaLockHandling;\r
1394   if (m_currentFocusOfThread)\r
1395   {\r
1396     for (FocusOfThreads::iterator i = m_focusOfThreads.begin();\r
1397          i != m_focusOfThreads.end(); i ++)\r
1398     {\r
1399       FocusOfThread *fot = &(*i).second;\r
1400       m_setting->m_keymaps.searchWindow(&fot->m_keymaps,\r
1401                                         fot->m_className, fot->m_titleName);\r
1402     }\r
1403   }\r
1404   m_setting->m_keymaps.searchWindow(&m_globalFocus.m_keymaps, _T(""), _T(""));\r
1405   if (m_globalFocus.m_keymaps.empty())\r
1406   {\r
1407     Acquire a(&m_log, 0);\r
1408     m_log << _T("internal error: m_globalFocus.m_keymap is empty")\r
1409           << std::endl;\r
1410   }\r
1411   m_currentFocusOfThread = &m_globalFocus;\r
1412   setCurrentKeymap(m_globalFocus.m_keymaps.front());\r
1413   m_hwndFocus = NULL;\r
1414   return true;\r
1415 }\r
1416 \r
1417 \r
1418 void Engine::checkShow(HWND i_hwnd)\r
1419 {\r
1420   // update show style of window\r
1421   // this update should be done in hook DLL, but to\r
1422   // avoid update-loss for some applications(such as\r
1423   // cmd.exe), we update here.\r
1424   bool isMaximized = false;\r
1425   bool isMinimized = false;\r
1426   bool isMDIMaximized = false;\r
1427   bool isMDIMinimized = false;\r
1428   while (i_hwnd)\r
1429   {\r
1430 #ifdef MAYU64\r
1431     LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);\r
1432 #else\r
1433     LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);\r
1434 #endif\r
1435     if (exStyle & WS_EX_MDICHILD)\r
1436     {\r
1437       WINDOWPLACEMENT placement;\r
1438       placement.length = sizeof(WINDOWPLACEMENT);\r
1439       if (GetWindowPlacement(i_hwnd, &placement))\r
1440       {\r
1441          switch (placement.showCmd)\r
1442          {\r
1443            case SW_SHOWMAXIMIZED:\r
1444              isMDIMaximized = true;\r
1445              break;\r
1446            case SW_SHOWMINIMIZED:\r
1447              isMDIMinimized = true;\r
1448              break;\r
1449            case SW_SHOWNORMAL:\r
1450            default:\r
1451              break;\r
1452          }\r
1453       }\r
1454     }\r
1455 \r
1456 #ifdef MAYU64\r
1457     LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);\r
1458 #else\r
1459     LONG style = GetWindowLong(i_hwnd, GWL_STYLE);\r
1460 #endif\r
1461     if ((style & WS_CHILD) == 0)\r
1462     {\r
1463       WINDOWPLACEMENT placement;\r
1464       placement.length = sizeof(WINDOWPLACEMENT);\r
1465       if (GetWindowPlacement(i_hwnd, &placement))\r
1466       {\r
1467          switch (placement.showCmd)\r
1468          {\r
1469            case SW_SHOWMAXIMIZED:\r
1470              isMaximized = true;\r
1471              break;\r
1472            case SW_SHOWMINIMIZED:\r
1473              isMinimized = true;\r
1474              break;\r
1475            case SW_SHOWNORMAL:\r
1476            default:\r
1477              break;\r
1478          }\r
1479       }\r
1480     }  \r
1481     i_hwnd = GetParent(i_hwnd);\r
1482   }\r
1483   setShow(isMDIMaximized, isMDIMinimized, true);\r
1484   setShow(isMaximized, isMinimized, false);\r
1485 }\r
1486 \r
1487 \r
1488 // focus\r
1489 bool Engine::setFocus(HWND i_hwndFocus, DWORD i_threadId, \r
1490                       const tstringi &i_className, const tstringi &i_titleName,\r
1491                       bool i_isConsole)\r
1492 {\r
1493   Acquire a(&m_cs);\r
1494   if (m_isSynchronizing)\r
1495     return false;\r
1496   if (i_hwndFocus == NULL)\r
1497     return true;\r
1498 \r
1499   // remove newly created thread's id from m_detachedThreadIds\r
1500   if (!m_detachedThreadIds.empty())\r
1501   {\r
1502     DetachedThreadIds::iterator i;\r
1503     bool retry;\r
1504     do\r
1505     {\r
1506       retry = false;\r
1507       for (i = m_detachedThreadIds.begin();\r
1508            i != m_detachedThreadIds.end(); ++ i)\r
1509         if (*i == i_threadId)\r
1510         {\r
1511           m_detachedThreadIds.erase(i);\r
1512           retry = true;\r
1513           break;\r
1514         }\r
1515     } while (retry);\r
1516   }\r
1517   \r
1518   FocusOfThread *fot;\r
1519   FocusOfThreads::iterator i = m_focusOfThreads.find(i_threadId);\r
1520   if (i != m_focusOfThreads.end())\r
1521   {\r
1522     fot = &(*i).second;\r
1523     if (fot->m_hwndFocus == i_hwndFocus &&\r
1524         fot->m_isConsole == i_isConsole &&\r
1525         fot->m_className == i_className &&\r
1526         fot->m_titleName == i_titleName)\r
1527       return true;\r
1528   }\r
1529   else\r
1530   {\r
1531     i = m_focusOfThreads.insert(\r
1532       FocusOfThreads::value_type(i_threadId, FocusOfThread())).first;\r
1533     fot = &(*i).second;\r
1534     fot->m_threadId = i_threadId;\r
1535   }\r
1536   fot->m_hwndFocus = i_hwndFocus;\r
1537   fot->m_isConsole = i_isConsole;\r
1538   fot->m_className = i_className;\r
1539   fot->m_titleName = i_titleName;\r
1540   \r
1541   if (m_setting)\r
1542   {\r
1543     m_setting->m_keymaps.searchWindow(&fot->m_keymaps,\r
1544                                       i_className, i_titleName);\r
1545     ASSERT(0 < fot->m_keymaps.size());\r
1546   }\r
1547   else\r
1548     fot->m_keymaps.clear();\r
1549   checkShow(i_hwndFocus);\r
1550   return true;\r
1551 }\r
1552 \r
1553 \r
1554 // lock state\r
1555 bool Engine::setLockState(bool i_isNumLockToggled,\r
1556                           bool i_isCapsLockToggled,\r
1557                           bool i_isScrollLockToggled,\r
1558                           bool i_isKanaLockToggled,\r
1559                           bool i_isImeLockToggled,\r
1560                           bool i_isImeCompToggled)\r
1561 {\r
1562   Acquire a(&m_cs);\r
1563   if (m_isSynchronizing)\r
1564     return false;\r
1565   m_currentLock.on(Modifier::Type_NumLock, i_isNumLockToggled);\r
1566   m_currentLock.on(Modifier::Type_CapsLock, i_isCapsLockToggled);\r
1567   m_currentLock.on(Modifier::Type_ScrollLock, i_isScrollLockToggled);\r
1568   m_currentLock.on(Modifier::Type_KanaLock, i_isKanaLockToggled);\r
1569   m_currentLock.on(Modifier::Type_ImeLock, i_isImeLockToggled);\r
1570   m_currentLock.on(Modifier::Type_ImeComp, i_isImeCompToggled);\r
1571   return true;\r
1572 }\r
1573 \r
1574 \r
1575 // show\r
1576 bool Engine::setShow(bool i_isMaximized, bool i_isMinimized,\r
1577                      bool i_isMDI)\r
1578 {\r
1579   Acquire a(&m_cs);\r
1580   if (m_isSynchronizing)\r
1581     return false;\r
1582   Acquire b(&m_log, 1);\r
1583   Modifier::Type max, min;\r
1584   if (i_isMDI == true) {\r
1585     max = Modifier::Type_MdiMaximized;\r
1586     min = Modifier::Type_MdiMinimized;\r
1587   }\r
1588   else\r
1589   {\r
1590     max = Modifier::Type_Maximized;\r
1591     min = Modifier::Type_Minimized;\r
1592   }\r
1593   m_currentLock.on(max, i_isMaximized);\r
1594   m_currentLock.on(min, i_isMinimized);\r
1595   m_log << _T("Set show to ") << (i_isMaximized ? _T("Maximized") :\r
1596                                   i_isMinimized ? _T("Minimized") : _T("Normal"));\r
1597   if (i_isMDI == true)\r
1598   {\r
1599     m_log << _T(" (MDI)");\r
1600   }\r
1601   m_log << std::endl;\r
1602   return true;\r
1603 }\r
1604 \r
1605 \r
1606 // sync\r
1607 bool Engine::syncNotify()\r
1608 {\r
1609   Acquire a(&m_cs);\r
1610   if (!m_isSynchronizing)\r
1611     return false;\r
1612   CHECK_TRUE( SetEvent(m_eSync) );\r
1613   return true;\r
1614 }\r
1615 \r
1616 \r
1617 // thread detach notify\r
1618 bool Engine::threadDetachNotify(DWORD i_threadId)\r
1619 {\r
1620   Acquire a(&m_cs);\r
1621   m_detachedThreadIds.push_back(i_threadId);\r
1622   return true;\r
1623 }\r
1624 \r
1625 \r
1626 // get help message\r
1627 void Engine::getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle)\r
1628 {\r
1629   Acquire a(&m_cs);\r
1630   *o_helpMessage = m_helpMessage;\r
1631   *o_helpTitle = m_helpTitle;\r
1632 }\r
1633 \r
1634 \r
1635 // command notify\r
1636 void Engine::commandNotify(\r
1637   HWND i_hwnd, UINT i_message, WPARAM i_wParam, LPARAM i_lParam)\r
1638 {\r
1639   Acquire b(&m_log, 0);\r
1640   HWND hf = m_hwndFocus;\r
1641   if (!hf)\r
1642     return;\r
1643 \r
1644   if (GetWindowThreadProcessId(hf, NULL) == \r
1645       GetWindowThreadProcessId(m_hwndAssocWindow, NULL))\r
1646     return;     // inhibit the investigation of MADO TSUKAI NO YUUTSU\r
1647 \r
1648   const _TCHAR *target = NULL;\r
1649   int number_target = 0;\r
1650   \r
1651   if (i_hwnd == hf)\r
1652     target = _T("ToItself");\r
1653   else if (i_hwnd == GetParent(hf))\r
1654     target = _T("ToParentWindow");\r
1655   else\r
1656   {\r
1657     // Function::toMainWindow\r
1658     HWND h = hf;\r
1659     while (true)\r
1660     {\r
1661       HWND p = GetParent(h);\r
1662       if (!p)\r
1663         break;\r
1664       h = p;\r
1665     }\r
1666     if (i_hwnd == h)\r
1667       target = _T("ToMainWindow");\r
1668     else\r
1669     {\r
1670       // Function::toOverlappedWindow\r
1671       HWND h = hf;\r
1672       while (h)\r
1673       {\r
1674 #ifdef MAYU64\r
1675         LONG_PTR style = GetWindowLongPtr(h, GWL_STYLE);\r
1676 #else\r
1677         LONG style = GetWindowLong(h, GWL_STYLE);\r
1678 #endif\r
1679         if ((style & WS_CHILD) == 0)\r
1680           break;\r
1681         h = GetParent(h);\r
1682       }\r
1683       if (i_hwnd == h)\r
1684         target = _T("ToOverlappedWindow");\r
1685       else\r
1686       {\r
1687         // number\r
1688         HWND h = hf;\r
1689         for (number_target = 0; h; number_target ++, h = GetParent(h))\r
1690           if (i_hwnd == h)\r
1691             break;\r
1692         return;\r
1693       }\r
1694     }\r
1695   }\r
1696 \r
1697   m_log << _T("&PostMessage(");\r
1698   if (target)\r
1699     m_log << target;\r
1700   else\r
1701     m_log << number_target;\r
1702   m_log << _T(", ") << i_message\r
1703         << _T(", 0x") << std::hex << i_wParam\r
1704         << _T(", 0x") << i_lParam << _T(") # hwnd = ")\r
1705         << reinterpret_cast<int>(i_hwnd) << _T(", ")\r
1706         << _T("message = ") << std::dec;\r
1707   if (i_message == WM_COMMAND)\r
1708     m_log << _T("WM_COMMAND, ");\r
1709   else if (i_message == WM_SYSCOMMAND)\r
1710     m_log << _T("WM_SYSCOMMAND, ");\r
1711   else\r
1712     m_log << i_message << _T(", ");\r
1713   m_log << _T("wNotifyCode = ") << HIWORD(i_wParam) << _T(", ")\r
1714         << _T("wID = ") << LOWORD(i_wParam) << _T(", ")\r
1715         << _T("hwndCtrl = 0x") << std::hex << i_lParam << std::dec << std::endl;\r
1716 }\r