OSDN Git Service

separate intermediate directories for each projects to avoid confliction of dependenc...
[yamy/yamy.git] / function.cpp
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // function.cpp
3
4
5 #include "engine.h"
6 #include "hook.h"
7 #include "mayu.h"
8 #include "mayurc.h"
9 #include "misc.h"
10 #include "registry.h"
11 #include "vkeytable.h"
12 #include "windowstool.h"
13 #include <algorithm>
14 #include <process.h>
15
16 #define FUNCTION_DATA
17 #include "functions.h"
18 #undef FUNCTION_DATA
19
20
21 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
22 // TypeTable
23
24
25 template <class T> class TypeTable
26 {
27 public:
28   T m_type;
29   const _TCHAR *m_name;
30 };
31
32
33 template <class T> static inline
34 bool getTypeName(tstring *o_name, T i_type,
35                  const TypeTable<T> *i_table, size_t i_n)
36 {
37   for (size_t i = 0; i < i_n; ++ i)
38     if (i_table[i].m_type == i_type)
39     {
40       *o_name = i_table[i].m_name;
41       return true;
42     }
43   return false;
44 }
45
46 template <class T> static inline
47 bool getTypeValue(T *o_type, const tstringi &i_name,
48                   const TypeTable<T> *i_table, size_t i_n)
49 {
50   for (size_t i = 0; i < i_n; ++ i)
51     if (i_table[i].m_name == i_name)
52     {
53       *o_type = i_table[i].m_type;
54       return true;
55     }
56   return false;
57 }
58
59
60 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61 // VKey
62
63
64 // stream output
65 tostream &operator<<(tostream &i_ost, VKey i_data)
66 {
67   if (i_data & VKey_extended)
68     i_ost << _T("E-");
69   if (i_data & VKey_released)
70     i_ost << _T("U-");
71   if (i_data & VKey_pressed)
72     i_ost << _T("D-");
73
74   u_int8 code = i_data & ~(VKey_extended | VKey_released | VKey_pressed);
75   const VKeyTable *vkt;
76   for (vkt = g_vkeyTable; vkt->m_name; ++ vkt)
77     if (vkt->m_code == code)
78       break;
79   if (vkt->m_name)
80     i_ost << vkt->m_name;
81   else
82     i_ost << _T("0x") << std::hex << code << std::dec;
83   return i_ost;
84 }
85
86
87 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
88 // ToWindowType
89
90
91 // ToWindowType table
92 typedef TypeTable<ToWindowType> TypeTable_ToWindowType;
93 static const TypeTable_ToWindowType g_toWindowTypeTable[] =
94 {
95   { ToWindowType_toOverlappedWindow, _T("toOverlappedWindow") },
96   { ToWindowType_toMainWindow,       _T("toMainWindow")       },
97   { ToWindowType_toItself,           _T("toItself")           },
98   { ToWindowType_toParentWindow,     _T("toParentWindow")     },
99 };
100
101
102 // stream output
103 tostream &operator<<(tostream &i_ost, ToWindowType i_data)
104 {
105   tstring name;
106   if (getTypeName(&name, i_data,
107                   g_toWindowTypeTable, NUMBER_OF(g_toWindowTypeTable)))
108     i_ost << name;
109   else
110     i_ost << static_cast<int>(i_data);
111   return i_ost;
112 }
113
114
115 // get value of ToWindowType
116 bool getTypeValue(ToWindowType *o_type, const tstring &i_name)
117 {
118   return getTypeValue(o_type, i_name,
119                       g_toWindowTypeTable, NUMBER_OF(g_toWindowTypeTable));
120 }
121
122
123 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124 // GravityType
125
126
127 // GravityType table
128 typedef TypeTable<GravityType> TypeTable_GravityType;
129 static const TypeTable_GravityType g_gravityTypeTable[] =
130 {
131   { GravityType_C,  _T("C")  },
132   { GravityType_N,  _T("N")  },
133   { GravityType_E,  _T("E")  },
134   { GravityType_W,  _T("W")  },
135   { GravityType_S,  _T("S")  },
136   { GravityType_NW, _T("NW") },
137   { GravityType_NW, _T("WN") },
138   { GravityType_NE, _T("NE") },
139   { GravityType_NE, _T("EN") },
140   { GravityType_SW, _T("SW") },
141   { GravityType_SW, _T("WS") },
142   { GravityType_SE, _T("SE") },
143   { GravityType_SE, _T("ES") },
144 };
145
146
147 // stream output
148 tostream &operator<<(tostream &i_ost, GravityType i_data)
149 {
150   tstring name;
151   if (getTypeName(&name, i_data,
152                   g_gravityTypeTable, NUMBER_OF(g_gravityTypeTable)))
153     i_ost << name;
154   else
155     i_ost << _T("(GravityType internal error)");
156   return i_ost;
157 }
158
159
160 // get value of GravityType
161 bool getTypeValue(GravityType *o_type, const tstring &i_name)
162 {
163   return getTypeValue(o_type, i_name,
164                       g_gravityTypeTable, NUMBER_OF(g_gravityTypeTable));
165 }
166
167
168 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169 // MouseHookType
170
171
172 // MouseHookType table
173 typedef TypeTable<MouseHookType> TypeTable_MouseHookType;
174 static const TypeTable_MouseHookType g_mouseHookTypeTable[] =
175 {
176   { MouseHookType_None,  _T("None")  },
177   { MouseHookType_Wheel,  _T("Wheel")  },
178   { MouseHookType_WindowMove,  _T("WindowMove")  },
179 };
180
181
182 // stream output
183 tostream &operator<<(tostream &i_ost, MouseHookType i_data)
184 {
185   tstring name;
186   if (getTypeName(&name, i_data,
187                   g_mouseHookTypeTable, NUMBER_OF(g_mouseHookTypeTable)))
188     i_ost << name;
189   else
190     i_ost << _T("(MouseHookType internal error)");
191   return i_ost;
192 }
193
194
195 // get value of MouseHookType
196 bool getTypeValue(MouseHookType *o_type, const tstring &i_name)
197 {
198   return getTypeValue(o_type, i_name, g_mouseHookTypeTable,
199                       NUMBER_OF(g_mouseHookTypeTable));
200 }
201
202
203 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
204 // MayuDialogType
205
206
207 // ModifierLockType table
208 typedef TypeTable<MayuDialogType> TypeTable_MayuDialogType;
209 static const TypeTable_MayuDialogType g_mayuDialogTypeTable[] =
210 {
211   { MayuDialogType_investigate, _T("investigate")  },
212   { MayuDialogType_log,         _T("log")          },
213 };
214
215
216 // stream output
217 tostream &operator<<(tostream &i_ost, MayuDialogType i_data)
218 {
219   tstring name;
220   if (getTypeName(&name, i_data,
221                   g_mayuDialogTypeTable, NUMBER_OF(g_mayuDialogTypeTable)))
222     i_ost << name;
223   else
224     i_ost << _T("(MayuDialogType internal error)");
225   return i_ost;
226 }
227
228
229 // get value of MayuDialogType
230 bool getTypeValue(MayuDialogType *o_type, const tstring &i_name)
231 {
232   return getTypeValue(o_type, i_name, g_mayuDialogTypeTable,
233                       NUMBER_OF(g_mayuDialogTypeTable));
234 }
235
236
237 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
238 // ToggleType
239
240
241 // ToggleType table
242 typedef TypeTable<ToggleType> TypeTable_ToggleType;
243 static const TypeTable_ToggleType g_toggleType[] =
244 {
245   { ToggleType_toggle, _T("toggle") },
246   { ToggleType_off, _T("off") },
247   { ToggleType_off, _T("false") },
248   { ToggleType_off, _T("released") },
249   { ToggleType_on,  _T("on")  },
250   { ToggleType_on,  _T("true")  },
251   { ToggleType_on,  _T("pressed")  },
252 };
253
254
255 // stream output
256 tostream &operator<<(tostream &i_ost, ToggleType i_data)
257 {
258   tstring name;
259   if (getTypeName(&name, i_data, g_toggleType, NUMBER_OF(g_toggleType)))
260     i_ost << name;
261   else
262     i_ost << _T("(ToggleType internal error)");
263   return i_ost;
264 }
265
266
267 // get value of ToggleType
268 bool getTypeValue(ToggleType *o_type, const tstring &i_name)
269 {
270   return getTypeValue(o_type, i_name, g_toggleType,
271                       NUMBER_OF(g_toggleType));
272 }
273
274
275 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
276 // ModifierLockType
277
278
279 // ModifierLockType table
280 typedef TypeTable<ModifierLockType> TypeTable_ModifierLockType;
281 static const TypeTable_ModifierLockType g_modifierLockTypeTable[] =
282 {
283   { ModifierLockType_Lock0, _T("lock0") },
284   { ModifierLockType_Lock1, _T("lock1") },
285   { ModifierLockType_Lock2, _T("lock2") },
286   { ModifierLockType_Lock3, _T("lock3") },
287   { ModifierLockType_Lock4, _T("lock4") },
288   { ModifierLockType_Lock5, _T("lock5") },
289   { ModifierLockType_Lock6, _T("lock6") },
290   { ModifierLockType_Lock7, _T("lock7") },
291   { ModifierLockType_Lock8, _T("lock8") },
292   { ModifierLockType_Lock9, _T("lock9") },
293 };
294
295
296 // stream output
297 tostream &operator<<(tostream &i_ost, ModifierLockType i_data)
298 {
299   tstring name;
300   if (getTypeName(&name, i_data,
301                   g_modifierLockTypeTable, NUMBER_OF(g_modifierLockTypeTable)))
302     i_ost << name;
303   else
304     i_ost << _T("(ModifierLockType internal error)");
305   return i_ost;
306 }
307
308
309 // get value of ModifierLockType
310 bool getTypeValue(ModifierLockType *o_type, const tstring &i_name)
311 {
312   return getTypeValue(o_type, i_name, g_modifierLockTypeTable,
313                       NUMBER_OF(g_modifierLockTypeTable));
314 }
315
316
317 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
318 // ShowCommandType
319
320
321 // ShowCommandType table
322 typedef TypeTable<ShowCommandType> TypeTable_ShowCommandType;
323 static const TypeTable_ShowCommandType g_showCommandTypeTable[] =
324 {
325   { ShowCommandType_hide,            _T("hide")            },
326   { ShowCommandType_maximize,        _T("maximize")        },
327   { ShowCommandType_minimize,        _T("minimize")        },
328   { ShowCommandType_restore,         _T("restore")         },
329   { ShowCommandType_show,            _T("show")            },
330   { ShowCommandType_showDefault,     _T("showDefault")     },
331   { ShowCommandType_showMaximized,   _T("showMaximized")   },
332   { ShowCommandType_showMinimized,   _T("showMinimized")   },
333   { ShowCommandType_showMinNoActive, _T("showMinNoActive") },
334   { ShowCommandType_showNA,          _T("showNA")          },
335   { ShowCommandType_showNoActivate,  _T("showNoActivate")  },
336   { ShowCommandType_showNormal,      _T("showNormal")      },
337 };
338
339
340 // stream output
341 tostream &operator<<(tostream &i_ost, ShowCommandType i_data)
342 {
343   tstring name;
344   if (getTypeName(&name, i_data,
345                   g_showCommandTypeTable, NUMBER_OF(g_showCommandTypeTable)))
346     i_ost << name;
347   else
348     i_ost << _T("(ShowCommandType internal error)");
349   return i_ost;
350 }
351
352
353 // get value of ShowCommandType
354 bool getTypeValue(ShowCommandType *o_type, const tstring &i_name)
355 {
356   return getTypeValue(o_type, i_name, g_showCommandTypeTable,
357                       NUMBER_OF(g_showCommandTypeTable));
358 }
359
360
361 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
362 // TargetWindowType
363
364
365 // ModifierLockType table
366 typedef TypeTable<TargetWindowType> TypeTable_TargetWindowType;
367 static const TypeTable_TargetWindowType g_targetWindowType[] =
368 {
369   { TargetWindowType_overlapped, _T("overlapped") },
370   { TargetWindowType_mdi,        _T("mdi")        },
371 };
372
373
374 // stream output
375 tostream &operator<<(tostream &i_ost, TargetWindowType i_data)
376 {
377   tstring name;
378   if (getTypeName(&name, i_data,
379                   g_targetWindowType, NUMBER_OF(g_targetWindowType)))
380     i_ost << name;
381   else
382     i_ost << _T("(TargetWindowType internal error)");
383   return i_ost;
384 }
385
386
387 // get value of TargetWindowType
388 bool getTypeValue(TargetWindowType *o_type, const tstring &i_name)
389 {
390   return getTypeValue(o_type, i_name, g_targetWindowType,
391                       NUMBER_OF(g_targetWindowType));
392 }
393
394
395 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
396 // BooleanType
397
398
399 // BooleanType table
400 typedef TypeTable<BooleanType> TypeTable_BooleanType;
401 static const TypeTable_BooleanType g_booleanType[] =
402 {
403   { BooleanType_false, _T("false") },
404   { BooleanType_true,  _T("true")  },
405 };
406
407
408 // stream output
409 tostream &operator<<(tostream &i_ost, BooleanType i_data)
410 {
411   tstring name;
412   if (getTypeName(&name, i_data, g_booleanType, NUMBER_OF(g_booleanType)))
413     i_ost << name;
414   else
415     i_ost << _T("(BooleanType internal error)");
416   return i_ost;
417 }
418
419
420 // get value of BooleanType
421 bool getTypeValue(BooleanType *o_type, const tstring &i_name)
422 {
423   return getTypeValue(o_type, i_name, g_booleanType,
424                       NUMBER_OF(g_booleanType));
425 }
426
427
428 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
429 // LogicalOperatorType
430
431
432 // LogicalOperatorType table
433 typedef TypeTable<LogicalOperatorType> TypeTable_LogicalOperatorType;
434 static const TypeTable_LogicalOperatorType g_logicalOperatorType[] =
435 {
436   { LogicalOperatorType_or, _T("||") },
437   { LogicalOperatorType_and,  _T("&&")  },
438 };
439
440
441 // stream output
442 tostream &operator<<(tostream &i_ost, LogicalOperatorType i_data)
443 {
444   tstring name;
445   if (getTypeName(&name, i_data, g_logicalOperatorType,
446                   NUMBER_OF(g_logicalOperatorType)))
447     i_ost << name;
448   else
449     i_ost << _T("(LogicalOperatorType internal error)");
450   return i_ost;
451 }
452
453
454 // get value of LogicalOperatorType
455 bool getTypeValue(LogicalOperatorType *o_type, const tstring &i_name)
456 {
457   return getTypeValue(o_type, i_name, g_logicalOperatorType,
458                       NUMBER_OF(g_logicalOperatorType));
459 }
460
461
462 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
463 // WindowMonitorFromType
464
465
466 // WindowMonitorFromType table
467 typedef TypeTable<WindowMonitorFromType> TypeTable_WindowMonitorFromType;
468 static const TypeTable_WindowMonitorFromType g_windowMonitorFromType[] =
469 {
470   { WindowMonitorFromType_primary, _T("primary") },
471   { WindowMonitorFromType_current, _T("current") },
472 };
473
474
475 // stream output
476 tostream &operator<<(tostream &i_ost, WindowMonitorFromType i_data)
477 {
478   tstring name;
479   if(getTypeName(&name, i_data, g_windowMonitorFromType,
480                  NUMBER_OF(g_windowMonitorFromType)))
481     i_ost << name;
482   else
483     i_ost << _T("(WindowMonitorFromType internal error)");
484   return i_ost;
485 }
486
487
488 // get value of WindowMonitorFromType
489 bool getTypeValue(WindowMonitorFromType *o_type, const tstring &i_name)
490 {
491   return getTypeValue(o_type, i_name, g_windowMonitorFromType,
492                       NUMBER_OF(g_windowMonitorFromType));
493 }
494
495
496 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
497 // std::list<tstringq>
498
499
500 /// stream output
501 tostream &operator<<(tostream &i_ost, const std::list<tstringq> &i_data)
502 {
503   for (std::list<tstringq>::const_iterator
504          i = i_data.begin(); i != i_data.end(); ++ i)
505   {
506     i_ost << *i << _T(", ");
507   }
508   return i_ost;
509 }
510
511
512 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
513 // FunctionData
514
515
516 //
517 FunctionData::~FunctionData()
518 {
519 }
520
521
522 // stream output
523 tostream &operator<<(tostream &i_ost, const FunctionData *i_data)
524 {
525   return i_data->output(i_ost);
526 }
527
528
529 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
530 // FunctionCreator
531
532
533 ///
534 class FunctionCreator
535 {
536 public:
537   typedef FunctionData *(*Creator)();           /// 
538   
539 public:
540   const _TCHAR *m_name;                         /// function name
541   Creator m_creator;                            /// function data creator
542 };
543
544
545 // create function
546 FunctionData *createFunctionData(const tstring &i_name)
547 {
548   static 
549 #define FUNCTION_CREATOR
550 #include "functions.h"
551 #undef FUNCTION_CREATOR
552     ;
553
554   for (size_t i = 0; i != NUMBER_OF(functionCreators); ++ i)
555     if (i_name == functionCreators[i].m_name)
556       return functionCreators[i].m_creator();
557   return NULL;
558 }
559
560
561 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
562 // misc. functions
563
564
565 //
566 bool getSuitableWindow(FunctionParam *i_param, HWND *o_hwnd)
567 {
568   if (!i_param->m_isPressed)
569     return false;
570   *o_hwnd = getToplevelWindow(i_param->m_hwnd, NULL);
571   if (!*o_hwnd)
572     return false;
573   return true;
574 }
575
576 //
577 bool getSuitableMdiWindow(FunctionParam *i_param, HWND *o_hwnd,
578                           TargetWindowType *io_twt,
579                           RECT *o_rcWindow = NULL, RECT *o_rcParent = NULL)
580 {
581   if (!i_param->m_isPressed)
582     return false;
583   bool isMdi = *io_twt == TargetWindowType_mdi;
584   *o_hwnd = getToplevelWindow(i_param->m_hwnd, &isMdi);
585   *io_twt = isMdi ? TargetWindowType_mdi : TargetWindowType_overlapped;
586   if (!*o_hwnd)
587     return false;
588   switch (*io_twt)
589   {
590     case TargetWindowType_overlapped:
591       if (o_rcWindow)
592         GetWindowRect(*o_hwnd, o_rcWindow);
593       if (o_rcParent) {
594         HMONITOR hm = monitorFromWindow(i_param->m_hwnd,
595                                         MONITOR_DEFAULTTONEAREST);
596         MONITORINFO mi;
597         mi.cbSize = sizeof(mi);
598         getMonitorInfo(hm, &mi);
599         *o_rcParent = mi.rcWork;
600       }
601       break;
602     case TargetWindowType_mdi:
603       if (o_rcWindow)
604         getChildWindowRect(*o_hwnd, o_rcWindow);
605       if (o_rcParent)
606         GetClientRect(GetParent(*o_hwnd), o_rcParent);
607       break;
608   }
609   return true;
610 }
611
612 // get clipboard text (you must call closeClopboard())
613 static const _TCHAR *getTextFromClipboard(HGLOBAL *o_hdata)
614 {
615   *o_hdata = NULL;
616   
617   if (!OpenClipboard(NULL))
618     return NULL;
619
620 #ifdef UNICODE
621   *o_hdata = GetClipboardData(CF_UNICODETEXT);
622 #else
623   *o_hdata = GetClipboardData(CF_TEXT);
624 #endif
625   if (!*o_hdata)
626     return NULL;
627   
628   _TCHAR *data = reinterpret_cast<_TCHAR *>(GlobalLock(*o_hdata));
629   if (!data)
630     return NULL;
631   return data;
632 }
633
634 // close clipboard that opend by getTextFromClipboard()
635 static void closeClipboard(HGLOBAL i_hdata, HGLOBAL i_hdataNew = NULL)
636 {
637   if (i_hdata)
638     GlobalUnlock(i_hdata);
639   if (i_hdataNew)
640   {
641     EmptyClipboard();
642 #ifdef UNICODE
643     SetClipboardData(CF_UNICODETEXT, i_hdataNew);
644 #else
645     SetClipboardData(CF_TEXT, i_hdataNew);
646 #endif
647   }
648   CloseClipboard();
649 }
650
651
652 // EmacsEditKillLineFunc.
653 // clear the contents of the clopboard
654 // at that time, confirm if it is the result of the previous kill-line
655 void Engine::EmacsEditKillLine::func()
656 {
657   if (!m_buf.empty())
658   {
659     HGLOBAL g;
660     const _TCHAR *text = getTextFromClipboard(&g);
661     if (text == NULL || m_buf != text)
662       reset();
663     closeClipboard(g);
664   }
665   if (OpenClipboard(NULL))
666   {
667     EmptyClipboard();
668     CloseClipboard();
669   }
670 }
671
672
673 /** if the text of the clipboard is
674 @doc
675 <pre>
676 1: EDIT Control (at EOL C-K): ""            =&gt; buf + "\r\n", Delete   
677 0: EDIT Control (other  C-K): "(.+)"        =&gt; buf + "\1"             
678 0: IE FORM TEXTAREA (at EOL C-K): "\r\n"    =&gt; buf + "\r\n"           
679 2: IE FORM TEXTAREA (other C-K): "(.+)\r\n" =&gt; buf + "\1", Return Left
680 ^retval
681 </pre>
682 */
683 HGLOBAL Engine::EmacsEditKillLine::makeNewKillLineBuf(
684   const _TCHAR *i_data, int *o_retval)
685 {
686   size_t len = m_buf.size();
687   len += _tcslen(i_data) + 3;
688   
689   HGLOBAL hdata = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
690                               len * sizeof(_TCHAR));
691   if (!hdata)
692     return NULL;
693   _TCHAR *dataNew = reinterpret_cast<_TCHAR *>(GlobalLock(hdata));
694   *dataNew = _T('\0');
695   if (!m_buf.empty())
696     _tcscpy(dataNew, m_buf.c_str());
697   
698   len = _tcslen(i_data);
699   if (3 <= len &&
700       i_data[len - 2] == _T('\r') && i_data[len - 1] == _T('\n'))
701   {
702     _tcscat(dataNew, i_data);
703     len = _tcslen(dataNew);
704     dataNew[len - 2] = _T('\0'); // chomp
705     *o_retval = 2;
706   }
707   else if (len == 0)
708   {
709     _tcscat(dataNew, _T("\r\n"));
710     *o_retval = 1;
711   }
712   else
713   {
714     _tcscat(dataNew, i_data);
715     *o_retval = 0;
716   }
717   
718   m_buf = dataNew;
719   
720   GlobalUnlock(hdata);
721   return hdata;
722 }
723
724
725 // EmacsEditKillLinePred
726 int Engine::EmacsEditKillLine::pred()
727 {
728   HGLOBAL g;
729   const _TCHAR *text = getTextFromClipboard(&g);
730   int retval;
731   HGLOBAL hdata = makeNewKillLineBuf(text ? text : _T(""), &retval);
732   closeClipboard(g, hdata);
733   return retval;
734 }
735
736
737 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
738 // functions
739
740
741 // send a default key to Windows
742 void Engine::funcDefault(FunctionParam *i_param)
743 {
744   {
745     Acquire a(&m_log, 1);
746     m_log << std::endl;
747     i_param->m_doesNeedEndl = false;
748   }
749   if (i_param->m_isPressed)
750     generateModifierEvents(i_param->m_c.m_mkey.m_modifier);
751   generateKeyEvent(i_param->m_c.m_mkey.m_key, i_param->m_isPressed, true);
752 }
753
754 // use a corresponding key of a parent keymap
755 void Engine::funcKeymapParent(FunctionParam *i_param)
756 {
757   Current c(i_param->m_c);
758   c.m_keymap = c.m_keymap->getParentKeymap();
759   if (!c.m_keymap)
760   {
761     funcDefault(i_param);
762     return;
763   }
764   
765   {
766     Acquire a(&m_log, 1);
767     m_log << _T("(") << c.m_keymap->getName() << _T(")") << std::endl;
768   }
769   i_param->m_doesNeedEndl = false;
770   generateKeyboardEvents(c);
771 }
772
773 // use a corresponding key of a current window
774 void Engine::funcKeymapWindow(FunctionParam *i_param)
775 {
776   Current c(i_param->m_c);
777   c.m_keymap = m_currentFocusOfThread->m_keymaps.front();
778   c.m_i = m_currentFocusOfThread->m_keymaps.begin();
779   generateKeyboardEvents(c);
780 }
781
782 // use a corresponding key of the previous prefixed keymap
783 void Engine::funcKeymapPrevPrefix(FunctionParam *i_param, int i_previous)
784 {
785   Current c(i_param->m_c);
786   if (0 < i_previous && 0 <= m_keymapPrefixHistory.size() - i_previous)
787   {
788     int n = i_previous - 1;
789     KeymapPtrList::reverse_iterator i = m_keymapPrefixHistory.rbegin();
790     while (0 < n && i != m_keymapPrefixHistory.rend())
791       --n, ++i;
792     c.m_keymap = *i;
793     generateKeyboardEvents(c);
794   }
795 }
796
797 // use a corresponding key of an other window class, or use a default key
798 void Engine::funcOtherWindowClass(FunctionParam *i_param)
799 {
800   Current c(i_param->m_c);
801   ++ c.m_i;
802   if (c.m_i == m_currentFocusOfThread->m_keymaps.end())
803   {
804     funcDefault(i_param);
805     return;
806   }
807   
808   c.m_keymap = *c.m_i;
809   {
810     Acquire a(&m_log, 1);
811     m_log << _T("(") << c.m_keymap->getName() << _T(")") << std::endl;
812   }
813   i_param->m_doesNeedEndl = false;
814   generateKeyboardEvents(c);
815 }
816
817 // prefix key
818 void Engine::funcPrefix(FunctionParam *i_param, const Keymap *i_keymap,
819                         BooleanType i_doesIgnoreModifiers)
820 {
821   if (!i_param->m_isPressed)
822     return;
823   
824   setCurrentKeymap(i_keymap, true);
825   
826   // generate prefixed event
827   generateEvents(i_param->m_c, m_currentKeymap, &Event::prefixed);
828   
829   m_isPrefix = true;
830   m_doesEditNextModifier = false;
831   m_doesIgnoreModifierForPrefix = !!i_doesIgnoreModifiers;
832
833   {
834     Acquire a(&m_log, 1);
835     m_log << _T("(") << i_keymap->getName() << _T(", ")
836           << (i_doesIgnoreModifiers ? _T("true") : _T("false")) << _T(")");
837   }
838 }
839
840 // other keymap's key
841 void Engine::funcKeymap(FunctionParam *i_param, const Keymap *i_keymap)
842 {
843   Current c(i_param->m_c);
844   c.m_keymap = i_keymap;
845   {
846     Acquire a(&m_log, 1);
847     m_log << _T("(") << c.m_keymap->getName() << _T(")") << std::endl;
848     i_param->m_doesNeedEndl = false;
849   }
850   generateKeyboardEvents(c);
851 }
852
853 // sync
854 void Engine::funcSync(FunctionParam *i_param)
855 {
856   if (i_param->m_isPressed)
857     generateModifierEvents(i_param->m_af->m_modifier);
858   if (!i_param->m_isPressed || m_currentFocusOfThread->m_isConsole)
859     return;
860   
861   Key *sync = m_setting->m_keyboard.getSyncKey();
862   if (sync->getScanCodesSize() == 0)
863     return;
864   const ScanCode *sc = sync->getScanCodes();
865   
866   // set variables exported from mayu.dll
867   g_hookData->m_syncKey = sc->m_scan;
868   g_hookData->m_syncKeyIsExtended = !!(sc->m_flags & ScanCode::E0E1);
869   m_isSynchronizing = true;
870   generateKeyEvent(sync, false, false);
871   
872   m_cs.release();
873   DWORD r = WaitForSingleObject(m_eSync, 5000);
874   if (r == WAIT_TIMEOUT)
875   {
876     Acquire a(&m_log, 0);
877     m_log << _T(" *FAILED*") << std::endl;
878   }
879   m_cs.acquire();
880   m_isSynchronizing = false;
881 }
882
883 // toggle lock
884 void Engine::funcToggle(FunctionParam *i_param, ModifierLockType i_lock,
885                         ToggleType i_toggle)
886 {
887   if (i_param->m_isPressed)                     // ignore PRESS
888     return;
889
890   Modifier::Type mt = static_cast<Modifier::Type>(i_lock);
891   switch (i_toggle)
892   {
893     case ToggleType_toggle:
894       m_currentLock.press(mt, !m_currentLock.isPressed(mt));
895       break;
896     case ToggleType_off:
897       m_currentLock.press(mt, false);
898       break;
899     case ToggleType_on:
900       m_currentLock.press(mt, true);
901       break;
902   }
903 }
904
905 // edit next user input key's modifier
906 void Engine::funcEditNextModifier(FunctionParam *i_param,
907                                   const Modifier &i_modifier)
908 {
909   if (!i_param->m_isPressed)
910     return;
911   
912   m_isPrefix = true;
913   m_doesEditNextModifier = true;
914   m_doesIgnoreModifierForPrefix = true;
915   m_modifierForNextKey = i_modifier;
916 }
917
918 // variable
919 void Engine::funcVariable(FunctionParam *i_param, int i_mag, int i_inc)
920 {
921   if (!i_param->m_isPressed)
922     return;
923   m_variable *= i_mag;
924   m_variable += i_inc;
925 }
926
927 // repeat N times
928 void Engine::funcRepeat(FunctionParam *i_param, const KeySeq *i_keySeq,
929                         int i_max)
930 {
931   if (i_param->m_isPressed)
932   {
933     int end = MIN(m_variable, i_max);
934     for (int i = 0; i < end - 1; ++ i)
935       generateKeySeqEvents(i_param->m_c, i_keySeq, Part_all);
936     if (0 < end)
937       generateKeySeqEvents(i_param->m_c, i_keySeq, Part_down);
938   }
939   else
940     generateKeySeqEvents(i_param->m_c, i_keySeq, Part_up);
941 }
942
943 // undefined (bell)
944 void Engine::funcUndefined(FunctionParam *i_param)
945 {
946   if (!i_param->m_isPressed)
947     return;
948   MessageBeep(MB_OK);
949 }
950
951 // ignore
952 void Engine::funcIgnore(FunctionParam *)
953 {
954   // do nothing
955 }
956
957 // post message
958 void Engine::funcPostMessage(FunctionParam *i_param, ToWindowType i_window,
959                              UINT i_message, WPARAM i_wParam, LPARAM i_lParam)
960 {
961   if (!i_param->m_isPressed)
962     return;
963
964   int window = static_cast<int>(i_window);
965   
966   HWND hwnd = i_param->m_hwnd;
967   if (0 < window)
968   {
969     for (int i = 0; i < window; ++ i)
970       hwnd = GetParent(hwnd);
971   }
972   else if (window == ToWindowType_toMainWindow)
973   {
974     while (true)
975     {
976       HWND p = GetParent(hwnd);
977       if (!p)
978         break;
979       hwnd = p;
980     }
981   }
982   else if (window == ToWindowType_toOverlappedWindow)
983   {
984     while (hwnd)
985     {
986 #ifdef MAYU64
987       LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
988 #else
989       LONG style = GetWindowLong(hwnd, GWL_STYLE);
990 #endif
991       if ((style & WS_CHILD) == 0)
992         break;
993       hwnd = GetParent(hwnd);
994     }
995   }
996
997   if (hwnd)
998     PostMessage(hwnd, i_message, i_wParam, i_lParam);
999 }
1000
1001
1002 // ShellExecute
1003 void Engine::funcShellExecute(FunctionParam *i_param,
1004                               const StrExprArg &/*i_operation*/,
1005                               const StrExprArg &/*i_file*/,
1006                               const StrExprArg &/*i_parameters*/,
1007                               const StrExprArg &/*i_directory*/,
1008                               ShowCommandType /*i_showCommand*/)
1009 {
1010   if (!i_param->m_isPressed)
1011     return;
1012   m_afShellExecute = i_param->m_af;
1013   PostMessage(m_hwndAssocWindow,
1014               WM_APP_engineNotify, EngineNotify_shellExecute, 0);
1015 }
1016
1017
1018 // shell execute
1019 void Engine::shellExecute()
1020 {
1021   Acquire a(&m_cs);
1022   
1023   FunctionData_ShellExecute *fd =
1024     reinterpret_cast<FunctionData_ShellExecute *>(
1025       m_afShellExecute->m_functionData);
1026   
1027   int r = (int)ShellExecute(
1028     NULL,
1029     fd->m_operation.eval().empty() ? _T("open") : fd->m_operation.eval().c_str(),
1030     fd->m_file.eval().empty() ? NULL : fd->m_file.eval().c_str(),
1031     fd->m_parameters.eval().empty() ? NULL : fd->m_parameters.eval().c_str(),
1032     fd->m_directory.eval().empty() ? NULL : fd->m_directory.eval().c_str(),
1033     fd->m_showCommand);
1034   if (32 < r)
1035     return; // success
1036
1037   typedef TypeTable<int> ErrorTable;
1038   static const ErrorTable errorTable[] =
1039   {
1040     { 0, _T("The operating system is out of memory or resources.") },
1041     { ERROR_FILE_NOT_FOUND, _T("The specified file was not found.") },
1042     { ERROR_PATH_NOT_FOUND, _T("The specified path was not found.") },
1043     { ERROR_BAD_FORMAT, _T("The .exe file is invalid ")
1044       _T("(non-Win32R .exe or error in .exe image).") },
1045     { SE_ERR_ACCESSDENIED,
1046       _T("The operating system denied access to the specified file.") },
1047     { SE_ERR_ASSOCINCOMPLETE,
1048       _T("The file name association is incomplete or invalid.") },
1049     { SE_ERR_DDEBUSY,
1050       _T("The DDE transaction could not be completed ")
1051       _T("because other DDE transactions were being processed. ") },
1052     { SE_ERR_DDEFAIL, _T("The DDE transaction failed.") },
1053     { SE_ERR_DDETIMEOUT, _T("The DDE transaction could not be completed ")
1054       _T("because the request timed out.") },
1055     { SE_ERR_DLLNOTFOUND,
1056       _T("The specified dynamic-link library was not found.") },
1057     { SE_ERR_FNF, _T("The specified file was not found.") },
1058     { SE_ERR_NOASSOC, _T("There is no application associated ")
1059       _T("with the given file name extension.") },
1060     { SE_ERR_OOM,
1061       _T("There was not enough memory to complete the operation.") },
1062     { SE_ERR_PNF, _T("The specified path was not found.") },
1063     { SE_ERR_SHARE, _T("A sharing violation occurred.") },
1064   };
1065
1066   tstring errorMessage(_T("Unknown error."));
1067   getTypeName(&errorMessage, r, errorTable, NUMBER_OF(errorTable));
1068   
1069   Acquire b(&m_log, 0);
1070   m_log << _T("error: ") << fd << _T(": ") << errorMessage << std::endl;
1071 }
1072
1073
1074 struct EnumWindowsForSetForegroundWindowParam
1075 {
1076   const FunctionData_SetForegroundWindow *m_fd;
1077   HWND m_hwnd;
1078
1079 public:
1080   EnumWindowsForSetForegroundWindowParam(
1081     const FunctionData_SetForegroundWindow *i_fd)
1082     : m_fd(i_fd),
1083       m_hwnd(NULL)
1084   {
1085   }
1086 };
1087
1088
1089 /// enum windows for SetForegroundWindow
1090 static BOOL CALLBACK enumWindowsForSetForegroundWindow(
1091   HWND i_hwnd, LPARAM i_lParam)
1092 {
1093   EnumWindowsForSetForegroundWindowParam &ep =
1094     *reinterpret_cast<EnumWindowsForSetForegroundWindowParam *>(i_lParam);
1095
1096   _TCHAR name[GANA_MAX_ATOM_LENGTH];
1097   if (!GetClassName(i_hwnd, name, NUMBER_OF(name)))
1098     return TRUE;
1099   tsmatch what;
1100   if (!boost::regex_search(tstring(name), what, ep.m_fd->m_windowClassName))
1101     if (ep.m_fd->m_logicalOp == LogicalOperatorType_and)
1102       return TRUE;                              // match failed
1103
1104   if (ep.m_fd->m_logicalOp == LogicalOperatorType_and)
1105   {
1106     if (GetWindowText(i_hwnd, name, NUMBER_OF(name)) == 0)
1107       name[0] = _T('\0');
1108     if (!boost::regex_search(tstring(name), what,
1109                              ep.m_fd->m_windowTitleName))
1110       return TRUE;                              // match failed
1111   }
1112
1113   ep.m_hwnd = i_hwnd;
1114   return FALSE;
1115 }
1116
1117
1118 /// SetForegroundWindow
1119 void Engine::funcSetForegroundWindow(FunctionParam *i_param, const tregex &,
1120                                      LogicalOperatorType , const tregex &)
1121 {
1122   if (!i_param->m_isPressed)
1123     return;
1124   EnumWindowsForSetForegroundWindowParam
1125     ep(static_cast<const FunctionData_SetForegroundWindow *>(
1126       i_param->m_af->m_functionData));
1127   EnumWindows(enumWindowsForSetForegroundWindow,
1128               reinterpret_cast<LPARAM>(&ep));
1129   if (ep.m_hwnd)
1130     PostMessage(m_hwndAssocWindow,
1131                 WM_APP_engineNotify, EngineNotify_setForegroundWindow,
1132                 reinterpret_cast<LPARAM>(ep.m_hwnd));
1133
1134 }
1135
1136
1137 // load setting
1138 void Engine::funcLoadSetting(FunctionParam *i_param, const StrExprArg &i_name)
1139 {
1140   if (!i_param->m_isPressed)
1141     return;
1142   if (!i_name.eval().empty())
1143   {
1144     // set MAYU_REGISTRY_ROOT\.mayuIndex which name is same with i_name
1145     Registry reg(MAYU_REGISTRY_ROOT);
1146
1147     tregex split(_T("^([^;]*);([^;]*);(.*)$"));
1148     tstringi dot_mayu;
1149     for (size_t i = 0; i < MAX_MAYU_REGISTRY_ENTRIES; ++ i)
1150     {
1151       _TCHAR buf[100];
1152       _sntprintf(buf, NUMBER_OF(buf), _T(".mayu%d"), i);
1153       if (!reg.read(buf, &dot_mayu))
1154         break;
1155       
1156       tsmatch what;
1157       if (boost::regex_match(dot_mayu, what, split) &&
1158           what.str(1) == i_name.eval())
1159       { 
1160         reg.write(_T(".mayuIndex"), i);
1161         goto success;
1162       }
1163     }
1164
1165     {
1166       Acquire a(&m_log, 0);
1167       m_log << _T("unknown setting name: ") << i_name;
1168     }
1169     return;
1170     
1171     success: ;
1172   }
1173   PostMessage(m_hwndAssocWindow,
1174               WM_APP_engineNotify, EngineNotify_loadSetting, 0);
1175 }
1176
1177 // virtual key
1178 void Engine::funcVK(FunctionParam *i_param, VKey i_vkey)
1179 {
1180   long key = static_cast<long>(i_vkey);
1181   BYTE vkey = static_cast<BYTE>(i_vkey);
1182   bool isExtended = !!(key & VKey_extended);
1183   bool isUp       = !i_param->m_isPressed && !!(key & VKey_released);
1184   bool isDown     = i_param->m_isPressed && !!(key & VKey_pressed);
1185   
1186   if (vkey == VK_LBUTTON && isDown)
1187     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
1188   else if (vkey == VK_LBUTTON && isUp)
1189     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
1190   else if (vkey == VK_MBUTTON && isDown)
1191     mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0);
1192   else if (vkey == VK_MBUTTON && isUp)
1193     mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
1194   else if (vkey == VK_RBUTTON && isDown)
1195     mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
1196   else if (vkey == VK_RBUTTON && isUp)
1197     mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
1198   else if (vkey == VK_XBUTTON1 && isDown)
1199     mouse_event(MOUSEEVENTF_XDOWN, 0, 0, XBUTTON1, 0);
1200   else if (vkey == VK_XBUTTON1 && isUp)
1201     mouse_event(MOUSEEVENTF_XUP, 0, 0, XBUTTON1, 0);
1202   else if (vkey == VK_XBUTTON2 && isDown)
1203     mouse_event(MOUSEEVENTF_XDOWN, 0, 0, XBUTTON2, 0);
1204   else if (vkey == VK_XBUTTON2 && isUp)
1205     mouse_event(MOUSEEVENTF_XUP, 0, 0, XBUTTON2, 0);
1206   else if (isUp || isDown)
1207     keybd_event(vkey,
1208                 static_cast<BYTE>(MapVirtualKey(vkey, 0)),
1209                 (isExtended ? KEYEVENTF_EXTENDEDKEY : 0) |
1210                 (i_param->m_isPressed ? 0 : KEYEVENTF_KEYUP), 0);
1211 }
1212
1213 // wait
1214 void Engine::funcWait(FunctionParam *i_param, int i_milliSecond)
1215 {
1216   if (!i_param->m_isPressed)
1217     return;
1218   if (i_milliSecond < 0 || 5000 < i_milliSecond)        // too long wait
1219     return;
1220   
1221   m_isSynchronizing = true;
1222   m_cs.release();
1223   Sleep(i_milliSecond);
1224   m_cs.acquire();
1225   m_isSynchronizing = false;
1226 }
1227
1228 // investigate WM_COMMAND, WM_SYSCOMMAND
1229 void Engine::funcInvestigateCommand(FunctionParam *i_param)
1230 {
1231   if (!i_param->m_isPressed)
1232     return;
1233   Acquire a(&m_log, 0);
1234   g_hookData->m_doesNotifyCommand = !g_hookData->m_doesNotifyCommand;
1235   if (g_hookData->m_doesNotifyCommand)
1236     m_log << _T(" begin") << std::endl;
1237   else
1238     m_log << _T(" end") << std::endl;
1239 }
1240
1241 // show mayu dialog box
1242 void Engine::funcMayuDialog(FunctionParam *i_param, MayuDialogType i_dialog,
1243                             ShowCommandType i_showCommand)
1244 {
1245   if (!i_param->m_isPressed)
1246     return;
1247   PostMessage(getAssociatedWndow(), WM_APP_engineNotify, EngineNotify_showDlg,
1248               static_cast<LPARAM>(i_dialog) |
1249               static_cast<LPARAM>(i_showCommand));
1250 }
1251
1252 // describe bindings
1253 void Engine::funcDescribeBindings(FunctionParam *i_param)
1254 {
1255   if (!i_param->m_isPressed)
1256     return;
1257   {
1258     Acquire a(&m_log, 1);
1259     m_log << std::endl;
1260   }
1261   describeBindings();
1262 }
1263
1264 // show help message
1265 void Engine::funcHelpMessage(FunctionParam *i_param, const StrExprArg &i_title,
1266                              const StrExprArg &i_message)
1267 {
1268   if (!i_param->m_isPressed)
1269     return;
1270
1271   m_helpTitle = i_title.eval();
1272   m_helpMessage = i_message.eval();
1273   bool doesShow = !(i_title.eval().size() == 0 && i_message.eval().size() == 0);
1274   PostMessage(getAssociatedWndow(), WM_APP_engineNotify,
1275               EngineNotify_helpMessage, doesShow);
1276 }
1277
1278 // show variable
1279 void Engine::funcHelpVariable(FunctionParam *i_param, const StrExprArg &i_title)
1280 {
1281   if (!i_param->m_isPressed)
1282     return;
1283
1284   _TCHAR buf[20];
1285   _sntprintf(buf, NUMBER_OF(buf), _T("%d"), m_variable);
1286
1287   m_helpTitle = i_title.eval();
1288   m_helpMessage = buf;
1289   PostMessage(getAssociatedWndow(), WM_APP_engineNotify,
1290               EngineNotify_helpMessage, true);
1291 }
1292
1293 // raise window
1294 void Engine::funcWindowRaise(FunctionParam *i_param,
1295                              TargetWindowType i_twt)
1296 {
1297   HWND hwnd;
1298   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1299     return;
1300   SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
1301                SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);
1302 }
1303
1304 // lower window
1305 void Engine::funcWindowLower(FunctionParam *i_param, TargetWindowType i_twt)
1306 {
1307   HWND hwnd;
1308   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1309     return;
1310   SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0,
1311                SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);
1312 }
1313
1314 // minimize window
1315 void Engine::funcWindowMinimize(FunctionParam *i_param, TargetWindowType i_twt)
1316 {
1317   HWND hwnd;
1318   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1319     return;
1320   PostMessage(hwnd, WM_SYSCOMMAND,
1321               IsIconic(hwnd) ? SC_RESTORE : SC_MINIMIZE, 0);
1322 }
1323
1324 // maximize window
1325 void Engine::funcWindowMaximize(FunctionParam *i_param, TargetWindowType i_twt)
1326 {
1327   HWND hwnd;
1328   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1329     return;
1330   PostMessage(hwnd, WM_SYSCOMMAND,
1331               IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, 0);
1332 }
1333
1334 // maximize horizontally or virtically
1335 void Engine::funcWindowHVMaximize(FunctionParam *i_param,
1336                                   BooleanType i_isHorizontal,
1337                                   TargetWindowType i_twt)
1338 {
1339   HWND hwnd;
1340   RECT rc, rcd;
1341   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt, &rc, &rcd))
1342     return;
1343
1344   // erase non window
1345   while (true)
1346   {
1347     WindowPositions::iterator i = m_windowPositions.begin();
1348     WindowPositions::iterator end = m_windowPositions.end();
1349     for (; i != end; ++ i)
1350       if (!IsWindow((*i).m_hwnd))
1351         break;
1352     if (i == end)
1353       break;
1354     m_windowPositions.erase(i);
1355   }
1356
1357   // find target
1358   WindowPositions::iterator i = m_windowPositions.begin();
1359   WindowPositions::iterator end = m_windowPositions.end();
1360   WindowPositions::iterator target = end;
1361   for (; i != end; ++ i)
1362     if ((*i).m_hwnd == hwnd)
1363     {
1364       target = i;
1365       break;
1366     }
1367   
1368   if (IsZoomed(hwnd))
1369     PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1370   else
1371   {
1372     WindowPosition::Mode mode = WindowPosition::Mode_normal;
1373     
1374     if (target != end)
1375     {
1376       WindowPosition &wp = *target;
1377       rc = wp.m_rc;
1378       if (wp.m_mode == WindowPosition::Mode_HV)
1379         mode = wp.m_mode =
1380           i_isHorizontal ? WindowPosition::Mode_V : WindowPosition::Mode_H;
1381       else if (( i_isHorizontal && wp.m_mode == WindowPosition::Mode_V) ||
1382                (!i_isHorizontal && wp.m_mode == WindowPosition::Mode_H))
1383         mode = wp.m_mode = WindowPosition::Mode_HV;
1384       else
1385         m_windowPositions.erase(target);
1386     }
1387     else
1388     {
1389       mode = i_isHorizontal ? WindowPosition::Mode_H : WindowPosition::Mode_V;
1390       m_windowPositions.push_front(WindowPosition(hwnd, rc, mode));
1391     }
1392     
1393     if (static_cast<int>(mode) & static_cast<int>(WindowPosition::Mode_H))
1394       rc.left = rcd.left, rc.right = rcd.right;
1395     if (static_cast<int>(mode) & static_cast<int>(WindowPosition::Mode_V))
1396       rc.top = rcd.top, rc.bottom = rcd.bottom;
1397     
1398     asyncMoveWindow(hwnd, rc.left, rc.top, rcWidth(&rc), rcHeight(&rc));
1399   }
1400 }
1401
1402 // maximize window horizontally
1403 void Engine::funcWindowHMaximize(FunctionParam *i_param,
1404                                  TargetWindowType i_twt)
1405 {
1406   funcWindowHVMaximize(i_param, BooleanType_true, i_twt);
1407 }
1408
1409 // maximize window virtically
1410 void Engine::funcWindowVMaximize(FunctionParam *i_param,
1411                                  TargetWindowType i_twt)
1412 {
1413   funcWindowHVMaximize(i_param, BooleanType_false, i_twt);
1414 }
1415
1416 // move window
1417 void Engine::funcWindowMove(FunctionParam *i_param, int i_dx, int i_dy,
1418                             TargetWindowType i_twt)
1419 {
1420   funcWindowMoveTo(i_param, GravityType_C, i_dx, i_dy, i_twt);
1421 }
1422
1423 // move window to ...
1424 void Engine::funcWindowMoveTo(FunctionParam *i_param,
1425                               GravityType i_gravityType,
1426                               int i_dx, int i_dy, TargetWindowType i_twt)
1427 {
1428   HWND hwnd;
1429   RECT rc, rcd;
1430   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt, &rc, &rcd))
1431     return;
1432   
1433   int x = rc.left + i_dx;
1434   int y = rc.top + i_dy;
1435
1436   if (i_gravityType & GravityType_N)
1437     y = i_dy + rcd.top;
1438   if (i_gravityType & GravityType_E)
1439     x = i_dx + rcd.right - rcWidth(&rc);
1440   if (i_gravityType & GravityType_W)
1441     x = i_dx + rcd.left;
1442   if (i_gravityType & GravityType_S)
1443     y = i_dy + rcd.bottom - rcHeight(&rc);
1444   asyncMoveWindow(hwnd, x, y);
1445 }
1446
1447
1448 // move window visibly
1449 void Engine::funcWindowMoveVisibly(FunctionParam *i_param,
1450                                    TargetWindowType i_twt)
1451 {
1452   HWND hwnd;
1453   RECT rc, rcd;
1454   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt, &rc, &rcd))
1455     return;
1456
1457   int x = rc.left;
1458   int y = rc.top;
1459   if (rc.left < rcd.left)
1460     x = rcd.left;
1461   else if (rcd.right < rc.right)
1462     x = rcd.right - rcWidth(&rc);
1463   if (rc.top < rcd.top)
1464     y = rcd.top;
1465   else if (rcd.bottom < rc.bottom)
1466     y = rcd.bottom - rcHeight(&rc);
1467   asyncMoveWindow(hwnd, x, y);
1468 }
1469
1470
1471 struct EnumDisplayMonitorsForWindowMonitorToParam
1472 {
1473   std::vector<HMONITOR> m_monitors;
1474   std::vector<MONITORINFO> m_monitorinfos;
1475   int m_primaryMonitorIdx;
1476   int m_currentMonitorIdx;
1477
1478   HMONITOR m_hmon;
1479
1480 public:
1481   EnumDisplayMonitorsForWindowMonitorToParam(HMONITOR i_hmon)
1482     : m_hmon(i_hmon),
1483       m_primaryMonitorIdx(-1), m_currentMonitorIdx(-1)
1484   {
1485   }
1486 };
1487
1488 static BOOL CALLBACK enumDisplayMonitorsForWindowMonitorTo(
1489   HMONITOR i_hmon, HDC i_hdc, LPRECT i_rcMonitor, LPARAM i_data)
1490 {
1491   EnumDisplayMonitorsForWindowMonitorToParam &ep =
1492     *reinterpret_cast<EnumDisplayMonitorsForWindowMonitorToParam *>(i_data);
1493
1494   ep.m_monitors.push_back(i_hmon);
1495
1496   MONITORINFO mi;
1497   mi.cbSize = sizeof(mi);
1498   getMonitorInfo(i_hmon, &mi);
1499   ep.m_monitorinfos.push_back(mi);
1500
1501   if(mi.dwFlags & MONITORINFOF_PRIMARY)
1502     ep.m_primaryMonitorIdx = ep.m_monitors.size() - 1;
1503   if(i_hmon == ep.m_hmon)
1504     ep.m_currentMonitorIdx = ep.m_monitors.size() - 1;
1505
1506   return TRUE;
1507 }
1508
1509 /// move window to other monitor
1510 void Engine::funcWindowMonitorTo(
1511     FunctionParam *i_param, WindowMonitorFromType i_fromType, int i_monitor,
1512     BooleanType i_adjustPos, BooleanType i_adjustSize)
1513 {
1514   HWND hwnd;
1515   if(! getSuitableWindow(i_param, &hwnd))
1516     return;
1517
1518   HMONITOR hmonCur;
1519   hmonCur = monitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
1520
1521   EnumDisplayMonitorsForWindowMonitorToParam ep(hmonCur);
1522   enumDisplayMonitors(NULL, NULL, enumDisplayMonitorsForWindowMonitorTo,
1523                       reinterpret_cast<LPARAM>(&ep));
1524   if(ep.m_monitors.size() < 1 ||
1525      ep.m_primaryMonitorIdx < 0 || ep.m_currentMonitorIdx < 0)
1526     return;
1527
1528   int targetIdx;
1529   switch(i_fromType) {
1530   case WindowMonitorFromType_primary:
1531     targetIdx = (ep.m_primaryMonitorIdx + i_monitor) % ep.m_monitors.size();
1532     break;
1533
1534   case WindowMonitorFromType_current:
1535     targetIdx = (ep.m_currentMonitorIdx + i_monitor) % ep.m_monitors.size();
1536     break;
1537   }
1538   if(ep.m_currentMonitorIdx == targetIdx)
1539     return;
1540
1541   RECT rcCur, rcTarget, rcWin;
1542   rcCur = ep.m_monitorinfos[ep.m_currentMonitorIdx].rcWork;
1543   rcTarget = ep.m_monitorinfos[targetIdx].rcWork;
1544   GetWindowRect(hwnd, &rcWin);
1545
1546   int x = rcTarget.left + (rcWin.left - rcCur.left);
1547   int y = rcTarget.top + (rcWin.top - rcCur.top);
1548   int w = rcWidth(&rcWin);
1549   int h = rcHeight(&rcWin);
1550
1551   if(i_adjustPos) {
1552     if(x + w > rcTarget.right)
1553       x = rcTarget.right - w;
1554     if(x < rcTarget.left)
1555       x = rcTarget.left;
1556     if(w > rcWidth(&rcTarget)) {
1557       x = rcTarget.left;
1558       w = rcWidth(&rcTarget);
1559     }
1560
1561     if(y + h > rcTarget.bottom)
1562       y = rcTarget.bottom - h;
1563     if(y < rcTarget.top)
1564       y = rcTarget.top;
1565     if(h > rcHeight(&rcTarget)) {
1566       y = rcTarget.top;
1567       h = rcHeight(&rcTarget);
1568     }
1569   }
1570
1571   if(i_adjustPos && i_adjustSize) {
1572     if(IsZoomed(hwnd))
1573       PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1574     asyncMoveWindow(hwnd, x, y, w, h);
1575   } else {
1576     asyncMoveWindow(hwnd, x, y);
1577   }
1578 }
1579
1580 /// move window to other monitor
1581 void Engine::funcWindowMonitor(
1582     FunctionParam *i_param, int i_monitor,
1583     BooleanType i_adjustPos, BooleanType i_adjustSize)
1584 {
1585   funcWindowMonitorTo(i_param, WindowMonitorFromType_primary, i_monitor,
1586                       i_adjustPos, i_adjustSize);
1587 }
1588
1589
1590 //
1591 void Engine::funcWindowClingToLeft(FunctionParam *i_param,
1592                                    TargetWindowType i_twt)
1593 {
1594   funcWindowMoveTo(i_param, GravityType_W, 0, 0, i_twt);
1595 }
1596
1597 //
1598 void Engine::funcWindowClingToRight(FunctionParam *i_param,
1599                                     TargetWindowType i_twt)
1600 {
1601   funcWindowMoveTo(i_param, GravityType_E, 0, 0, i_twt);
1602 }
1603
1604 //
1605 void Engine::funcWindowClingToTop(FunctionParam *i_param,
1606                                   TargetWindowType i_twt)
1607 {
1608   funcWindowMoveTo(i_param, GravityType_N, 0, 0, i_twt);
1609 }
1610
1611 //
1612 void Engine::funcWindowClingToBottom(FunctionParam *i_param,
1613                                      TargetWindowType i_twt)
1614 {
1615   funcWindowMoveTo(i_param, GravityType_S, 0, 0, i_twt);
1616 }
1617
1618 // close window
1619 void Engine::funcWindowClose(FunctionParam *i_param, TargetWindowType i_twt)
1620 {
1621   HWND hwnd;
1622   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1623     return;
1624   PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
1625 }
1626
1627 // toggle top-most flag of the window
1628 void Engine::funcWindowToggleTopMost(FunctionParam *i_param)
1629 {
1630   HWND hwnd;
1631   if (!getSuitableWindow(i_param, &hwnd))
1632     return;
1633   SetWindowPos(
1634     hwnd,
1635 #ifdef MAYU64
1636     (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) ?
1637 #else
1638     (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) ?
1639 #endif
1640     HWND_NOTOPMOST : HWND_TOPMOST,
1641     0, 0, 0, 0,
1642     SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);
1643 }
1644
1645 // identify the window
1646 void Engine::funcWindowIdentify(FunctionParam *i_param)
1647 {
1648   if (!i_param->m_isPressed)
1649     return;
1650
1651   _TCHAR className[GANA_MAX_ATOM_LENGTH];
1652   bool ok = false;
1653   if (GetClassName(i_param->m_hwnd, className, NUMBER_OF(className)))
1654   {
1655     if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0)
1656     {
1657       _TCHAR titleName[1024];
1658       if (GetWindowText(i_param->m_hwnd, titleName, NUMBER_OF(titleName)) == 0)
1659         titleName[0] = _T('\0');
1660       {
1661         Acquire a(&m_log, 1);
1662         m_log << _T("HWND:\t") << std::hex
1663               << reinterpret_cast<int>(i_param->m_hwnd)
1664               << std::dec << std::endl;
1665       }
1666       Acquire a(&m_log, 0);
1667       m_log << _T("CLASS:\t") << className << std::endl;
1668       m_log << _T("TITLE:\t") << titleName << std::endl;
1669
1670       HWND hwnd = getToplevelWindow(i_param->m_hwnd, NULL);
1671       RECT rc;
1672       GetWindowRect(hwnd, &rc);
1673       m_log << _T("Toplevel Window Position/Size: (")
1674             << rc.left << _T(", ") << rc.top << _T(") / (")
1675             << rcWidth(&rc) << _T("x") << rcHeight(&rc)
1676             << _T(")") << std::endl;
1677       
1678       SystemParametersInfo(SPI_GETWORKAREA, 0, (void *)&rc, FALSE);
1679       m_log << _T("Desktop Window Position/Size: (")
1680             << rc.left << _T(", ") << rc.top << _T(") / (")
1681             << rcWidth(&rc) << _T("x") << rcHeight(&rc)
1682             << _T(")") << std::endl;
1683
1684       m_log << std::endl;
1685       ok = true;
1686     }
1687   }
1688   if (!ok)
1689   {
1690     UINT WM_MAYU_MESSAGE = RegisterWindowMessage(
1691                 addSessionId(WM_MAYU_MESSAGE_NAME).c_str());
1692     CHECK_TRUE( PostMessage(i_param->m_hwnd, WM_MAYU_MESSAGE,
1693                             MayuMessage_notifyName, 0) );
1694   }
1695 }
1696
1697 // set alpha blending parameter to the window
1698 void Engine::funcWindowSetAlpha(FunctionParam *i_param, int i_alpha)
1699 {
1700   HWND hwnd;
1701   if (!getSuitableWindow(i_param, &hwnd))
1702     return;
1703   
1704   if (i_alpha < 0)      // remove all alpha
1705   {
1706     for (WindowsWithAlpha::iterator i = m_windowsWithAlpha.begin(); 
1707          i != m_windowsWithAlpha.end(); ++ i)
1708     {
1709 #ifdef MAYU64
1710       SetWindowLongPtr(*i, GWL_EXSTYLE,
1711                     GetWindowLongPtr(*i, GWL_EXSTYLE) & ~WS_EX_LAYERED);
1712 #else
1713       SetWindowLong(*i, GWL_EXSTYLE,
1714                     GetWindowLong(*i, GWL_EXSTYLE) & ~WS_EX_LAYERED);
1715 #endif
1716       RedrawWindow(*i, NULL, NULL,
1717                    RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
1718     }
1719     m_windowsWithAlpha.clear();
1720   }
1721   else
1722   {
1723 #ifdef MAYU64
1724     LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
1725 #else
1726     LONG exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
1727 #endif
1728     if (exStyle & WS_EX_LAYERED)        // remove alpha
1729     {
1730       WindowsWithAlpha::iterator
1731         i = std::find(m_windowsWithAlpha.begin(), m_windowsWithAlpha.end(),
1732                       hwnd);
1733       if (i == m_windowsWithAlpha.end())
1734         return; // already layered by the application
1735     
1736       m_windowsWithAlpha.erase(i);
1737     
1738 #ifdef MAYU64
1739       SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
1740 #else    
1741       SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
1742 #endif
1743     }
1744     else        // add alpha
1745     {
1746 #ifdef MAYU64
1747       SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
1748 #else
1749       SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
1750 #endif
1751       i_alpha %= 101;
1752       if (!setLayeredWindowAttributes(hwnd, 0,
1753                                       (BYTE)(255 * i_alpha / 100), LWA_ALPHA))
1754       {
1755         Acquire a(&m_log, 0);
1756         m_log << _T("error: &WindowSetAlpha(") << i_alpha
1757               << _T(") failed for HWND: ") << std::hex
1758               << hwnd << std::dec << std::endl;
1759         return;
1760       }
1761       m_windowsWithAlpha.push_front(hwnd);
1762     }
1763     RedrawWindow(hwnd, NULL, NULL,
1764                  RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
1765   }
1766 }
1767
1768
1769 // redraw the window
1770 void Engine::funcWindowRedraw(FunctionParam *i_param)
1771 {
1772   HWND hwnd;
1773   if (!getSuitableWindow(i_param, &hwnd))
1774     return;
1775   RedrawWindow(hwnd, NULL, NULL,
1776                RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
1777 }
1778
1779 // resize window to
1780 void Engine::funcWindowResizeTo(FunctionParam *i_param, int i_width,
1781                                 int i_height, TargetWindowType i_twt)
1782 {
1783   HWND hwnd;
1784   RECT rc, rcd;
1785   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt, &rc, &rcd))
1786     return;
1787   
1788   if (i_width == 0)
1789     i_width = rcWidth(&rc);
1790   else if (i_width < 0)
1791     i_width += rcWidth(&rcd);
1792   
1793   if (i_height == 0)
1794     i_height = rcHeight(&rc);
1795   else if (i_height < 0)
1796     i_height += rcHeight(&rcd);
1797   
1798   asyncResize(hwnd, i_width, i_height);
1799 }
1800
1801 // move the mouse cursor
1802 void Engine::funcMouseMove(FunctionParam *i_param, int i_dx, int i_dy)
1803 {
1804   if (!i_param->m_isPressed)
1805     return;
1806   POINT pt;
1807   GetCursorPos(&pt);
1808   SetCursorPos(pt.x + i_dx, pt.y + i_dy);
1809 }
1810
1811 // send a mouse-wheel-message to Windows
1812 void Engine::funcMouseWheel(FunctionParam *i_param, int i_delta)
1813 {
1814   if (!i_param->m_isPressed)
1815     return;
1816   mouse_event(MOUSEEVENTF_WHEEL, 0, 0, i_delta, 0);
1817 }
1818
1819 // convert the contents of the Clipboard to upper case
1820 void Engine::funcClipboardChangeCase(FunctionParam *i_param,
1821                                      BooleanType i_doesConvertToUpperCase)
1822 {
1823   if (!i_param->m_isPressed)
1824     return;
1825   
1826   HGLOBAL hdata;
1827   const _TCHAR *text = getTextFromClipboard(&hdata);
1828   HGLOBAL hdataNew = NULL;
1829   if (text)
1830   {
1831     int size = static_cast<int>(GlobalSize(hdata));
1832     hdataNew = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
1833     if (hdataNew)
1834     {
1835       if (_TCHAR *dataNew = reinterpret_cast<_TCHAR *>(GlobalLock(hdataNew)))
1836       {
1837         std::memcpy(dataNew, text, size);
1838         _TCHAR *dataEnd = dataNew + size;
1839         while (dataNew < dataEnd && *dataNew)
1840         {
1841           _TCHAR c = *dataNew;
1842           if (_istlead(c))
1843             dataNew += 2;
1844           else
1845             *dataNew++ =
1846               i_doesConvertToUpperCase ? _totupper(c) : _totlower(c);
1847         }
1848         GlobalUnlock(hdataNew);
1849       }
1850     }
1851   }
1852   closeClipboard(hdata, hdataNew);
1853 }
1854
1855 // convert the contents of the Clipboard to upper case
1856 void Engine::funcClipboardUpcaseWord(FunctionParam *i_param)
1857 {
1858   funcClipboardChangeCase(i_param, BooleanType_true);
1859 }
1860
1861 // convert the contents of the Clipboard to lower case
1862 void Engine::funcClipboardDowncaseWord(FunctionParam *i_param)
1863 {
1864   funcClipboardChangeCase(i_param, BooleanType_false);
1865 }
1866
1867 // set the contents of the Clipboard to the string
1868 void Engine::funcClipboardCopy(FunctionParam *i_param, const StrExprArg &i_text)
1869 {
1870   if (!i_param->m_isPressed)
1871     return;
1872   if (!OpenClipboard(NULL))
1873     return;
1874   
1875   HGLOBAL hdataNew =
1876     GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
1877                 (i_text.eval().size() + 1) * sizeof(_TCHAR));
1878   if (!hdataNew)
1879     return;
1880   _TCHAR *dataNew = reinterpret_cast<_TCHAR *>(GlobalLock(hdataNew));
1881   _tcscpy(dataNew, i_text.eval().c_str());
1882   GlobalUnlock(hdataNew);
1883   closeClipboard(NULL, hdataNew);
1884 }
1885
1886 //
1887 void Engine::funcEmacsEditKillLinePred(
1888   FunctionParam *i_param, const KeySeq *i_keySeq1, const KeySeq *i_keySeq2)
1889 {
1890   m_emacsEditKillLine.m_doForceReset = false;
1891   if (!i_param->m_isPressed)
1892     return;
1893   
1894   int r = m_emacsEditKillLine.pred();
1895   const KeySeq *keySeq;
1896   if (r == 1)
1897     keySeq = i_keySeq1;
1898   else if (r == 2)
1899     keySeq = i_keySeq2;
1900   else // r == 0
1901     return;
1902   ASSERT(keySeq);
1903   generateKeySeqEvents(i_param->m_c, keySeq, Part_all);
1904 }
1905
1906 //
1907 void Engine::funcEmacsEditKillLineFunc(FunctionParam *i_param)
1908 {
1909   if (!i_param->m_isPressed)
1910     return;
1911   m_emacsEditKillLine.func();
1912   m_emacsEditKillLine.m_doForceReset = false;
1913 }
1914
1915 // clear log
1916 void Engine::funcLogClear(FunctionParam *i_param)
1917 {
1918   if (!i_param->m_isPressed)
1919     return;
1920   PostMessage(getAssociatedWndow(), WM_APP_engineNotify,
1921               EngineNotify_clearLog, 0);
1922 }
1923
1924 // recenter
1925 void Engine::funcRecenter(FunctionParam *i_param)
1926 {
1927   if (!i_param->m_isPressed)
1928     return;
1929   if (m_hwndFocus)
1930   {
1931     UINT WM_MAYU_MESSAGE = RegisterWindowMessage(
1932                 addSessionId(WM_MAYU_MESSAGE_NAME).c_str());
1933     PostMessage(m_hwndFocus, WM_MAYU_MESSAGE, MayuMessage_funcRecenter, 0);
1934   }
1935 }
1936
1937 // set IME open status
1938 void Engine::funcSetImeStatus(FunctionParam *i_param, ToggleType i_toggle)
1939 {
1940   if (!i_param->m_isPressed)
1941     return;
1942   if (m_hwndFocus)
1943   {
1944     UINT WM_MAYU_MESSAGE = RegisterWindowMessage(
1945                 addSessionId(WM_MAYU_MESSAGE_NAME).c_str());
1946     int status = -1;
1947     switch (i_toggle)
1948     {
1949       case ToggleType_toggle:
1950         status = -1;
1951         break;
1952       case ToggleType_off:
1953         status = 0;
1954         break;
1955       case ToggleType_on:
1956         status = 1;
1957         break;
1958     }
1959     PostMessage(m_hwndFocus, WM_MAYU_MESSAGE, MayuMessage_funcSetImeStatus, status);
1960   }
1961 }
1962
1963 // set IME open status
1964 void Engine::funcSetImeString(FunctionParam *i_param, const StrExprArg &i_data)
1965 {
1966   if (!i_param->m_isPressed)
1967     return;
1968   if (m_hwndFocus)
1969   {
1970     UINT WM_MAYU_MESSAGE = RegisterWindowMessage(
1971                 addSessionId(WM_MAYU_MESSAGE_NAME).c_str());
1972     PostMessage(m_hwndFocus, WM_MAYU_MESSAGE, MayuMessage_funcSetImeString, i_data.eval().size() * sizeof(_TCHAR));
1973
1974     DWORD len = 0;
1975     DWORD error;
1976     DisconnectNamedPipe(m_hookPipe);
1977     ConnectNamedPipe(m_hookPipe, NULL);
1978     error = WriteFile(m_hookPipe, i_data.eval().c_str(),
1979                       i_data.eval().size() * sizeof(_TCHAR),
1980                       &len, NULL);
1981
1982     //FlushFileBuffers(m_hookPipe);
1983   }
1984 }
1985
1986 // Direct SSTP Server
1987 class DirectSSTPServer
1988 {
1989 public:
1990   tstring m_path;
1991   HWND m_hwnd;
1992   tstring m_name;
1993   tstring m_keroname;
1994
1995 public:
1996   DirectSSTPServer()
1997     : m_hwnd(NULL)
1998   {
1999   }
2000 };
2001
2002
2003 class ParseDirectSSTPData
2004 {
2005   typedef boost::match_results<boost::regex::const_iterator> MR;
2006
2007 public:
2008   typedef std::map<tstring, DirectSSTPServer> DirectSSTPServers;
2009
2010 private:
2011   DirectSSTPServers *m_directSSTPServers;
2012   
2013 public:
2014   // constructor
2015   ParseDirectSSTPData(DirectSSTPServers *i_directSSTPServers)
2016     : m_directSSTPServers(i_directSSTPServers)
2017   {
2018   }
2019   
2020   bool operator()(const MR& i_what)
2021   {
2022 #ifdef _UNICODE
2023     tstring id(to_wstring(std::string(i_what[1].first, i_what[1].second)));
2024     tstring member(to_wstring(std::string(i_what[2].first, i_what[2].second)));
2025     tstring value(to_wstring(std::string(i_what[3].first, i_what[3].second)));
2026 #else
2027     tstring id(i_what[1].first, i_what[1].second);
2028     tstring member(i_what[2].first, i_what[2].second);
2029     tstring value(i_what[3].first, i_what[3].second);
2030 #endif
2031
2032     if (member == _T("path"))
2033       (*m_directSSTPServers)[id].m_path = value;
2034     else if (member == _T("hwnd"))
2035       (*m_directSSTPServers)[id].m_hwnd =
2036         reinterpret_cast<HWND>(_ttoi(value.c_str()));
2037     else if (member == _T("name"))
2038       (*m_directSSTPServers)[id].m_name = value;
2039     else if (member == _T("keroname"))
2040       (*m_directSSTPServers)[id].m_keroname = value;
2041     return true; 
2042   }
2043 };
2044
2045 // Direct SSTP
2046 void Engine::funcDirectSSTP(FunctionParam *i_param,
2047                             const tregex &i_name,
2048                             const StrExprArg &i_protocol,
2049                             const std::list<tstringq> &i_headers)
2050 {
2051   if (!i_param->m_isPressed)
2052     return;
2053
2054   // check Direct SSTP server exist ?
2055   if (HANDLE hm = OpenMutex(MUTEX_ALL_ACCESS, FALSE, _T("sakura")))
2056     CloseHandle(hm);
2057   else
2058   {
2059     Acquire a(&m_log, 0);
2060     m_log << _T(" Error(1): Direct SSTP server does not exist.");
2061     return;
2062   }
2063
2064   HANDLE hfm = OpenFileMapping(FILE_MAP_READ, FALSE, _T("Sakura"));
2065   if (!hfm)
2066   {
2067     Acquire a(&m_log, 0);
2068     m_log << _T(" Error(2): Direct SSTP server does not provide data.");
2069     return;
2070   }
2071   
2072   char *data =
2073     reinterpret_cast<char *>(MapViewOfFile(hfm, FILE_MAP_READ, 0, 0, 0));
2074   if (!data)
2075   {
2076     CloseHandle(hfm);
2077     Acquire a(&m_log, 0);
2078     m_log << _T(" Error(3): Direct SSTP server does not provide data.");
2079     return;
2080   }
2081   
2082   long length = *(long *)data;
2083   const char *begin = data + 4;
2084   const char *end = data + length;
2085   boost::regex getSakura("([0-9a-fA-F]{32})\\.([^\x01]+)\x01(.*?)\r\n");
2086   
2087   ParseDirectSSTPData::DirectSSTPServers servers;
2088   boost::regex_iterator<boost::regex::const_iterator>
2089     it(begin, end, getSakura), last;
2090   for (; it != last; ++it)
2091     ((ParseDirectSSTPData)(&servers))(*it);
2092
2093   // make request
2094   tstring request;
2095   if (!i_protocol.eval().size())
2096     request += _T("NOTIFY SSTP/1.1");
2097   else
2098     request += i_protocol.eval();
2099   request += _T("\r\n");
2100
2101   bool hasSender = false;
2102   for (std::list<tstringq>::const_iterator
2103          i = i_headers.begin(); i != i_headers.end(); ++ i)
2104   {
2105     if (_tcsnicmp(_T("Charset"), i->c_str(), 7) == 0 ||
2106         _tcsnicmp(_T("Hwnd"),    i->c_str(), 4) == 0)
2107       continue;
2108     if (_tcsnicmp(_T("Sender"), i->c_str(), 6) == 0)
2109       hasSender = true;
2110     request += i->c_str();
2111     request += _T("\r\n");
2112   }
2113
2114   if (!hasSender)
2115   {
2116     request += _T("Sender: ");
2117     request += loadString(IDS_mayu);
2118     request += _T("\r\n");
2119   }
2120   
2121   _TCHAR buf[100];
2122   _sntprintf(buf, NUMBER_OF(buf), _T("HWnd: %d\r\n"),
2123              reinterpret_cast<int>(m_hwndAssocWindow));
2124   request += buf;
2125
2126 #ifdef _UNICODE
2127   request += _T("Charset: UTF-8\r\n");
2128 #else
2129   request += _T("Charset: Shift_JIS\r\n");
2130 #endif
2131   request += _T("\r\n");
2132
2133 #ifdef _UNICODE
2134   std::string request_UTF_8 = to_UTF_8(request);
2135 #endif
2136
2137   // send request to Direct SSTP Server which matches i_name;
2138   for (ParseDirectSSTPData::DirectSSTPServers::iterator
2139          i = servers.begin(); i != servers.end(); ++ i)
2140   {
2141     tsmatch what;
2142     if (boost::regex_match(i->second.m_name, what, i_name))
2143     {
2144       COPYDATASTRUCT cd;
2145       cd.dwData = 9801;
2146 #ifdef _UNICODE
2147       cd.cbData = request_UTF_8.size();
2148       cd.lpData = (void *)request_UTF_8.c_str();
2149 #else
2150       cd.cbData = request.size();
2151       cd.lpData = (void *)request.c_str();
2152 #endif
2153 #ifdef MAYU64
2154       DWORD_PTR result;
2155 #else
2156       DWORD result;
2157 #endif
2158       SendMessageTimeout(i->second.m_hwnd, WM_COPYDATA,
2159                          reinterpret_cast<WPARAM>(m_hwndAssocWindow),
2160                          reinterpret_cast<LPARAM>(&cd),
2161                          SMTO_ABORTIFHUNG | SMTO_BLOCK, 5000, &result);
2162     }
2163   }
2164   
2165   UnmapViewOfFile(data);
2166   CloseHandle(hfm);
2167 }
2168
2169
2170 namespace shu
2171 {
2172   class PlugIn
2173   {
2174     enum Type
2175     {
2176       Type_A,
2177       Type_W
2178     };
2179     
2180   private:
2181     HMODULE m_dll;
2182     FARPROC m_func;
2183     Type m_type;
2184     tstringq m_funcParam;
2185     
2186   public:
2187     PlugIn() : m_dll(NULL)
2188     {
2189     }
2190     
2191     ~PlugIn()
2192     {
2193       FreeLibrary(m_dll);
2194     }
2195
2196     bool load(const tstringq &i_dllName, const tstringq &i_funcName,
2197               const tstringq &i_funcParam, tomsgstream &i_log)
2198     {
2199       m_dll = LoadLibrary((_T("Plugins\\") + i_dllName).c_str());
2200       if (!m_dll)
2201       {
2202         m_dll = LoadLibrary((_T("Plugin\\") + i_dllName).c_str());
2203         if (!m_dll)
2204         {
2205           m_dll = LoadLibrary(i_dllName.c_str());
2206           if (!m_dll)
2207           {
2208             Acquire a(&i_log);
2209             i_log << std::endl;
2210             i_log << _T("error: &PlugIn() failed to load ") << i_dllName << std::endl;
2211             return false;
2212           }
2213         }
2214       }
2215
2216       // get function
2217 #ifdef UNICODE
2218 #  define to_wstring
2219 #else
2220 #  define to_string
2221 #endif
2222       m_type = Type_W;
2223       m_func = GetProcAddress(m_dll, to_string(_T("mayu") + i_funcName + _T("W")).c_str());
2224       if (!m_func)
2225       {
2226         m_type = Type_A;
2227         m_func
2228           = GetProcAddress(m_dll, to_string(_T("mayu") + i_funcName + _T("A")).c_str());
2229         if (!m_func)
2230         {
2231           m_func = GetProcAddress(m_dll, to_string(_T("mayu") + i_funcName).c_str());
2232           if (!m_func)
2233           {
2234             m_func = GetProcAddress(m_dll, to_string(i_funcName).c_str());
2235             if (!m_func)
2236             {
2237               Acquire a(&i_log);
2238               i_log << std::endl;
2239               i_log << _T("error: &PlugIn() failed to find function: ")
2240                     << i_funcName << std::endl;
2241               return false;
2242             }
2243           }
2244         }
2245       }
2246       
2247       m_funcParam = i_funcParam;
2248       return true;
2249     }
2250
2251     void exec()
2252     {
2253       ASSERT( m_dll );
2254       ASSERT( m_func );
2255       
2256       typedef void (WINAPI * PLUGIN_FUNCTION_A)(const char *i_arg);
2257       typedef void (WINAPI * PLUGIN_FUNCTION_W)(const wchar_t *i_arg);
2258       switch (m_type)
2259       {
2260         case Type_A:
2261           reinterpret_cast<PLUGIN_FUNCTION_A>(m_func)(to_string(m_funcParam).c_str());
2262           break;
2263         case Type_W:
2264           reinterpret_cast<PLUGIN_FUNCTION_W>(m_func)(to_wstring(m_funcParam).c_str());
2265           break;
2266       }
2267     }
2268 #undef to_string
2269 #undef to_wstring
2270   };
2271
2272   static void plugInThread(void *i_plugin)
2273   {
2274     PlugIn *plugin = static_cast<PlugIn *>(i_plugin);
2275     plugin->exec();
2276     delete plugin;
2277   }
2278 }
2279
2280 void Engine::funcPlugIn(FunctionParam *i_param,
2281                         const StrExprArg &i_dllName,
2282                         const StrExprArg &i_funcName,
2283                         const StrExprArg &i_funcParam,
2284                         BooleanType i_doesCreateThread)
2285 {
2286   if (!i_param->m_isPressed)
2287     return;
2288
2289   shu::PlugIn *plugin = new shu::PlugIn();
2290   if (!plugin->load(i_dllName.eval(), i_funcName.eval(), i_funcParam.eval(), m_log))
2291   {
2292     delete plugin;
2293     return;
2294   }
2295   if (i_doesCreateThread)
2296   {
2297     if (_beginthread(shu::plugInThread, 0, plugin) == -1)
2298     {
2299       delete plugin;
2300       Acquire a(&m_log);
2301       m_log << std::endl;
2302       m_log << _T("error: &PlugIn() failed to create thread.");
2303     }
2304     return;
2305   }
2306   else
2307     plugin->exec();
2308 }
2309
2310
2311 void Engine::funcMouseHook(FunctionParam *i_param,
2312                            MouseHookType i_hookType, int i_hookParam)
2313 {
2314   GetCursorPos(&g_hookData->m_mousePos);
2315   g_hookData->m_mouseHookType = i_hookType;
2316   g_hookData->m_mouseHookParam = i_hookParam;
2317
2318   switch (i_hookType)
2319   {
2320     case MouseHookType_WindowMove:
2321     {
2322       // For this type, g_hookData->m_mouseHookParam means
2323       // target window type to move.
2324       HWND target;
2325       bool isMDI;
2326
2327       // i_hooParam < 0 means target window to move is MDI.
2328       if (i_hookParam < 0)
2329         isMDI = true;
2330       else
2331         isMDI = false;
2332
2333       // abs(i_hookParam) == 2: target is window under mouse cursor
2334       // otherwise: target is current focus window
2335       if (i_hookParam == 2 || i_hookParam == -2)
2336         target = WindowFromPoint(g_hookData->m_mousePos);
2337       else
2338         target = i_param->m_hwnd;
2339
2340       g_hookData->m_hwndMouseHookTarget =
2341         reinterpret_cast<DWORD>(getToplevelWindow(target, &isMDI));
2342       break;
2343     default:
2344       g_hookData->m_hwndMouseHookTarget = NULL;
2345       break;
2346     }
2347   }
2348   return;
2349 }
2350
2351
2352 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2353 // StrExpr
2354 class StrExpr
2355 {
2356 private:
2357   tstringq m_symbol;
2358 protected:
2359   static const Engine *s_engine;
2360 public:
2361   StrExpr(const tstringq &i_symbol) : m_symbol(i_symbol) {};
2362
2363   virtual ~StrExpr() {};
2364
2365   virtual StrExpr *clone() const
2366   {
2367     return new StrExpr(*this);
2368   }
2369
2370   virtual tstringq eval() const
2371   {
2372     return m_symbol;
2373   }
2374
2375   static void setEngine(const Engine *i_engine) { s_engine = i_engine; }
2376 };
2377
2378 const Engine *StrExpr::s_engine = NULL;
2379
2380 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2381 // StrExprClipboard
2382 class StrExprClipboard : public StrExpr
2383 {
2384 public:
2385   StrExprClipboard(const tstringq &i_symbol) : StrExpr(i_symbol) {};
2386
2387   ~StrExprClipboard() {};
2388
2389   StrExpr *clone() const
2390   {
2391     return new StrExprClipboard(*this);
2392   }
2393
2394   tstringq eval() const
2395   {
2396     HGLOBAL g;
2397     const _TCHAR *text = getTextFromClipboard(&g);
2398     const tstring value(text == NULL ? _T("") : text);
2399     closeClipboard(g);
2400     return value;
2401   }
2402 };
2403
2404
2405 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2406 // StrExprWindowClassName
2407 class StrExprWindowClassName : public StrExpr
2408 {
2409 public:
2410   StrExprWindowClassName(const tstringq &i_symbol) : StrExpr(i_symbol) {};
2411
2412   ~StrExprWindowClassName() {};
2413
2414   StrExpr *clone() const
2415   {
2416     return new StrExprWindowClassName(*this);
2417   }
2418
2419   tstringq eval() const
2420   {
2421     return s_engine->getCurrentWindowClassName();
2422   }
2423 };
2424
2425
2426 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2427 // StrExprWindowTitleName
2428 class StrExprWindowTitleName : public StrExpr
2429 {
2430 public:
2431   StrExprWindowTitleName(const tstringq &i_symbol) : StrExpr(i_symbol) {};
2432
2433   ~StrExprWindowTitleName() {};
2434
2435   StrExpr *clone() const
2436   {
2437     return new StrExprWindowTitleName(*this);
2438   }
2439
2440   tstringq eval() const
2441   {
2442     return s_engine->getCurrentWindowTitleName();
2443   }
2444 };
2445
2446
2447 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2448 // StrExprArg
2449
2450
2451 // default constructor
2452 StrExprArg::StrExprArg()
2453 {
2454   m_expr = new StrExpr(_T(""));
2455 }
2456
2457
2458 // copy contructor
2459 StrExprArg::StrExprArg(const StrExprArg &i_data)
2460 {
2461   m_expr = i_data.m_expr->clone();
2462 }
2463
2464
2465 StrExprArg &StrExprArg::operator=(const StrExprArg &i_data)
2466 {
2467   if (i_data.m_expr == m_expr)
2468     return *this;
2469
2470   delete m_expr;
2471   m_expr = i_data.m_expr->clone();
2472
2473   return *this;
2474 }
2475
2476
2477 // initializer
2478 StrExprArg::StrExprArg(const tstringq &i_symbol, Type i_type)
2479 {
2480   switch (i_type)
2481   {
2482     case Literal:
2483       m_expr = new StrExpr(i_symbol);
2484       break;
2485     case Builtin:
2486       if (i_symbol == _T("Clipboard"))
2487         m_expr = new StrExprClipboard(i_symbol);
2488       else if (i_symbol == _T("WindowClassName"))
2489         m_expr = new StrExprWindowClassName(i_symbol);
2490       else if (i_symbol == _T("WindowTitleName"))
2491         m_expr = new StrExprWindowTitleName(i_symbol);
2492       break;
2493     default:
2494       break;
2495   }
2496 }
2497
2498
2499 StrExprArg::~StrExprArg()
2500 {
2501   delete m_expr;
2502 }
2503
2504
2505 tstringq StrExprArg::eval() const
2506 {
2507   return m_expr->eval();
2508 }
2509
2510 void StrExprArg::setEngine(const Engine *i_engine)
2511 {
2512   StrExpr::setEngine(i_engine);
2513 }
2514
2515 // stream output
2516 tostream &operator<<(tostream &i_ost, const StrExprArg &i_data)
2517 {
2518   i_ost << i_data.eval();
2519   return i_ost;
2520 }