OSDN Git Service

24dd0feec82ecb490eee5e1caf7eb32edf962dcb
[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 #if defined(_WINNT)
871   generateKeyEvent(sync, false, false);
872 #elif defined(_WIN95)
873   generateKeyEvent(sync, true, false);
874 #else
875 #  error
876 #endif
877   
878   m_cs.release();
879   DWORD r = WaitForSingleObject(m_eSync, 5000);
880   if (r == WAIT_TIMEOUT)
881   {
882     Acquire a(&m_log, 0);
883     m_log << _T(" *FAILED*") << std::endl;
884   }
885   m_cs.acquire();
886   m_isSynchronizing = false;
887 }
888
889 // toggle lock
890 void Engine::funcToggle(FunctionParam *i_param, ModifierLockType i_lock,
891                         ToggleType i_toggle)
892 {
893   if (i_param->m_isPressed)                     // ignore PRESS
894     return;
895
896   Modifier::Type mt = static_cast<Modifier::Type>(i_lock);
897   switch (i_toggle)
898   {
899     case ToggleType_toggle:
900       m_currentLock.press(mt, !m_currentLock.isPressed(mt));
901       break;
902     case ToggleType_off:
903       m_currentLock.press(mt, false);
904       break;
905     case ToggleType_on:
906       m_currentLock.press(mt, true);
907       break;
908   }
909 }
910
911 // edit next user input key's modifier
912 void Engine::funcEditNextModifier(FunctionParam *i_param,
913                                   const Modifier &i_modifier)
914 {
915   if (!i_param->m_isPressed)
916     return;
917   
918   m_isPrefix = true;
919   m_doesEditNextModifier = true;
920   m_doesIgnoreModifierForPrefix = true;
921   m_modifierForNextKey = i_modifier;
922 }
923
924 // variable
925 void Engine::funcVariable(FunctionParam *i_param, int i_mag, int i_inc)
926 {
927   if (!i_param->m_isPressed)
928     return;
929   m_variable *= i_mag;
930   m_variable += i_inc;
931 }
932
933 // repeat N times
934 void Engine::funcRepeat(FunctionParam *i_param, const KeySeq *i_keySeq,
935                         int i_max)
936 {
937   if (i_param->m_isPressed)
938   {
939     int end = MIN(m_variable, i_max);
940     for (int i = 0; i < end - 1; ++ i)
941       generateKeySeqEvents(i_param->m_c, i_keySeq, Part_all);
942     if (0 < end)
943       generateKeySeqEvents(i_param->m_c, i_keySeq, Part_down);
944   }
945   else
946     generateKeySeqEvents(i_param->m_c, i_keySeq, Part_up);
947 }
948
949 // undefined (bell)
950 void Engine::funcUndefined(FunctionParam *i_param)
951 {
952   if (!i_param->m_isPressed)
953     return;
954   MessageBeep(MB_OK);
955 }
956
957 // ignore
958 void Engine::funcIgnore(FunctionParam *)
959 {
960   // do nothing
961 }
962
963 // post message
964 void Engine::funcPostMessage(FunctionParam *i_param, ToWindowType i_window,
965                              UINT i_message, WPARAM i_wParam, LPARAM i_lParam)
966 {
967   if (!i_param->m_isPressed)
968     return;
969
970   int window = static_cast<int>(i_window);
971   
972   HWND hwnd = i_param->m_hwnd;
973   if (0 < window)
974   {
975     for (int i = 0; i < window; ++ i)
976       hwnd = GetParent(hwnd);
977   }
978   else if (window == ToWindowType_toMainWindow)
979   {
980     while (true)
981     {
982       HWND p = GetParent(hwnd);
983       if (!p)
984         break;
985       hwnd = p;
986     }
987   }
988   else if (window == ToWindowType_toOverlappedWindow)
989   {
990     while (hwnd)
991     {
992 #ifdef MAYU64
993       LONG_PTR style = GetWindowLongPtr(hwnd, GWL_STYLE);
994 #else
995       LONG style = GetWindowLong(hwnd, GWL_STYLE);
996 #endif
997       if ((style & WS_CHILD) == 0)
998         break;
999       hwnd = GetParent(hwnd);
1000     }
1001   }
1002
1003   if (hwnd)
1004     PostMessage(hwnd, i_message, i_wParam, i_lParam);
1005 }
1006
1007
1008 // ShellExecute
1009 void Engine::funcShellExecute(FunctionParam *i_param,
1010                               const StrExprArg &/*i_operation*/,
1011                               const StrExprArg &/*i_file*/,
1012                               const StrExprArg &/*i_parameters*/,
1013                               const StrExprArg &/*i_directory*/,
1014                               ShowCommandType /*i_showCommand*/)
1015 {
1016   if (!i_param->m_isPressed)
1017     return;
1018   m_afShellExecute = i_param->m_af;
1019   PostMessage(m_hwndAssocWindow,
1020               WM_APP_engineNotify, EngineNotify_shellExecute, 0);
1021 }
1022
1023
1024 // shell execute
1025 void Engine::shellExecute()
1026 {
1027   Acquire a(&m_cs);
1028   
1029   FunctionData_ShellExecute *fd =
1030     reinterpret_cast<FunctionData_ShellExecute *>(
1031       m_afShellExecute->m_functionData);
1032   
1033   int r = (int)ShellExecute(
1034     NULL,
1035     fd->m_operation.eval().empty() ? _T("open") : fd->m_operation.eval().c_str(),
1036     fd->m_file.eval().empty() ? NULL : fd->m_file.eval().c_str(),
1037     fd->m_parameters.eval().empty() ? NULL : fd->m_parameters.eval().c_str(),
1038     fd->m_directory.eval().empty() ? NULL : fd->m_directory.eval().c_str(),
1039     fd->m_showCommand);
1040   if (32 < r)
1041     return; // success
1042
1043   typedef TypeTable<int> ErrorTable;
1044   static const ErrorTable errorTable[] =
1045   {
1046     { 0, _T("The operating system is out of memory or resources.") },
1047     { ERROR_FILE_NOT_FOUND, _T("The specified file was not found.") },
1048     { ERROR_PATH_NOT_FOUND, _T("The specified path was not found.") },
1049     { ERROR_BAD_FORMAT, _T("The .exe file is invalid ")
1050       _T("(non-Win32R .exe or error in .exe image).") },
1051     { SE_ERR_ACCESSDENIED,
1052       _T("The operating system denied access to the specified file.") },
1053     { SE_ERR_ASSOCINCOMPLETE,
1054       _T("The file name association is incomplete or invalid.") },
1055     { SE_ERR_DDEBUSY,
1056       _T("The DDE transaction could not be completed ")
1057       _T("because other DDE transactions were being processed. ") },
1058     { SE_ERR_DDEFAIL, _T("The DDE transaction failed.") },
1059     { SE_ERR_DDETIMEOUT, _T("The DDE transaction could not be completed ")
1060       _T("because the request timed out.") },
1061     { SE_ERR_DLLNOTFOUND,
1062       _T("The specified dynamic-link library was not found.") },
1063     { SE_ERR_FNF, _T("The specified file was not found.") },
1064     { SE_ERR_NOASSOC, _T("There is no application associated ")
1065       _T("with the given file name extension.") },
1066     { SE_ERR_OOM,
1067       _T("There was not enough memory to complete the operation.") },
1068     { SE_ERR_PNF, _T("The specified path was not found.") },
1069     { SE_ERR_SHARE, _T("A sharing violation occurred.") },
1070   };
1071
1072   tstring errorMessage(_T("Unknown error."));
1073   getTypeName(&errorMessage, r, errorTable, NUMBER_OF(errorTable));
1074   
1075   Acquire b(&m_log, 0);
1076   m_log << _T("error: ") << fd << _T(": ") << errorMessage << std::endl;
1077 }
1078
1079
1080 struct EnumWindowsForSetForegroundWindowParam
1081 {
1082   const FunctionData_SetForegroundWindow *m_fd;
1083   HWND m_hwnd;
1084
1085 public:
1086   EnumWindowsForSetForegroundWindowParam(
1087     const FunctionData_SetForegroundWindow *i_fd)
1088     : m_fd(i_fd),
1089       m_hwnd(NULL)
1090   {
1091   }
1092 };
1093
1094
1095 /// enum windows for SetForegroundWindow
1096 static BOOL CALLBACK enumWindowsForSetForegroundWindow(
1097   HWND i_hwnd, LPARAM i_lParam)
1098 {
1099   EnumWindowsForSetForegroundWindowParam &ep =
1100     *reinterpret_cast<EnumWindowsForSetForegroundWindowParam *>(i_lParam);
1101
1102   _TCHAR name[GANA_MAX_ATOM_LENGTH];
1103   if (!GetClassName(i_hwnd, name, NUMBER_OF(name)))
1104     return TRUE;
1105   tsmatch what;
1106   if (!boost::regex_search(tstring(name), what, ep.m_fd->m_windowClassName))
1107     if (ep.m_fd->m_logicalOp == LogicalOperatorType_and)
1108       return TRUE;                              // match failed
1109
1110   if (ep.m_fd->m_logicalOp == LogicalOperatorType_and)
1111   {
1112     if (GetWindowText(i_hwnd, name, NUMBER_OF(name)) == 0)
1113       name[0] = _T('\0');
1114     if (!boost::regex_search(tstring(name), what,
1115                              ep.m_fd->m_windowTitleName))
1116       return TRUE;                              // match failed
1117   }
1118
1119   ep.m_hwnd = i_hwnd;
1120   return FALSE;
1121 }
1122
1123
1124 /// SetForegroundWindow
1125 void Engine::funcSetForegroundWindow(FunctionParam *i_param, const tregex &,
1126                                      LogicalOperatorType , const tregex &)
1127 {
1128   if (!i_param->m_isPressed)
1129     return;
1130   EnumWindowsForSetForegroundWindowParam
1131     ep(static_cast<const FunctionData_SetForegroundWindow *>(
1132       i_param->m_af->m_functionData));
1133   EnumWindows(enumWindowsForSetForegroundWindow,
1134               reinterpret_cast<LPARAM>(&ep));
1135   if (ep.m_hwnd)
1136     PostMessage(m_hwndAssocWindow,
1137                 WM_APP_engineNotify, EngineNotify_setForegroundWindow,
1138                 reinterpret_cast<LPARAM>(ep.m_hwnd));
1139
1140 }
1141
1142
1143 // load setting
1144 void Engine::funcLoadSetting(FunctionParam *i_param, const StrExprArg &i_name)
1145 {
1146   if (!i_param->m_isPressed)
1147     return;
1148   if (!i_name.eval().empty())
1149   {
1150     // set MAYU_REGISTRY_ROOT\.mayuIndex which name is same with i_name
1151     Registry reg(MAYU_REGISTRY_ROOT);
1152
1153     tregex split(_T("^([^;]*);([^;]*);(.*)$"));
1154     tstringi dot_mayu;
1155     for (size_t i = 0; i < MAX_MAYU_REGISTRY_ENTRIES; ++ i)
1156     {
1157       _TCHAR buf[100];
1158       _sntprintf(buf, NUMBER_OF(buf), _T(".mayu%d"), i);
1159       if (!reg.read(buf, &dot_mayu))
1160         break;
1161       
1162       tsmatch what;
1163       if (boost::regex_match(dot_mayu, what, split) &&
1164           what.str(1) == i_name.eval())
1165       { 
1166         reg.write(_T(".mayuIndex"), i);
1167         goto success;
1168       }
1169     }
1170
1171     {
1172       Acquire a(&m_log, 0);
1173       m_log << _T("unknown setting name: ") << i_name;
1174     }
1175     return;
1176     
1177     success: ;
1178   }
1179   PostMessage(m_hwndAssocWindow,
1180               WM_APP_engineNotify, EngineNotify_loadSetting, 0);
1181 }
1182
1183 // virtual key
1184 void Engine::funcVK(FunctionParam *i_param, VKey i_vkey)
1185 {
1186   long key = static_cast<long>(i_vkey);
1187   BYTE vkey = static_cast<BYTE>(i_vkey);
1188   bool isExtended = !!(key & VKey_extended);
1189   bool isUp       = !i_param->m_isPressed && !!(key & VKey_released);
1190   bool isDown     = i_param->m_isPressed && !!(key & VKey_pressed);
1191   
1192   if (vkey == VK_LBUTTON && isDown)
1193     mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
1194   else if (vkey == VK_LBUTTON && isUp)
1195     mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
1196   else if (vkey == VK_MBUTTON && isDown)
1197     mouse_event(MOUSEEVENTF_MIDDLEDOWN, 0, 0, 0, 0);
1198   else if (vkey == VK_MBUTTON && isUp)
1199     mouse_event(MOUSEEVENTF_MIDDLEUP, 0, 0, 0, 0);
1200   else if (vkey == VK_RBUTTON && isDown)
1201     mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
1202   else if (vkey == VK_RBUTTON && isUp)
1203     mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
1204 #if(_WIN32_WINNT >= 0x0500)
1205   else if (vkey == VK_XBUTTON1 && isDown)
1206     mouse_event(MOUSEEVENTF_XDOWN, 0, 0, XBUTTON1, 0);
1207   else if (vkey == VK_XBUTTON1 && isUp)
1208     mouse_event(MOUSEEVENTF_XUP, 0, 0, XBUTTON1, 0);
1209   else if (vkey == VK_XBUTTON2 && isDown)
1210     mouse_event(MOUSEEVENTF_XDOWN, 0, 0, XBUTTON2, 0);
1211   else if (vkey == VK_XBUTTON2 && isUp)
1212     mouse_event(MOUSEEVENTF_XUP, 0, 0, XBUTTON2, 0);
1213 #endif /* _WIN32_WINNT >= 0x0500 */
1214   else if (isUp || isDown)
1215     keybd_event(vkey,
1216                 static_cast<BYTE>(MapVirtualKey(vkey, 0)),
1217                 (isExtended ? KEYEVENTF_EXTENDEDKEY : 0) |
1218                 (i_param->m_isPressed ? 0 : KEYEVENTF_KEYUP), 0);
1219 }
1220
1221 // wait
1222 void Engine::funcWait(FunctionParam *i_param, int i_milliSecond)
1223 {
1224   if (!i_param->m_isPressed)
1225     return;
1226   if (i_milliSecond < 0 || 5000 < i_milliSecond)        // too long wait
1227     return;
1228   
1229   m_isSynchronizing = true;
1230   m_cs.release();
1231   Sleep(i_milliSecond);
1232   m_cs.acquire();
1233   m_isSynchronizing = false;
1234 }
1235
1236 // investigate WM_COMMAND, WM_SYSCOMMAND
1237 void Engine::funcInvestigateCommand(FunctionParam *i_param)
1238 {
1239   if (!i_param->m_isPressed)
1240     return;
1241   Acquire a(&m_log, 0);
1242   g_hookData->m_doesNotifyCommand = !g_hookData->m_doesNotifyCommand;
1243   if (g_hookData->m_doesNotifyCommand)
1244     m_log << _T(" begin") << std::endl;
1245   else
1246     m_log << _T(" end") << std::endl;
1247 }
1248
1249 // show mayu dialog box
1250 void Engine::funcMayuDialog(FunctionParam *i_param, MayuDialogType i_dialog,
1251                             ShowCommandType i_showCommand)
1252 {
1253   if (!i_param->m_isPressed)
1254     return;
1255   PostMessage(getAssociatedWndow(), WM_APP_engineNotify, EngineNotify_showDlg,
1256               static_cast<LPARAM>(i_dialog) |
1257               static_cast<LPARAM>(i_showCommand));
1258 }
1259
1260 // describe bindings
1261 void Engine::funcDescribeBindings(FunctionParam *i_param)
1262 {
1263   if (!i_param->m_isPressed)
1264     return;
1265   {
1266     Acquire a(&m_log, 1);
1267     m_log << std::endl;
1268   }
1269   describeBindings();
1270 }
1271
1272 // show help message
1273 void Engine::funcHelpMessage(FunctionParam *i_param, const StrExprArg &i_title,
1274                              const StrExprArg &i_message)
1275 {
1276   if (!i_param->m_isPressed)
1277     return;
1278
1279   m_helpTitle = i_title.eval();
1280   m_helpMessage = i_message.eval();
1281   bool doesShow = !(i_title.eval().size() == 0 && i_message.eval().size() == 0);
1282   PostMessage(getAssociatedWndow(), WM_APP_engineNotify,
1283               EngineNotify_helpMessage, doesShow);
1284 }
1285
1286 // show variable
1287 void Engine::funcHelpVariable(FunctionParam *i_param, const StrExprArg &i_title)
1288 {
1289   if (!i_param->m_isPressed)
1290     return;
1291
1292   _TCHAR buf[20];
1293   _sntprintf(buf, NUMBER_OF(buf), _T("%d"), m_variable);
1294
1295   m_helpTitle = i_title.eval();
1296   m_helpMessage = buf;
1297   PostMessage(getAssociatedWndow(), WM_APP_engineNotify,
1298               EngineNotify_helpMessage, true);
1299 }
1300
1301 // raise window
1302 void Engine::funcWindowRaise(FunctionParam *i_param,
1303                              TargetWindowType i_twt)
1304 {
1305   HWND hwnd;
1306   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1307     return;
1308   SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
1309                SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);
1310 }
1311
1312 // lower window
1313 void Engine::funcWindowLower(FunctionParam *i_param, TargetWindowType i_twt)
1314 {
1315   HWND hwnd;
1316   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1317     return;
1318   SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0,
1319                SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);
1320 }
1321
1322 // minimize window
1323 void Engine::funcWindowMinimize(FunctionParam *i_param, TargetWindowType i_twt)
1324 {
1325   HWND hwnd;
1326   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1327     return;
1328   PostMessage(hwnd, WM_SYSCOMMAND,
1329               IsIconic(hwnd) ? SC_RESTORE : SC_MINIMIZE, 0);
1330 }
1331
1332 // maximize window
1333 void Engine::funcWindowMaximize(FunctionParam *i_param, TargetWindowType i_twt)
1334 {
1335   HWND hwnd;
1336   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1337     return;
1338   PostMessage(hwnd, WM_SYSCOMMAND,
1339               IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, 0);
1340 }
1341
1342 // maximize horizontally or virtically
1343 void Engine::funcWindowHVMaximize(FunctionParam *i_param,
1344                                   BooleanType i_isHorizontal,
1345                                   TargetWindowType i_twt)
1346 {
1347   HWND hwnd;
1348   RECT rc, rcd;
1349   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt, &rc, &rcd))
1350     return;
1351
1352   // erase non window
1353   while (true)
1354   {
1355     WindowPositions::iterator i = m_windowPositions.begin();
1356     WindowPositions::iterator end = m_windowPositions.end();
1357     for (; i != end; ++ i)
1358       if (!IsWindow((*i).m_hwnd))
1359         break;
1360     if (i == end)
1361       break;
1362     m_windowPositions.erase(i);
1363   }
1364
1365   // find target
1366   WindowPositions::iterator i = m_windowPositions.begin();
1367   WindowPositions::iterator end = m_windowPositions.end();
1368   WindowPositions::iterator target = end;
1369   for (; i != end; ++ i)
1370     if ((*i).m_hwnd == hwnd)
1371     {
1372       target = i;
1373       break;
1374     }
1375   
1376   if (IsZoomed(hwnd))
1377     PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1378   else
1379   {
1380     WindowPosition::Mode mode = WindowPosition::Mode_normal;
1381     
1382     if (target != end)
1383     {
1384       WindowPosition &wp = *target;
1385       rc = wp.m_rc;
1386       if (wp.m_mode == WindowPosition::Mode_HV)
1387         mode = wp.m_mode =
1388           i_isHorizontal ? WindowPosition::Mode_V : WindowPosition::Mode_H;
1389       else if (( i_isHorizontal && wp.m_mode == WindowPosition::Mode_V) ||
1390                (!i_isHorizontal && wp.m_mode == WindowPosition::Mode_H))
1391         mode = wp.m_mode = WindowPosition::Mode_HV;
1392       else
1393         m_windowPositions.erase(target);
1394     }
1395     else
1396     {
1397       mode = i_isHorizontal ? WindowPosition::Mode_H : WindowPosition::Mode_V;
1398       m_windowPositions.push_front(WindowPosition(hwnd, rc, mode));
1399     }
1400     
1401     if (static_cast<int>(mode) & static_cast<int>(WindowPosition::Mode_H))
1402       rc.left = rcd.left, rc.right = rcd.right;
1403     if (static_cast<int>(mode) & static_cast<int>(WindowPosition::Mode_V))
1404       rc.top = rcd.top, rc.bottom = rcd.bottom;
1405     
1406     asyncMoveWindow(hwnd, rc.left, rc.top, rcWidth(&rc), rcHeight(&rc));
1407   }
1408 }
1409
1410 // maximize window horizontally
1411 void Engine::funcWindowHMaximize(FunctionParam *i_param,
1412                                  TargetWindowType i_twt)
1413 {
1414   funcWindowHVMaximize(i_param, BooleanType_true, i_twt);
1415 }
1416
1417 // maximize window virtically
1418 void Engine::funcWindowVMaximize(FunctionParam *i_param,
1419                                  TargetWindowType i_twt)
1420 {
1421   funcWindowHVMaximize(i_param, BooleanType_false, i_twt);
1422 }
1423
1424 // move window
1425 void Engine::funcWindowMove(FunctionParam *i_param, int i_dx, int i_dy,
1426                             TargetWindowType i_twt)
1427 {
1428   funcWindowMoveTo(i_param, GravityType_C, i_dx, i_dy, i_twt);
1429 }
1430
1431 // move window to ...
1432 void Engine::funcWindowMoveTo(FunctionParam *i_param,
1433                               GravityType i_gravityType,
1434                               int i_dx, int i_dy, TargetWindowType i_twt)
1435 {
1436   HWND hwnd;
1437   RECT rc, rcd;
1438   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt, &rc, &rcd))
1439     return;
1440   
1441   int x = rc.left + i_dx;
1442   int y = rc.top + i_dy;
1443
1444   if (i_gravityType & GravityType_N)
1445     y = i_dy + rcd.top;
1446   if (i_gravityType & GravityType_E)
1447     x = i_dx + rcd.right - rcWidth(&rc);
1448   if (i_gravityType & GravityType_W)
1449     x = i_dx + rcd.left;
1450   if (i_gravityType & GravityType_S)
1451     y = i_dy + rcd.bottom - rcHeight(&rc);
1452   asyncMoveWindow(hwnd, x, y);
1453 }
1454
1455
1456 // move window visibly
1457 void Engine::funcWindowMoveVisibly(FunctionParam *i_param,
1458                                    TargetWindowType i_twt)
1459 {
1460   HWND hwnd;
1461   RECT rc, rcd;
1462   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt, &rc, &rcd))
1463     return;
1464
1465   int x = rc.left;
1466   int y = rc.top;
1467   if (rc.left < rcd.left)
1468     x = rcd.left;
1469   else if (rcd.right < rc.right)
1470     x = rcd.right - rcWidth(&rc);
1471   if (rc.top < rcd.top)
1472     y = rcd.top;
1473   else if (rcd.bottom < rc.bottom)
1474     y = rcd.bottom - rcHeight(&rc);
1475   asyncMoveWindow(hwnd, x, y);
1476 }
1477
1478
1479 struct EnumDisplayMonitorsForWindowMonitorToParam
1480 {
1481   std::vector<HMONITOR> m_monitors;
1482   std::vector<MONITORINFO> m_monitorinfos;
1483   int m_primaryMonitorIdx;
1484   int m_currentMonitorIdx;
1485
1486   HMONITOR m_hmon;
1487
1488 public:
1489   EnumDisplayMonitorsForWindowMonitorToParam(HMONITOR i_hmon)
1490     : m_hmon(i_hmon),
1491       m_primaryMonitorIdx(-1), m_currentMonitorIdx(-1)
1492   {
1493   }
1494 };
1495
1496 static BOOL CALLBACK enumDisplayMonitorsForWindowMonitorTo(
1497   HMONITOR i_hmon, HDC i_hdc, LPRECT i_rcMonitor, LPARAM i_data)
1498 {
1499   EnumDisplayMonitorsForWindowMonitorToParam &ep =
1500     *reinterpret_cast<EnumDisplayMonitorsForWindowMonitorToParam *>(i_data);
1501
1502   ep.m_monitors.push_back(i_hmon);
1503
1504   MONITORINFO mi;
1505   mi.cbSize = sizeof(mi);
1506   getMonitorInfo(i_hmon, &mi);
1507   ep.m_monitorinfos.push_back(mi);
1508
1509   if(mi.dwFlags & MONITORINFOF_PRIMARY)
1510     ep.m_primaryMonitorIdx = ep.m_monitors.size() - 1;
1511   if(i_hmon == ep.m_hmon)
1512     ep.m_currentMonitorIdx = ep.m_monitors.size() - 1;
1513
1514   return TRUE;
1515 }
1516
1517 /// move window to other monitor
1518 void Engine::funcWindowMonitorTo(
1519     FunctionParam *i_param, WindowMonitorFromType i_fromType, int i_monitor,
1520     BooleanType i_adjustPos, BooleanType i_adjustSize)
1521 {
1522   HWND hwnd;
1523   if(! getSuitableWindow(i_param, &hwnd))
1524     return;
1525
1526   HMONITOR hmonCur;
1527   hmonCur = monitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
1528
1529   EnumDisplayMonitorsForWindowMonitorToParam ep(hmonCur);
1530   enumDisplayMonitors(NULL, NULL, enumDisplayMonitorsForWindowMonitorTo,
1531                       reinterpret_cast<LPARAM>(&ep));
1532   if(ep.m_monitors.size() < 1 ||
1533      ep.m_primaryMonitorIdx < 0 || ep.m_currentMonitorIdx < 0)
1534     return;
1535
1536   int targetIdx;
1537   switch(i_fromType) {
1538   case WindowMonitorFromType_primary:
1539     targetIdx = (ep.m_primaryMonitorIdx + i_monitor) % ep.m_monitors.size();
1540     break;
1541
1542   case WindowMonitorFromType_current:
1543     targetIdx = (ep.m_currentMonitorIdx + i_monitor) % ep.m_monitors.size();
1544     break;
1545   }
1546   if(ep.m_currentMonitorIdx == targetIdx)
1547     return;
1548
1549   RECT rcCur, rcTarget, rcWin;
1550   rcCur = ep.m_monitorinfos[ep.m_currentMonitorIdx].rcWork;
1551   rcTarget = ep.m_monitorinfos[targetIdx].rcWork;
1552   GetWindowRect(hwnd, &rcWin);
1553
1554   int x = rcTarget.left + (rcWin.left - rcCur.left);
1555   int y = rcTarget.top + (rcWin.top - rcCur.top);
1556   int w = rcWidth(&rcWin);
1557   int h = rcHeight(&rcWin);
1558
1559   if(i_adjustPos) {
1560     if(x + w > rcTarget.right)
1561       x = rcTarget.right - w;
1562     if(x < rcTarget.left)
1563       x = rcTarget.left;
1564     if(w > rcWidth(&rcTarget)) {
1565       x = rcTarget.left;
1566       w = rcWidth(&rcTarget);
1567     }
1568
1569     if(y + h > rcTarget.bottom)
1570       y = rcTarget.bottom - h;
1571     if(y < rcTarget.top)
1572       y = rcTarget.top;
1573     if(h > rcHeight(&rcTarget)) {
1574       y = rcTarget.top;
1575       h = rcHeight(&rcTarget);
1576     }
1577   }
1578
1579   if(i_adjustPos && i_adjustSize) {
1580     if(IsZoomed(hwnd))
1581       PostMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
1582     asyncMoveWindow(hwnd, x, y, w, h);
1583   } else {
1584     asyncMoveWindow(hwnd, x, y);
1585   }
1586 }
1587
1588 /// move window to other monitor
1589 void Engine::funcWindowMonitor(
1590     FunctionParam *i_param, int i_monitor,
1591     BooleanType i_adjustPos, BooleanType i_adjustSize)
1592 {
1593   funcWindowMonitorTo(i_param, WindowMonitorFromType_primary, i_monitor,
1594                       i_adjustPos, i_adjustSize);
1595 }
1596
1597
1598 //
1599 void Engine::funcWindowClingToLeft(FunctionParam *i_param,
1600                                    TargetWindowType i_twt)
1601 {
1602   funcWindowMoveTo(i_param, GravityType_W, 0, 0, i_twt);
1603 }
1604
1605 //
1606 void Engine::funcWindowClingToRight(FunctionParam *i_param,
1607                                     TargetWindowType i_twt)
1608 {
1609   funcWindowMoveTo(i_param, GravityType_E, 0, 0, i_twt);
1610 }
1611
1612 //
1613 void Engine::funcWindowClingToTop(FunctionParam *i_param,
1614                                   TargetWindowType i_twt)
1615 {
1616   funcWindowMoveTo(i_param, GravityType_N, 0, 0, i_twt);
1617 }
1618
1619 //
1620 void Engine::funcWindowClingToBottom(FunctionParam *i_param,
1621                                      TargetWindowType i_twt)
1622 {
1623   funcWindowMoveTo(i_param, GravityType_S, 0, 0, i_twt);
1624 }
1625
1626 // close window
1627 void Engine::funcWindowClose(FunctionParam *i_param, TargetWindowType i_twt)
1628 {
1629   HWND hwnd;
1630   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt))
1631     return;
1632   PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
1633 }
1634
1635 // toggle top-most flag of the window
1636 void Engine::funcWindowToggleTopMost(FunctionParam *i_param)
1637 {
1638   HWND hwnd;
1639   if (!getSuitableWindow(i_param, &hwnd))
1640     return;
1641   SetWindowPos(
1642     hwnd,
1643 #ifdef MAYU64
1644     (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) ?
1645 #else
1646     (GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) ?
1647 #endif
1648     HWND_NOTOPMOST : HWND_TOPMOST,
1649     0, 0, 0, 0,
1650     SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);
1651 }
1652
1653 // identify the window
1654 void Engine::funcWindowIdentify(FunctionParam *i_param)
1655 {
1656   if (!i_param->m_isPressed)
1657     return;
1658
1659   _TCHAR className[GANA_MAX_ATOM_LENGTH];
1660   bool ok = false;
1661   if (GetClassName(i_param->m_hwnd, className, NUMBER_OF(className)))
1662   {
1663     if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0)
1664     {
1665       _TCHAR titleName[1024];
1666       if (GetWindowText(i_param->m_hwnd, titleName, NUMBER_OF(titleName)) == 0)
1667         titleName[0] = _T('\0');
1668       {
1669         Acquire a(&m_log, 1);
1670         m_log << _T("HWND:\t") << std::hex
1671               << reinterpret_cast<int>(i_param->m_hwnd)
1672               << std::dec << std::endl;
1673       }
1674       Acquire a(&m_log, 0);
1675       m_log << _T("CLASS:\t") << className << std::endl;
1676       m_log << _T("TITLE:\t") << titleName << std::endl;
1677
1678       HWND hwnd = getToplevelWindow(i_param->m_hwnd, NULL);
1679       RECT rc;
1680       GetWindowRect(hwnd, &rc);
1681       m_log << _T("Toplevel Window Position/Size: (")
1682             << rc.left << _T(", ") << rc.top << _T(") / (")
1683             << rcWidth(&rc) << _T("x") << rcHeight(&rc)
1684             << _T(")") << std::endl;
1685       
1686       SystemParametersInfo(SPI_GETWORKAREA, 0, (void *)&rc, FALSE);
1687       m_log << _T("Desktop Window Position/Size: (")
1688             << rc.left << _T(", ") << rc.top << _T(") / (")
1689             << rcWidth(&rc) << _T("x") << rcHeight(&rc)
1690             << _T(")") << std::endl;
1691
1692       m_log << std::endl;
1693       ok = true;
1694     }
1695   }
1696   if (!ok)
1697   {
1698     UINT WM_MAYU_MESSAGE = RegisterWindowMessage(
1699                 addSessionId(WM_MAYU_MESSAGE_NAME).c_str());
1700     CHECK_TRUE( PostMessage(i_param->m_hwnd, WM_MAYU_MESSAGE,
1701                             MayuMessage_notifyName, 0) );
1702   }
1703 }
1704
1705 // set alpha blending parameter to the window
1706 void Engine::funcWindowSetAlpha(FunctionParam *i_param, int i_alpha)
1707 {
1708 #if defined(_WINNT)
1709   HWND hwnd;
1710   if (!getSuitableWindow(i_param, &hwnd))
1711     return;
1712   
1713   if (i_alpha < 0)      // remove all alpha
1714   {
1715     for (WindowsWithAlpha::iterator i = m_windowsWithAlpha.begin(); 
1716          i != m_windowsWithAlpha.end(); ++ i)
1717     {
1718 #ifdef MAYU64
1719       SetWindowLongPtr(*i, GWL_EXSTYLE,
1720                     GetWindowLongPtr(*i, GWL_EXSTYLE) & ~WS_EX_LAYERED);
1721 #else
1722       SetWindowLong(*i, GWL_EXSTYLE,
1723                     GetWindowLong(*i, GWL_EXSTYLE) & ~WS_EX_LAYERED);
1724 #endif
1725       RedrawWindow(*i, NULL, NULL,
1726                    RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
1727     }
1728     m_windowsWithAlpha.clear();
1729   }
1730   else
1731   {
1732 #ifdef MAYU64
1733     LONG_PTR exStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
1734 #else
1735     LONG exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
1736 #endif
1737     if (exStyle & WS_EX_LAYERED)        // remove alpha
1738     {
1739       WindowsWithAlpha::iterator
1740         i = std::find(m_windowsWithAlpha.begin(), m_windowsWithAlpha.end(),
1741                       hwnd);
1742       if (i == m_windowsWithAlpha.end())
1743         return; // already layered by the application
1744     
1745       m_windowsWithAlpha.erase(i);
1746     
1747 #ifdef MAYU64
1748       SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
1749 #else    
1750       SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
1751 #endif
1752     }
1753     else        // add alpha
1754     {
1755 #ifdef MAYU64
1756       SetWindowLongPtr(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
1757 #else
1758       SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
1759 #endif
1760       i_alpha %= 101;
1761       if (!setLayeredWindowAttributes(hwnd, 0,
1762                                       (BYTE)(255 * i_alpha / 100), LWA_ALPHA))
1763       {
1764         Acquire a(&m_log, 0);
1765         m_log << _T("error: &WindowSetAlpha(") << i_alpha
1766               << _T(") failed for HWND: ") << std::hex
1767               << hwnd << std::dec << std::endl;
1768         return;
1769       }
1770       m_windowsWithAlpha.push_front(hwnd);
1771     }
1772     RedrawWindow(hwnd, NULL, NULL,
1773                  RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
1774   }
1775 #endif // _WINNT
1776 }
1777
1778
1779 // redraw the window
1780 void Engine::funcWindowRedraw(FunctionParam *i_param)
1781 {
1782   HWND hwnd;
1783   if (!getSuitableWindow(i_param, &hwnd))
1784     return;
1785   RedrawWindow(hwnd, NULL, NULL,
1786                RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
1787 }
1788
1789 // resize window to
1790 void Engine::funcWindowResizeTo(FunctionParam *i_param, int i_width,
1791                                 int i_height, TargetWindowType i_twt)
1792 {
1793   HWND hwnd;
1794   RECT rc, rcd;
1795   if (!getSuitableMdiWindow(i_param, &hwnd, &i_twt, &rc, &rcd))
1796     return;
1797   
1798   if (i_width == 0)
1799     i_width = rcWidth(&rc);
1800   else if (i_width < 0)
1801     i_width += rcWidth(&rcd);
1802   
1803   if (i_height == 0)
1804     i_height = rcHeight(&rc);
1805   else if (i_height < 0)
1806     i_height += rcHeight(&rcd);
1807   
1808   asyncResize(hwnd, i_width, i_height);
1809 }
1810
1811 // move the mouse cursor
1812 void Engine::funcMouseMove(FunctionParam *i_param, int i_dx, int i_dy)
1813 {
1814   if (!i_param->m_isPressed)
1815     return;
1816   POINT pt;
1817   GetCursorPos(&pt);
1818   SetCursorPos(pt.x + i_dx, pt.y + i_dy);
1819 }
1820
1821 // send a mouse-wheel-message to Windows
1822 void Engine::funcMouseWheel(FunctionParam *i_param, int i_delta)
1823 {
1824   if (!i_param->m_isPressed)
1825     return;
1826   mouse_event(MOUSEEVENTF_WHEEL, 0, 0, i_delta, 0);
1827 }
1828
1829 // convert the contents of the Clipboard to upper case
1830 void Engine::funcClipboardChangeCase(FunctionParam *i_param,
1831                                      BooleanType i_doesConvertToUpperCase)
1832 {
1833   if (!i_param->m_isPressed)
1834     return;
1835   
1836   HGLOBAL hdata;
1837   const _TCHAR *text = getTextFromClipboard(&hdata);
1838   HGLOBAL hdataNew = NULL;
1839   if (text)
1840   {
1841     int size = static_cast<int>(GlobalSize(hdata));
1842     hdataNew = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size);
1843     if (hdataNew)
1844     {
1845       if (_TCHAR *dataNew = reinterpret_cast<_TCHAR *>(GlobalLock(hdataNew)))
1846       {
1847         std::memcpy(dataNew, text, size);
1848         _TCHAR *dataEnd = dataNew + size;
1849         while (dataNew < dataEnd && *dataNew)
1850         {
1851           _TCHAR c = *dataNew;
1852           if (_istlead(c))
1853             dataNew += 2;
1854           else
1855             *dataNew++ =
1856               i_doesConvertToUpperCase ? _totupper(c) : _totlower(c);
1857         }
1858         GlobalUnlock(hdataNew);
1859       }
1860     }
1861   }
1862   closeClipboard(hdata, hdataNew);
1863 }
1864
1865 // convert the contents of the Clipboard to upper case
1866 void Engine::funcClipboardUpcaseWord(FunctionParam *i_param)
1867 {
1868   funcClipboardChangeCase(i_param, BooleanType_true);
1869 }
1870
1871 // convert the contents of the Clipboard to lower case
1872 void Engine::funcClipboardDowncaseWord(FunctionParam *i_param)
1873 {
1874   funcClipboardChangeCase(i_param, BooleanType_false);
1875 }
1876
1877 // set the contents of the Clipboard to the string
1878 void Engine::funcClipboardCopy(FunctionParam *i_param, const StrExprArg &i_text)
1879 {
1880   if (!i_param->m_isPressed)
1881     return;
1882   if (!OpenClipboard(NULL))
1883     return;
1884   
1885   HGLOBAL hdataNew =
1886     GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
1887                 (i_text.eval().size() + 1) * sizeof(_TCHAR));
1888   if (!hdataNew)
1889     return;
1890   _TCHAR *dataNew = reinterpret_cast<_TCHAR *>(GlobalLock(hdataNew));
1891   _tcscpy(dataNew, i_text.eval().c_str());
1892   GlobalUnlock(hdataNew);
1893   closeClipboard(NULL, hdataNew);
1894 }
1895
1896 //
1897 void Engine::funcEmacsEditKillLinePred(
1898   FunctionParam *i_param, const KeySeq *i_keySeq1, const KeySeq *i_keySeq2)
1899 {
1900   m_emacsEditKillLine.m_doForceReset = false;
1901   if (!i_param->m_isPressed)
1902     return;
1903   
1904   int r = m_emacsEditKillLine.pred();
1905   const KeySeq *keySeq;
1906   if (r == 1)
1907     keySeq = i_keySeq1;
1908   else if (r == 2)
1909     keySeq = i_keySeq2;
1910   else // r == 0
1911     return;
1912   ASSERT(keySeq);
1913   generateKeySeqEvents(i_param->m_c, keySeq, Part_all);
1914 }
1915
1916 //
1917 void Engine::funcEmacsEditKillLineFunc(FunctionParam *i_param)
1918 {
1919   if (!i_param->m_isPressed)
1920     return;
1921   m_emacsEditKillLine.func();
1922   m_emacsEditKillLine.m_doForceReset = false;
1923 }
1924
1925 // clear log
1926 void Engine::funcLogClear(FunctionParam *i_param)
1927 {
1928   if (!i_param->m_isPressed)
1929     return;
1930   PostMessage(getAssociatedWndow(), WM_APP_engineNotify,
1931               EngineNotify_clearLog, 0);
1932 }
1933
1934 // recenter
1935 void Engine::funcRecenter(FunctionParam *i_param)
1936 {
1937   if (!i_param->m_isPressed)
1938     return;
1939   if (m_hwndFocus)
1940   {
1941     UINT WM_MAYU_MESSAGE = RegisterWindowMessage(
1942                 addSessionId(WM_MAYU_MESSAGE_NAME).c_str());
1943     PostMessage(m_hwndFocus, WM_MAYU_MESSAGE, MayuMessage_funcRecenter, 0);
1944   }
1945 }
1946
1947 // set IME open status
1948 void Engine::funcSetImeStatus(FunctionParam *i_param, ToggleType i_toggle)
1949 {
1950   if (!i_param->m_isPressed)
1951     return;
1952   if (m_hwndFocus)
1953   {
1954     UINT WM_MAYU_MESSAGE = RegisterWindowMessage(
1955                 addSessionId(WM_MAYU_MESSAGE_NAME).c_str());
1956     int status = -1;
1957     switch (i_toggle)
1958     {
1959       case ToggleType_toggle:
1960         status = -1;
1961         break;
1962       case ToggleType_off:
1963         status = 0;
1964         break;
1965       case ToggleType_on:
1966         status = 1;
1967         break;
1968     }
1969     PostMessage(m_hwndFocus, WM_MAYU_MESSAGE, MayuMessage_funcSetImeStatus, status);
1970   }
1971 }
1972
1973 // set IME open status
1974 void Engine::funcSetImeString(FunctionParam *i_param, const StrExprArg &i_data)
1975 {
1976 #if defined(_WINNT)
1977   if (!i_param->m_isPressed)
1978     return;
1979   if (m_hwndFocus)
1980   {
1981     UINT WM_MAYU_MESSAGE = RegisterWindowMessage(
1982                 addSessionId(WM_MAYU_MESSAGE_NAME).c_str());
1983     PostMessage(m_hwndFocus, WM_MAYU_MESSAGE, MayuMessage_funcSetImeString, i_data.eval().size() * sizeof(_TCHAR));
1984
1985     DWORD len = 0;
1986     DWORD error;
1987     DisconnectNamedPipe(m_hookPipe);
1988     ConnectNamedPipe(m_hookPipe, NULL);
1989     error = WriteFile(m_hookPipe, i_data.eval().c_str(),
1990                       i_data.eval().size() * sizeof(_TCHAR),
1991                       &len, NULL);
1992
1993     //FlushFileBuffers(m_hookPipe);
1994   }
1995 #else
1996   Acquire a(&m_log);
1997   m_log << _T("supported on only Windows NT/2000/XP") << std::endl;
1998 #endif
1999 }
2000
2001 // Direct SSTP Server
2002 class DirectSSTPServer
2003 {
2004 public:
2005   tstring m_path;
2006   HWND m_hwnd;
2007   tstring m_name;
2008   tstring m_keroname;
2009
2010 public:
2011   DirectSSTPServer()
2012     : m_hwnd(NULL)
2013   {
2014   }
2015 };
2016
2017
2018 class ParseDirectSSTPData
2019 {
2020   typedef boost::match_results<boost::regex::const_iterator> MR;
2021
2022 public:
2023   typedef std::map<tstring, DirectSSTPServer> DirectSSTPServers;
2024
2025 private:
2026   DirectSSTPServers *m_directSSTPServers;
2027   
2028 public:
2029   // constructor
2030   ParseDirectSSTPData(DirectSSTPServers *i_directSSTPServers)
2031     : m_directSSTPServers(i_directSSTPServers)
2032   {
2033   }
2034   
2035   bool operator()(const MR& i_what)
2036   {
2037 #ifdef _UNICODE
2038     tstring id(to_wstring(std::string(i_what[1].first, i_what[1].second)));
2039     tstring member(to_wstring(std::string(i_what[2].first, i_what[2].second)));
2040     tstring value(to_wstring(std::string(i_what[3].first, i_what[3].second)));
2041 #else
2042     tstring id(i_what[1].first, i_what[1].second);
2043     tstring member(i_what[2].first, i_what[2].second);
2044     tstring value(i_what[3].first, i_what[3].second);
2045 #endif
2046
2047     if (member == _T("path"))
2048       (*m_directSSTPServers)[id].m_path = value;
2049     else if (member == _T("hwnd"))
2050       (*m_directSSTPServers)[id].m_hwnd =
2051         reinterpret_cast<HWND>(_ttoi(value.c_str()));
2052     else if (member == _T("name"))
2053       (*m_directSSTPServers)[id].m_name = value;
2054     else if (member == _T("keroname"))
2055       (*m_directSSTPServers)[id].m_keroname = value;
2056     return true; 
2057   }
2058 };
2059
2060 // Direct SSTP
2061 void Engine::funcDirectSSTP(FunctionParam *i_param,
2062                             const tregex &i_name,
2063                             const StrExprArg &i_protocol,
2064                             const std::list<tstringq> &i_headers)
2065 {
2066   if (!i_param->m_isPressed)
2067     return;
2068
2069   // check Direct SSTP server exist ?
2070   if (HANDLE hm = OpenMutex(MUTEX_ALL_ACCESS, FALSE, _T("sakura")))
2071     CloseHandle(hm);
2072   else
2073   {
2074     Acquire a(&m_log, 0);
2075     m_log << _T(" Error(1): Direct SSTP server does not exist.");
2076     return;
2077   }
2078
2079   HANDLE hfm = OpenFileMapping(FILE_MAP_READ, FALSE, _T("Sakura"));
2080   if (!hfm)
2081   {
2082     Acquire a(&m_log, 0);
2083     m_log << _T(" Error(2): Direct SSTP server does not provide data.");
2084     return;
2085   }
2086   
2087   char *data =
2088     reinterpret_cast<char *>(MapViewOfFile(hfm, FILE_MAP_READ, 0, 0, 0));
2089   if (!data)
2090   {
2091     CloseHandle(hfm);
2092     Acquire a(&m_log, 0);
2093     m_log << _T(" Error(3): Direct SSTP server does not provide data.");
2094     return;
2095   }
2096   
2097   long length = *(long *)data;
2098   const char *begin = data + 4;
2099   const char *end = data + length;
2100   boost::regex getSakura("([0-9a-fA-F]{32})\\.([^\x01]+)\x01(.*?)\r\n");
2101   
2102   ParseDirectSSTPData::DirectSSTPServers servers;
2103   boost::regex_iterator<boost::regex::const_iterator>
2104     it(begin, end, getSakura), last;
2105   for (; it != last; ++it)
2106     ((ParseDirectSSTPData)(&servers))(*it);
2107
2108   // make request
2109   tstring request;
2110   if (!i_protocol.eval().size())
2111     request += _T("NOTIFY SSTP/1.1");
2112   else
2113     request += i_protocol.eval();
2114   request += _T("\r\n");
2115
2116   bool hasSender = false;
2117   for (std::list<tstringq>::const_iterator
2118          i = i_headers.begin(); i != i_headers.end(); ++ i)
2119   {
2120     if (_tcsnicmp(_T("Charset"), i->c_str(), 7) == 0 ||
2121         _tcsnicmp(_T("Hwnd"),    i->c_str(), 4) == 0)
2122       continue;
2123     if (_tcsnicmp(_T("Sender"), i->c_str(), 6) == 0)
2124       hasSender = true;
2125     request += i->c_str();
2126     request += _T("\r\n");
2127   }
2128
2129   if (!hasSender)
2130   {
2131     request += _T("Sender: ");
2132     request += loadString(IDS_mayu);
2133     request += _T("\r\n");
2134   }
2135   
2136   _TCHAR buf[100];
2137   _sntprintf(buf, NUMBER_OF(buf), _T("HWnd: %d\r\n"),
2138              reinterpret_cast<int>(m_hwndAssocWindow));
2139   request += buf;
2140
2141 #ifdef _UNICODE
2142   request += _T("Charset: UTF-8\r\n");
2143 #else
2144   request += _T("Charset: Shift_JIS\r\n");
2145 #endif
2146   request += _T("\r\n");
2147
2148 #ifdef _UNICODE
2149   std::string request_UTF_8 = to_UTF_8(request);
2150 #endif
2151
2152   // send request to Direct SSTP Server which matches i_name;
2153   for (ParseDirectSSTPData::DirectSSTPServers::iterator
2154          i = servers.begin(); i != servers.end(); ++ i)
2155   {
2156     tsmatch what;
2157     if (boost::regex_match(i->second.m_name, what, i_name))
2158     {
2159       COPYDATASTRUCT cd;
2160       cd.dwData = 9801;
2161 #ifdef _UNICODE
2162       cd.cbData = request_UTF_8.size();
2163       cd.lpData = (void *)request_UTF_8.c_str();
2164 #else
2165       cd.cbData = request.size();
2166       cd.lpData = (void *)request.c_str();
2167 #endif
2168 #ifdef MAYU64
2169       DWORD_PTR result;
2170 #else
2171       DWORD result;
2172 #endif
2173       SendMessageTimeout(i->second.m_hwnd, WM_COPYDATA,
2174                          reinterpret_cast<WPARAM>(m_hwndAssocWindow),
2175                          reinterpret_cast<LPARAM>(&cd),
2176                          SMTO_ABORTIFHUNG | SMTO_BLOCK, 5000, &result);
2177     }
2178   }
2179   
2180   UnmapViewOfFile(data);
2181   CloseHandle(hfm);
2182 }
2183
2184
2185 namespace shu
2186 {
2187   class PlugIn
2188   {
2189     enum Type
2190     {
2191       Type_A,
2192       Type_W
2193     };
2194     
2195   private:
2196     HMODULE m_dll;
2197     FARPROC m_func;
2198     Type m_type;
2199     tstringq m_funcParam;
2200     
2201   public:
2202     PlugIn() : m_dll(NULL)
2203     {
2204     }
2205     
2206     ~PlugIn()
2207     {
2208       FreeLibrary(m_dll);
2209     }
2210
2211     bool load(const tstringq &i_dllName, const tstringq &i_funcName,
2212               const tstringq &i_funcParam, tomsgstream &i_log)
2213     {
2214       m_dll = LoadLibrary((_T("Plugins\\") + i_dllName).c_str());
2215       if (!m_dll)
2216       {
2217         m_dll = LoadLibrary((_T("Plugin\\") + i_dllName).c_str());
2218         if (!m_dll)
2219         {
2220           m_dll = LoadLibrary(i_dllName.c_str());
2221           if (!m_dll)
2222           {
2223             Acquire a(&i_log);
2224             i_log << std::endl;
2225             i_log << _T("error: &PlugIn() failed to load ") << i_dllName << std::endl;
2226             return false;
2227           }
2228         }
2229       }
2230
2231       // get function
2232 #ifdef UNICODE
2233 #  define to_wstring
2234 #else
2235 #  define to_string
2236 #endif
2237       m_type = Type_W;
2238       m_func = GetProcAddress(m_dll, to_string(_T("mayu") + i_funcName + _T("W")).c_str());
2239       if (!m_func)
2240       {
2241         m_type = Type_A;
2242         m_func
2243           = GetProcAddress(m_dll, to_string(_T("mayu") + i_funcName + _T("A")).c_str());
2244         if (!m_func)
2245         {
2246           m_func = GetProcAddress(m_dll, to_string(_T("mayu") + i_funcName).c_str());
2247           if (!m_func)
2248           {
2249             m_func = GetProcAddress(m_dll, to_string(i_funcName).c_str());
2250             if (!m_func)
2251             {
2252               Acquire a(&i_log);
2253               i_log << std::endl;
2254               i_log << _T("error: &PlugIn() failed to find function: ")
2255                     << i_funcName << std::endl;
2256               return false;
2257             }
2258           }
2259         }
2260       }
2261       
2262       m_funcParam = i_funcParam;
2263       return true;
2264     }
2265
2266     void exec()
2267     {
2268       ASSERT( m_dll );
2269       ASSERT( m_func );
2270       
2271       typedef void (WINAPI * PLUGIN_FUNCTION_A)(const char *i_arg);
2272       typedef void (WINAPI * PLUGIN_FUNCTION_W)(const wchar_t *i_arg);
2273       switch (m_type)
2274       {
2275         case Type_A:
2276           reinterpret_cast<PLUGIN_FUNCTION_A>(m_func)(to_string(m_funcParam).c_str());
2277           break;
2278         case Type_W:
2279           reinterpret_cast<PLUGIN_FUNCTION_W>(m_func)(to_wstring(m_funcParam).c_str());
2280           break;
2281       }
2282     }
2283 #undef to_string
2284 #undef to_wstring
2285   };
2286
2287   static void plugInThread(void *i_plugin)
2288   {
2289     PlugIn *plugin = static_cast<PlugIn *>(i_plugin);
2290     plugin->exec();
2291     delete plugin;
2292   }
2293 }
2294
2295 void Engine::funcPlugIn(FunctionParam *i_param,
2296                         const StrExprArg &i_dllName,
2297                         const StrExprArg &i_funcName,
2298                         const StrExprArg &i_funcParam,
2299                         BooleanType i_doesCreateThread)
2300 {
2301   if (!i_param->m_isPressed)
2302     return;
2303
2304   shu::PlugIn *plugin = new shu::PlugIn();
2305   if (!plugin->load(i_dllName.eval(), i_funcName.eval(), i_funcParam.eval(), m_log))
2306   {
2307     delete plugin;
2308     return;
2309   }
2310   if (i_doesCreateThread)
2311   {
2312     if (_beginthread(shu::plugInThread, 0, plugin) == -1)
2313     {
2314       delete plugin;
2315       Acquire a(&m_log);
2316       m_log << std::endl;
2317       m_log << _T("error: &PlugIn() failed to create thread.");
2318     }
2319     return;
2320   }
2321   else
2322     plugin->exec();
2323 }
2324
2325
2326 void Engine::funcMouseHook(FunctionParam *i_param,
2327                            MouseHookType i_hookType, int i_hookParam)
2328 {
2329   GetCursorPos(&g_hookData->m_mousePos);
2330   g_hookData->m_mouseHookType = i_hookType;
2331   g_hookData->m_mouseHookParam = i_hookParam;
2332
2333   switch (i_hookType)
2334   {
2335     case MouseHookType_WindowMove:
2336     {
2337       // For this type, g_hookData->m_mouseHookParam means
2338       // target window type to move.
2339       HWND target;
2340       bool isMDI;
2341
2342       // i_hooParam < 0 means target window to move is MDI.
2343       if (i_hookParam < 0)
2344         isMDI = true;
2345       else
2346         isMDI = false;
2347
2348       // abs(i_hookParam) == 2: target is window under mouse cursor
2349       // otherwise: target is current focus window
2350       if (i_hookParam == 2 || i_hookParam == -2)
2351         target = WindowFromPoint(g_hookData->m_mousePos);
2352       else
2353         target = i_param->m_hwnd;
2354
2355       g_hookData->m_hwndMouseHookTarget =
2356         reinterpret_cast<DWORD>(getToplevelWindow(target, &isMDI));
2357       break;
2358     default:
2359       g_hookData->m_hwndMouseHookTarget = NULL;
2360       break;
2361     }
2362   }
2363   return;
2364 }
2365
2366
2367 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2368 // StrExpr
2369 class StrExpr
2370 {
2371 private:
2372   tstringq m_symbol;
2373 protected:
2374   static const Engine *s_engine;
2375 public:
2376   StrExpr(const tstringq &i_symbol) : m_symbol(i_symbol) {};
2377
2378   virtual ~StrExpr() {};
2379
2380   virtual StrExpr *clone() const
2381   {
2382     return new StrExpr(*this);
2383   }
2384
2385   virtual tstringq eval() const
2386   {
2387     return m_symbol;
2388   }
2389
2390   static void setEngine(const Engine *i_engine) { s_engine = i_engine; }
2391 };
2392
2393 const Engine *StrExpr::s_engine = NULL;
2394
2395 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2396 // StrExprClipboard
2397 class StrExprClipboard : public StrExpr
2398 {
2399 public:
2400   StrExprClipboard(const tstringq &i_symbol) : StrExpr(i_symbol) {};
2401
2402   ~StrExprClipboard() {};
2403
2404   StrExpr *clone() const
2405   {
2406     return new StrExprClipboard(*this);
2407   }
2408
2409   tstringq eval() const
2410   {
2411     HGLOBAL g;
2412     const _TCHAR *text = getTextFromClipboard(&g);
2413     const tstring value(text == NULL ? _T("") : text);
2414     closeClipboard(g);
2415     return value;
2416   }
2417 };
2418
2419
2420 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2421 // StrExprWindowClassName
2422 class StrExprWindowClassName : public StrExpr
2423 {
2424 public:
2425   StrExprWindowClassName(const tstringq &i_symbol) : StrExpr(i_symbol) {};
2426
2427   ~StrExprWindowClassName() {};
2428
2429   StrExpr *clone() const
2430   {
2431     return new StrExprWindowClassName(*this);
2432   }
2433
2434   tstringq eval() const
2435   {
2436     return s_engine->getCurrentWindowClassName();
2437   }
2438 };
2439
2440
2441 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2442 // StrExprWindowTitleName
2443 class StrExprWindowTitleName : public StrExpr
2444 {
2445 public:
2446   StrExprWindowTitleName(const tstringq &i_symbol) : StrExpr(i_symbol) {};
2447
2448   ~StrExprWindowTitleName() {};
2449
2450   StrExpr *clone() const
2451   {
2452     return new StrExprWindowTitleName(*this);
2453   }
2454
2455   tstringq eval() const
2456   {
2457     return s_engine->getCurrentWindowTitleName();
2458   }
2459 };
2460
2461
2462 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2463 // StrExprArg
2464
2465
2466 // default constructor
2467 StrExprArg::StrExprArg()
2468 {
2469   m_expr = new StrExpr(_T(""));
2470 }
2471
2472
2473 // copy contructor
2474 StrExprArg::StrExprArg(const StrExprArg &i_data)
2475 {
2476   m_expr = i_data.m_expr->clone();
2477 }
2478
2479
2480 StrExprArg &StrExprArg::operator=(const StrExprArg &i_data)
2481 {
2482   if (i_data.m_expr == m_expr)
2483     return *this;
2484
2485   delete m_expr;
2486   m_expr = i_data.m_expr->clone();
2487
2488   return *this;
2489 }
2490
2491
2492 // initializer
2493 StrExprArg::StrExprArg(const tstringq &i_symbol, Type i_type)
2494 {
2495   switch (i_type)
2496   {
2497     case Literal:
2498       m_expr = new StrExpr(i_symbol);
2499       break;
2500     case Builtin:
2501       if (i_symbol == _T("Clipboard"))
2502         m_expr = new StrExprClipboard(i_symbol);
2503       else if (i_symbol == _T("WindowClassName"))
2504         m_expr = new StrExprWindowClassName(i_symbol);
2505       else if (i_symbol == _T("WindowTitleName"))
2506         m_expr = new StrExprWindowTitleName(i_symbol);
2507       break;
2508     default:
2509       break;
2510   }
2511 }
2512
2513
2514 StrExprArg::~StrExprArg()
2515 {
2516   delete m_expr;
2517 }
2518
2519
2520 tstringq StrExprArg::eval() const
2521 {
2522   return m_expr->eval();
2523 }
2524
2525 void StrExprArg::setEngine(const Engine *i_engine)
2526 {
2527   StrExpr::setEngine(i_engine);
2528 }
2529
2530 // stream output
2531 tostream &operator<<(tostream &i_ost, const StrExprArg &i_data)
2532 {
2533   i_ost << i_data.eval();
2534   return i_ost;
2535 }