OSDN Git Service

change EOL style to CRLF to adjust to default setting of Visual Studio
[yamy/yamy.git] / keymap.cpp
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
2 // setting.cpp\r
3 \r
4 \r
5 #include "keymap.h"\r
6 #include "errormessage.h"\r
7 #include "stringtool.h"\r
8 #include "setting.h"\r
9 #include <algorithm>\r
10 \r
11 \r
12 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
13 // Action\r
14 \r
15 //\r
16 tostream &operator<<(tostream &i_ost, const Action &i_action)\r
17 {\r
18   return i_action.output(i_ost);\r
19 }\r
20 \r
21 \r
22 //\r
23 ActionKey::ActionKey(const ModifiedKey &i_mk)\r
24   : m_modifiedKey(i_mk)\r
25 {\r
26 }\r
27 \r
28 //\r
29 Action::Type ActionKey::getType() const\r
30 {\r
31   return Type_key;\r
32 }\r
33 \r
34 // create clone\r
35 Action *ActionKey::clone() const\r
36 {\r
37   return new ActionKey(m_modifiedKey);\r
38 }\r
39 \r
40 // stream output\r
41 tostream &ActionKey::output(tostream &i_ost) const\r
42 {\r
43   return i_ost << m_modifiedKey;\r
44 }\r
45 \r
46 //\r
47 ActionKeySeq::ActionKeySeq(KeySeq *i_keySeq)\r
48   : m_keySeq(i_keySeq)\r
49 {\r
50 }\r
51 \r
52 //\r
53 Action::Type ActionKeySeq::getType() const\r
54 {\r
55   return Type_keySeq;\r
56 }\r
57 \r
58 // create clone\r
59 Action *ActionKeySeq::clone() const\r
60 {\r
61   return new ActionKeySeq(m_keySeq);\r
62 }\r
63 \r
64 // stream output\r
65 tostream &ActionKeySeq::output(tostream &i_ost) const\r
66 {\r
67   return i_ost << _T("$") << m_keySeq->getName();\r
68 }\r
69 \r
70 //\r
71 ActionFunction::ActionFunction(FunctionData *i_functionData,\r
72                                Modifier i_modifier)\r
73   : m_functionData(i_functionData),\r
74     m_modifier(i_modifier)\r
75 {\r
76 }\r
77 \r
78 //\r
79 ActionFunction::~ActionFunction()\r
80 {\r
81   delete m_functionData;\r
82 }\r
83 \r
84 //\r
85 Action::Type ActionFunction::getType() const\r
86 {\r
87   return Type_function;\r
88 }\r
89 \r
90 // create clone\r
91 Action *ActionFunction::clone() const\r
92 {\r
93   return new ActionFunction(m_functionData->clone(), m_modifier);\r
94 }\r
95 \r
96 // stream output\r
97 tostream &ActionFunction::output(tostream &i_ost) const\r
98 {\r
99   return i_ost << m_modifier << m_functionData;\r
100 }\r
101 \r
102 \r
103 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
104 // KeySeq\r
105 \r
106 \r
107 void KeySeq::copy()\r
108 {\r
109   for (Actions::iterator i = m_actions.begin(); i != m_actions.end(); ++ i)\r
110     (*i) = (*i)->clone();\r
111 }\r
112 \r
113 \r
114 void KeySeq::clear()\r
115 {\r
116   for (Actions::iterator i = m_actions.begin(); i != m_actions.end(); ++ i)\r
117     delete (*i);\r
118 }\r
119 \r
120 \r
121 KeySeq::KeySeq(const tstringi &i_name)\r
122   : m_name(i_name),\r
123     m_mode(Modifier::Type_KEYSEQ)\r
124 {\r
125 }\r
126 \r
127 \r
128 KeySeq::KeySeq(const KeySeq &i_ks)\r
129   : m_actions(i_ks.m_actions),\r
130     m_name(i_ks.m_name),\r
131     m_mode(i_ks.m_mode)\r
132 {\r
133   copy();\r
134 }\r
135 \r
136 \r
137 KeySeq::~KeySeq()\r
138 {\r
139   clear();\r
140 }\r
141 \r
142 \r
143 KeySeq &KeySeq::operator=(const KeySeq &i_ks)\r
144 {\r
145   if (this != &i_ks)\r
146   {\r
147     clear();\r
148     m_actions = i_ks.m_actions;\r
149     m_mode = i_ks.m_mode;\r
150     copy();\r
151   }\r
152   return *this;\r
153 }\r
154 \r
155 \r
156 KeySeq &KeySeq::add(const Action &i_action)\r
157 {\r
158   m_actions.push_back(i_action.clone());\r
159   return *this;\r
160 }\r
161 \r
162 \r
163 /// get the first modified key of this key sequence\r
164 ModifiedKey KeySeq::getFirstModifiedKey() const\r
165 {\r
166   if (0 < m_actions.size())\r
167   {\r
168     const Action *a = m_actions.front();\r
169     switch (a->getType())\r
170     {\r
171       case Action::Type_key:\r
172         return reinterpret_cast<const ActionKey *>(a)->m_modifiedKey;\r
173       case Action::Type_keySeq:\r
174         return reinterpret_cast<const ActionKeySeq *>(a)->\r
175           m_keySeq->getFirstModifiedKey();\r
176       default:\r
177         break;\r
178     }\r
179   }\r
180   return ModifiedKey();                         // failed\r
181 }\r
182 \r
183 \r
184 // stream output\r
185 tostream &operator<<(tostream &i_ost, const KeySeq &i_ks)\r
186 {\r
187   for (KeySeq::Actions::const_iterator\r
188          i = i_ks.m_actions.begin(); i != i_ks.m_actions.end(); ++ i)\r
189     i_ost << **i << _T(" ");\r
190   return i_ost;\r
191 }\r
192 \r
193 \r
194 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
195 // Keymap\r
196 \r
197 \r
198 Keymap::KeyAssignments &Keymap::getKeyAssignments(const ModifiedKey &i_mk)\r
199 {\r
200   ASSERT(1 <= i_mk.m_key->getScanCodesSize());\r
201   return m_hashedKeyAssignments[i_mk.m_key->getScanCodes()->m_scan %\r
202                                HASHED_KEY_ASSIGNMENT_SIZE];\r
203 }\r
204 \r
205 const Keymap::KeyAssignments &\r
206 Keymap::getKeyAssignments(const ModifiedKey &i_mk) const\r
207 {\r
208   ASSERT(1 <= i_mk.m_key->getScanCodesSize());\r
209   return m_hashedKeyAssignments[i_mk.m_key->getScanCodes()->m_scan %\r
210                                HASHED_KEY_ASSIGNMENT_SIZE];\r
211 }\r
212 \r
213 \r
214 Keymap::Keymap(Type i_type,\r
215                const tstringi &i_name,\r
216                const tstringi &i_windowClass,\r
217                const tstringi &i_windowTitle,\r
218                KeySeq *i_defaultKeySeq,\r
219                Keymap *i_parentKeymap)\r
220   : m_type(i_type),\r
221     m_name(i_name),\r
222     m_defaultKeySeq(i_defaultKeySeq),\r
223     m_parentKeymap(i_parentKeymap),\r
224     m_windowClass(_T(".*")),\r
225     m_windowTitle(_T(".*"))\r
226 {\r
227   if (i_type == Type_windowAnd || i_type == Type_windowOr)\r
228     try\r
229     {\r
230       tregex::flag_type f = (tregex::normal | \r
231                              tregex::icase);\r
232       if (!i_windowClass.empty())\r
233         m_windowClass.assign(i_windowClass, f);\r
234       if (!i_windowTitle.empty())\r
235         m_windowTitle.assign(i_windowTitle, f);\r
236     }\r
237     catch (boost::bad_expression &i_e)\r
238     {\r
239       throw ErrorMessage() << i_e.what();\r
240     }\r
241 }\r
242 \r
243 \r
244 // add a key assignment;\r
245 void Keymap::addAssignment(const ModifiedKey &i_mk, KeySeq *i_keySeq)\r
246 {\r
247   KeyAssignments &ka = getKeyAssignments(i_mk);\r
248   for (KeyAssignments::iterator i = ka.begin(); i != ka.end(); ++ i)\r
249     if ((*i).m_modifiedKey == i_mk)\r
250     {\r
251       (*i).m_keySeq = i_keySeq;\r
252       return;\r
253     }\r
254   ka.push_front(KeyAssignment(i_mk, i_keySeq));\r
255 }\r
256 \r
257 \r
258 // add modifier\r
259 void Keymap::addModifier(Modifier::Type i_mt, AssignOperator i_ao,\r
260                          AssignMode i_am, Key *i_key)\r
261 {\r
262   if (i_ao == AO_new)\r
263     m_modAssignments[i_mt].clear();\r
264   else\r
265   {\r
266     for (ModAssignments::iterator i = m_modAssignments[i_mt].begin();\r
267          i != m_modAssignments[i_mt].end(); ++ i)\r
268       if ((*i).m_key == i_key)\r
269       {\r
270         (*i).m_assignOperator = i_ao;\r
271         (*i).m_assignMode = i_am;\r
272         return;\r
273       }\r
274   }\r
275   ModAssignment ma;\r
276   ma.m_assignOperator = i_ao;\r
277   ma.m_assignMode = i_am;\r
278   ma.m_key = i_key;\r
279   m_modAssignments[i_mt].push_back(ma);\r
280 }\r
281 \r
282   \r
283 // search\r
284 const Keymap::KeyAssignment *\r
285 Keymap::searchAssignment(const ModifiedKey &i_mk) const\r
286 {\r
287   const KeyAssignments &ka = getKeyAssignments(i_mk);\r
288   for (KeyAssignments::const_iterator i = ka.begin(); i != ka.end(); ++ i)\r
289     if ((*i).m_modifiedKey.m_key == i_mk.m_key &&\r
290         (*i).m_modifiedKey.m_modifier.doesMatch(i_mk.m_modifier))\r
291       return &(*i);\r
292   return NULL;\r
293 }\r
294 \r
295 \r
296 // does same window\r
297 bool Keymap::doesSameWindow(const tstringi i_className,\r
298                             const tstringi &i_titleName)\r
299 {\r
300   if (m_type == Type_keymap)\r
301     return false;\r
302 \r
303   tsmatch what;\r
304   if (boost::regex_search(i_className, what, m_windowClass))\r
305   {\r
306     if (m_type == Type_windowAnd)\r
307       return boost::regex_search(i_titleName, what, m_windowTitle);\r
308     else // type == Type_windowOr\r
309       return true;\r
310   }\r
311   else\r
312   {\r
313     if (m_type == Type_windowAnd)\r
314       return false;\r
315     else // type == Type_windowOr\r
316       return boost::regex_search(i_titleName, what, m_windowTitle);\r
317   }\r
318 }\r
319 \r
320 \r
321 // adjust modifier\r
322 void Keymap::adjustModifier(Keyboard &i_keyboard)\r
323 {\r
324   for (size_t i = 0; i < NUMBER_OF(m_modAssignments); ++ i)\r
325   {\r
326     ModAssignments mos;\r
327     if (m_parentKeymap)\r
328       mos = m_parentKeymap->m_modAssignments[i];\r
329     else\r
330     {\r
331       // set default modifiers\r
332       if (i < Modifier::Type_BASIC)\r
333       {\r
334         Keyboard::Mods mods =\r
335           i_keyboard.getModifiers(static_cast<Modifier::Type>(i));\r
336         for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)\r
337         {\r
338           ModAssignment ma;\r
339           ma.m_assignOperator = AO_add;\r
340           ma.m_assignMode = AM_normal;\r
341           ma.m_key = *j;\r
342           mos.push_back(ma);\r
343         }\r
344       }\r
345     }\r
346     \r
347     // mod adjust\r
348     for (ModAssignments::iterator mai = m_modAssignments[i].begin();\r
349          mai != m_modAssignments[i].end(); ++ mai)\r
350     {\r
351       ModAssignment ma = *mai;\r
352       ma.m_assignOperator = AO_new;\r
353       switch ((*mai).m_assignOperator)\r
354       {\r
355         case AO_new:\r
356         {\r
357           mos.clear();\r
358           mos.push_back(ma);\r
359           break;\r
360         }\r
361         case AO_add:\r
362         {\r
363           mos.push_back(ma);\r
364           break;\r
365         }\r
366         case AO_sub:\r
367         {\r
368           for (ModAssignments::iterator j = mos.begin();\r
369                j != mos.end(); ++ j)\r
370             if ((*j).m_key == ma.m_key)\r
371             {\r
372               mos.erase(j);\r
373               break;\r
374             }\r
375           break;\r
376         }\r
377         case AO_overwrite:\r
378         {\r
379           for (ModAssignments::iterator j = mos.begin();\r
380                j != mos.end(); ++ j)\r
381             (*j).m_assignMode = (*mai).m_assignMode;\r
382           break;\r
383         }\r
384       }\r
385     }\r
386 \r
387     // erase redundant modifiers\r
388     for (ModAssignments::iterator j = mos.begin(); j != mos.end(); ++ j)\r
389     {\r
390       ModAssignments::iterator k;\r
391       for (k = j, ++ k; k != mos.end(); ++ k)\r
392         if ((*k).m_key == (*j).m_key)\r
393           break;\r
394       if (k != mos.end())\r
395       {\r
396         k = j;\r
397         ++ j;\r
398         mos.erase(k);\r
399         break;\r
400       }\r
401     }\r
402     \r
403     m_modAssignments[i] = mos;\r
404   }\r
405 }\r
406 \r
407 \r
408 // describe\r
409 void Keymap::describe(tostream &i_ost, DescribeParam *i_dp) const\r
410 {\r
411   // Is this keymap already described ?\r
412   {\r
413     DescribeParam::DescribedKeymap::iterator\r
414       i = std::find(i_dp->m_dkeymap.begin(), i_dp->m_dkeymap.end(), this);\r
415     if (i != i_dp->m_dkeymap.end())\r
416       return;                                   // yes!\r
417     i_dp->m_dkeymap.push_back(this);\r
418   }\r
419 \r
420   switch (m_type)\r
421   {\r
422     case Type_keymap:\r
423       i_ost << _T("keymap ") << m_name;\r
424       break;\r
425     case Type_windowAnd:\r
426       i_ost << _T("window ") << m_name << _T(" ");\r
427       if (m_windowTitle.str() == _T(".*"))\r
428         i_ost << _T("/") << m_windowClass.str() << _T("/");\r
429       else\r
430         i_ost << _T("( /") << m_windowClass.str() << _T("/ && /")\r
431               << m_windowTitle.str() << _T("/ )");\r
432       break;\r
433     case Type_windowOr:\r
434       i_ost << _T("window ") << m_name << _T(" ( /")\r
435             << m_windowClass.str() << _T("/ || /") << m_windowTitle.str()\r
436             << _T("/ )");\r
437       break;\r
438   }\r
439   if (m_parentKeymap)\r
440     i_ost << _T(" : ") << m_parentKeymap->m_name;\r
441   i_ost << _T(" = ") << *m_defaultKeySeq << std::endl;\r
442 \r
443   // describe modifiers\r
444   if (i_dp->m_doesDescribeModifiers)\r
445   {\r
446     for (int t = Modifier::Type_begin; t != Modifier::Type_end; ++ t)\r
447     {\r
448       Modifier::Type type = static_cast<Modifier::Type>(t);\r
449       const Keymap::ModAssignments &ma = getModAssignments(type);\r
450       if (ma.size())\r
451       {\r
452         i_ost << _T(" mod ") << type << _T("\t= ");\r
453         for (Keymap::ModAssignments::const_iterator\r
454                j = ma.begin(); j != ma.end(); ++ j)\r
455         {\r
456           switch (j->m_assignMode)\r
457           {\r
458             case Keymap::AM_true: i_ost << _T("!"); break;\r
459             case Keymap::AM_oneShot: i_ost << _T("!!"); break;\r
460             case Keymap::AM_oneShotRepeatable: i_ost << _T("!!!"); break;\r
461             default:\r
462               break;\r
463           }\r
464           i_ost << *j->m_key << _T(" ");\r
465         }\r
466         i_ost << std::endl;\r
467       }\r
468     }\r
469     i_dp->m_doesDescribeModifiers = false;\r
470   }\r
471   \r
472   typedef std::vector<KeyAssignment> SortedKeyAssignments;\r
473   SortedKeyAssignments ska;\r
474   for (size_t i = 0; i < HASHED_KEY_ASSIGNMENT_SIZE; ++ i)\r
475   {\r
476     const KeyAssignments &ka = m_hashedKeyAssignments[i];\r
477     for (KeyAssignments::const_iterator j = ka.begin(); j != ka.end(); ++ j)\r
478       ska.push_back(*j);\r
479   }\r
480   std::sort(ska.begin(), ska.end());\r
481   for (SortedKeyAssignments::iterator i = ska.begin(); i != ska.end(); ++ i)\r
482   {\r
483     // Is this key assignment already described ?\r
484     DescribeParam::DescribedKeys::iterator\r
485       j = std::find(i_dp->m_dk.begin(), i_dp->m_dk.end(), i->m_modifiedKey);\r
486     if (j != i_dp->m_dk.end())\r
487       continue;                                 // yes!\r
488 \r
489     // check if the key is an event\r
490     Key **e;\r
491     for (e = Event::events; *e; ++ e)\r
492       if (i->m_modifiedKey.m_key == *e)\r
493         break;\r
494     if (*e)\r
495       i_ost << _T(" event ") << *i->m_modifiedKey.m_key;\r
496     else\r
497       i_ost << _T(" key ") << i->m_modifiedKey;\r
498     i_ost << _T("\t= ") << *i->m_keySeq << std::endl;\r
499     i_dp->m_dk.push_back(i->m_modifiedKey);\r
500   }\r
501 \r
502   i_ost << std::endl;\r
503   \r
504   if (m_parentKeymap)\r
505     m_parentKeymap->describe(i_ost, i_dp);\r
506 }\r
507 \r
508 // set default keySeq and parent keymap if default keySeq has not been set\r
509 bool Keymap::setIfNotYet(KeySeq *i_keySeq, Keymap *i_parentKeymap)\r
510 {\r
511   if (m_defaultKeySeq)\r
512     return false;\r
513   m_defaultKeySeq = i_keySeq;\r
514   m_parentKeymap = i_parentKeymap;\r
515   return true;\r
516 }\r
517 \r
518 // stream output\r
519 extern tostream &operator<<(tostream &i_ost, const Keymap *i_keymap)\r
520 {\r
521   return i_ost << i_keymap->getName();\r
522 }\r
523 \r
524 \r
525 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
526 // Keymaps\r
527 \r
528 \r
529 Keymaps::Keymaps()\r
530 {\r
531 }\r
532 \r
533 \r
534 // search by name\r
535 Keymap *Keymaps::searchByName(const tstringi &i_name)\r
536 {\r
537   for (KeymapList::iterator\r
538          i = m_keymapList.begin(); i != m_keymapList.end(); ++ i)\r
539     if ((*i).getName() == i_name)\r
540       return &*i;\r
541   return NULL;\r
542 }\r
543 \r
544 \r
545 // search window\r
546 void Keymaps::searchWindow(KeymapPtrList *o_keymapPtrList,\r
547                            const tstringi &i_className,\r
548                            const tstringi &i_titleName)\r
549 {\r
550   o_keymapPtrList->clear();\r
551   for (KeymapList::iterator\r
552          i = m_keymapList.begin(); i != m_keymapList.end(); ++ i)\r
553     if ((*i).doesSameWindow(i_className, i_titleName))\r
554       o_keymapPtrList->push_back(&(*i));\r
555 }\r
556 \r
557 \r
558 // add keymap\r
559 Keymap *Keymaps::add(const Keymap &i_keymap)\r
560 {\r
561   if (Keymap *k = searchByName(i_keymap.getName()))\r
562     return k;\r
563   m_keymapList.push_front(i_keymap);\r
564   return &m_keymapList.front();\r
565 }\r
566 \r
567 \r
568 // adjust modifier\r
569 void Keymaps::adjustModifier(Keyboard &i_keyboard)\r
570 {\r
571   for (KeymapList::reverse_iterator i = m_keymapList.rbegin();\r
572        i != m_keymapList.rend(); ++ i)\r
573     (*i).adjustModifier(i_keyboard);\r
574 }\r
575 \r
576 \r
577 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
578 // KeySeqs\r
579 \r
580 \r
581 // add a named keyseq (name can be empty)\r
582 KeySeq *KeySeqs::add(const KeySeq &i_keySeq)\r
583 {\r
584   if (!i_keySeq.getName().empty())\r
585   {\r
586     KeySeq *ks = searchByName(i_keySeq.getName());\r
587     if (ks)\r
588       return &(*ks = i_keySeq);\r
589   }\r
590   m_keySeqList.push_front(i_keySeq);\r
591   return &m_keySeqList.front();\r
592 }\r
593 \r
594 \r
595 // search by name\r
596 KeySeq *KeySeqs::searchByName(const tstringi &i_name)\r
597 {\r
598   for (KeySeqList::iterator\r
599          i = m_keySeqList.begin(); i != m_keySeqList.end(); ++ i)\r
600     if ((*i).getName() == i_name)\r
601       return &(*i);\r
602   return NULL;\r
603 }\r