OSDN Git Service

enable command notify on x64
[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                 clear();\r
147                 m_actions = i_ks.m_actions;\r
148                 m_mode = i_ks.m_mode;\r
149                 copy();\r
150         }\r
151         return *this;\r
152 }\r
153 \r
154 \r
155 KeySeq &KeySeq::add(const Action &i_action)\r
156 {\r
157         m_actions.push_back(i_action.clone());\r
158         return *this;\r
159 }\r
160 \r
161 \r
162 /// get the first modified key of this key sequence\r
163 ModifiedKey KeySeq::getFirstModifiedKey() const\r
164 {\r
165         if (0 < m_actions.size()) {\r
166                 const Action *a = m_actions.front();\r
167                 switch (a->getType()) {\r
168                 case Action::Type_key:\r
169                         return reinterpret_cast<const ActionKey *>(a)->m_modifiedKey;\r
170                 case Action::Type_keySeq:\r
171                         return reinterpret_cast<const ActionKeySeq *>(a)->\r
172                                    m_keySeq->getFirstModifiedKey();\r
173                 default:\r
174                         break;\r
175                 }\r
176         }\r
177         return ModifiedKey();                           // failed\r
178 }\r
179 \r
180 \r
181 // stream output\r
182 tostream &operator<<(tostream &i_ost, const KeySeq &i_ks)\r
183 {\r
184         for (KeySeq::Actions::const_iterator\r
185                         i = i_ks.m_actions.begin(); i != i_ks.m_actions.end(); ++ i)\r
186                 i_ost << **i << _T(" ");\r
187         return i_ost;\r
188 }\r
189 \r
190 \r
191 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
192 // Keymap\r
193 \r
194 \r
195 Keymap::KeyAssignments &Keymap::getKeyAssignments(const ModifiedKey &i_mk)\r
196 {\r
197         ASSERT(1 <= i_mk.m_key->getScanCodesSize());\r
198         return m_hashedKeyAssignments[i_mk.m_key->getScanCodes()->m_scan %\r
199                                                                   HASHED_KEY_ASSIGNMENT_SIZE];\r
200 }\r
201 \r
202 const Keymap::KeyAssignments &\r
203 Keymap::getKeyAssignments(const ModifiedKey &i_mk) const\r
204 {\r
205         ASSERT(1 <= i_mk.m_key->getScanCodesSize());\r
206         return m_hashedKeyAssignments[i_mk.m_key->getScanCodes()->m_scan %\r
207                                                                   HASHED_KEY_ASSIGNMENT_SIZE];\r
208 }\r
209 \r
210 \r
211 Keymap::Keymap(Type i_type,\r
212                            const tstringi &i_name,\r
213                            const tstringi &i_windowClass,\r
214                            const tstringi &i_windowTitle,\r
215                            KeySeq *i_defaultKeySeq,\r
216                            Keymap *i_parentKeymap)\r
217                 : m_type(i_type),\r
218                 m_name(i_name),\r
219                 m_defaultKeySeq(i_defaultKeySeq),\r
220                 m_parentKeymap(i_parentKeymap),\r
221                 m_windowClass(_T(".*")),\r
222                 m_windowTitle(_T(".*"))\r
223 {\r
224         if (i_type == Type_windowAnd || i_type == Type_windowOr)\r
225                 try {\r
226                         tregex::flag_type f = (tregex::normal |\r
227                                                                    tregex::icase);\r
228                         if (!i_windowClass.empty())\r
229                                 m_windowClass.assign(i_windowClass, f);\r
230                         if (!i_windowTitle.empty())\r
231                                 m_windowTitle.assign(i_windowTitle, f);\r
232                 } catch (boost::bad_expression &i_e) {\r
233                         throw ErrorMessage() << i_e.what();\r
234                 }\r
235 }\r
236 \r
237 \r
238 // add a key assignment;\r
239 void Keymap::addAssignment(const ModifiedKey &i_mk, KeySeq *i_keySeq)\r
240 {\r
241         KeyAssignments &ka = getKeyAssignments(i_mk);\r
242         for (KeyAssignments::iterator i = ka.begin(); i != ka.end(); ++ i)\r
243                 if ((*i).m_modifiedKey == i_mk) {\r
244                         (*i).m_keySeq = i_keySeq;\r
245                         return;\r
246                 }\r
247         ka.push_front(KeyAssignment(i_mk, i_keySeq));\r
248 }\r
249 \r
250 \r
251 // add modifier\r
252 void Keymap::addModifier(Modifier::Type i_mt, AssignOperator i_ao,\r
253                                                  AssignMode i_am, Key *i_key)\r
254 {\r
255         if (i_ao == AO_new)\r
256                 m_modAssignments[i_mt].clear();\r
257         else {\r
258                 for (ModAssignments::iterator i = m_modAssignments[i_mt].begin();\r
259                                 i != m_modAssignments[i_mt].end(); ++ i)\r
260                         if ((*i).m_key == i_key) {\r
261                                 (*i).m_assignOperator = i_ao;\r
262                                 (*i).m_assignMode = i_am;\r
263                                 return;\r
264                         }\r
265         }\r
266         ModAssignment ma;\r
267         ma.m_assignOperator = i_ao;\r
268         ma.m_assignMode = i_am;\r
269         ma.m_key = i_key;\r
270         m_modAssignments[i_mt].push_back(ma);\r
271 }\r
272 \r
273 \r
274 // search\r
275 const Keymap::KeyAssignment *\r
276 Keymap::searchAssignment(const ModifiedKey &i_mk) const\r
277 {\r
278         const KeyAssignments &ka = getKeyAssignments(i_mk);\r
279         for (KeyAssignments::const_iterator i = ka.begin(); i != ka.end(); ++ i)\r
280                 if ((*i).m_modifiedKey.m_key == i_mk.m_key &&\r
281                                 (*i).m_modifiedKey.m_modifier.doesMatch(i_mk.m_modifier))\r
282                         return &(*i);\r
283         return NULL;\r
284 }\r
285 \r
286 \r
287 // does same window\r
288 bool Keymap::doesSameWindow(const tstringi i_className,\r
289                                                         const tstringi &i_titleName)\r
290 {\r
291         if (m_type == Type_keymap)\r
292                 return false;\r
293 \r
294         tsmatch what;\r
295         if (boost::regex_search(i_className, what, m_windowClass)) {\r
296                 if (m_type == Type_windowAnd)\r
297                         return boost::regex_search(i_titleName, what, m_windowTitle);\r
298                 else // type == Type_windowOr\r
299                         return true;\r
300         } else {\r
301                 if (m_type == Type_windowAnd)\r
302                         return false;\r
303                 else // type == Type_windowOr\r
304                         return boost::regex_search(i_titleName, what, m_windowTitle);\r
305         }\r
306 }\r
307 \r
308 \r
309 // adjust modifier\r
310 void Keymap::adjustModifier(Keyboard &i_keyboard)\r
311 {\r
312         for (size_t i = 0; i < NUMBER_OF(m_modAssignments); ++ i) {\r
313                 ModAssignments mos;\r
314                 if (m_parentKeymap)\r
315                         mos = m_parentKeymap->m_modAssignments[i];\r
316                 else {\r
317                         // set default modifiers\r
318                         if (i < Modifier::Type_BASIC) {\r
319                                 Keyboard::Mods mods =\r
320                                         i_keyboard.getModifiers(static_cast<Modifier::Type>(i));\r
321                                 for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j) {\r
322                                         ModAssignment ma;\r
323                                         ma.m_assignOperator = AO_add;\r
324                                         ma.m_assignMode = AM_normal;\r
325                                         ma.m_key = *j;\r
326                                         mos.push_back(ma);\r
327                                 }\r
328                         }\r
329                 }\r
330 \r
331                 // mod adjust\r
332                 for (ModAssignments::iterator mai = m_modAssignments[i].begin();\r
333                                 mai != m_modAssignments[i].end(); ++ mai) {\r
334                         ModAssignment ma = *mai;\r
335                         ma.m_assignOperator = AO_new;\r
336                         switch ((*mai).m_assignOperator) {\r
337                         case AO_new: {\r
338                                 mos.clear();\r
339                                 mos.push_back(ma);\r
340                                 break;\r
341                         }\r
342                         case AO_add: {\r
343                                 mos.push_back(ma);\r
344                                 break;\r
345                         }\r
346                         case AO_sub: {\r
347                                 for (ModAssignments::iterator j = mos.begin();\r
348                                                 j != mos.end(); ++ j)\r
349                                         if ((*j).m_key == ma.m_key) {\r
350                                                 mos.erase(j);\r
351                                                 break;\r
352                                         }\r
353                                 break;\r
354                         }\r
355                         case AO_overwrite: {\r
356                                 for (ModAssignments::iterator j = mos.begin();\r
357                                                 j != mos.end(); ++ j)\r
358                                         (*j).m_assignMode = (*mai).m_assignMode;\r
359                                 break;\r
360                         }\r
361                         }\r
362                 }\r
363 \r
364                 // erase redundant modifiers\r
365                 for (ModAssignments::iterator j = mos.begin(); j != mos.end(); ++ j) {\r
366                         ModAssignments::iterator k;\r
367                         for (k = j, ++ k; k != mos.end(); ++ k)\r
368                                 if ((*k).m_key == (*j).m_key)\r
369                                         break;\r
370                         if (k != mos.end()) {\r
371                                 k = j;\r
372                                 ++ j;\r
373                                 mos.erase(k);\r
374                                 break;\r
375                         }\r
376                 }\r
377 \r
378                 m_modAssignments[i] = mos;\r
379         }\r
380 }\r
381 \r
382 \r
383 // describe\r
384 void Keymap::describe(tostream &i_ost, DescribeParam *i_dp) const\r
385 {\r
386         // Is this keymap already described ?\r
387         {\r
388                 DescribeParam::DescribedKeymap::iterator\r
389                 i = std::find(i_dp->m_dkeymap.begin(), i_dp->m_dkeymap.end(), this);\r
390                 if (i != i_dp->m_dkeymap.end())\r
391                         return;                                 // yes!\r
392                 i_dp->m_dkeymap.push_back(this);\r
393         }\r
394 \r
395         switch (m_type) {\r
396         case Type_keymap:\r
397                 i_ost << _T("keymap ") << m_name;\r
398                 break;\r
399         case Type_windowAnd:\r
400                 i_ost << _T("window ") << m_name << _T(" ");\r
401                 if (m_windowTitle.str() == _T(".*"))\r
402                         i_ost << _T("/") << m_windowClass.str() << _T("/");\r
403                 else\r
404                         i_ost << _T("( /") << m_windowClass.str() << _T("/ && /")\r
405                         << m_windowTitle.str() << _T("/ )");\r
406                 break;\r
407         case Type_windowOr:\r
408                 i_ost << _T("window ") << m_name << _T(" ( /")\r
409                 << m_windowClass.str() << _T("/ || /") << m_windowTitle.str()\r
410                 << _T("/ )");\r
411                 break;\r
412         }\r
413         if (m_parentKeymap)\r
414                 i_ost << _T(" : ") << m_parentKeymap->m_name;\r
415         i_ost << _T(" = ") << *m_defaultKeySeq << std::endl;\r
416 \r
417         // describe modifiers\r
418         if (i_dp->m_doesDescribeModifiers) {\r
419                 for (int t = Modifier::Type_begin; t != Modifier::Type_end; ++ t) {\r
420                         Modifier::Type type = static_cast<Modifier::Type>(t);\r
421                         const Keymap::ModAssignments &ma = getModAssignments(type);\r
422                         if (ma.size()) {\r
423                                 i_ost << _T(" mod ") << type << _T("\t= ");\r
424                                 for (Keymap::ModAssignments::const_iterator\r
425                                                 j = ma.begin(); j != ma.end(); ++ j) {\r
426                                         switch (j->m_assignMode) {\r
427                                         case Keymap::AM_true:\r
428                                                 i_ost << _T("!");\r
429                                                 break;\r
430                                         case Keymap::AM_oneShot:\r
431                                                 i_ost << _T("!!");\r
432                                                 break;\r
433                                         case Keymap::AM_oneShotRepeatable:\r
434                                                 i_ost << _T("!!!");\r
435                                                 break;\r
436                                         default:\r
437                                                 break;\r
438                                         }\r
439                                         i_ost << *j->m_key << _T(" ");\r
440                                 }\r
441                                 i_ost << std::endl;\r
442                         }\r
443                 }\r
444                 i_dp->m_doesDescribeModifiers = false;\r
445         }\r
446 \r
447         typedef std::vector<KeyAssignment> SortedKeyAssignments;\r
448         SortedKeyAssignments ska;\r
449         for (size_t i = 0; i < HASHED_KEY_ASSIGNMENT_SIZE; ++ i) {\r
450                 const KeyAssignments &ka = m_hashedKeyAssignments[i];\r
451                 for (KeyAssignments::const_iterator j = ka.begin(); j != ka.end(); ++ j)\r
452                         ska.push_back(*j);\r
453         }\r
454         std::sort(ska.begin(), ska.end());\r
455         for (SortedKeyAssignments::iterator i = ska.begin(); i != ska.end(); ++ i) {\r
456                 // Is this key assignment already described ?\r
457                 DescribeParam::DescribedKeys::iterator\r
458                 j = std::find(i_dp->m_dk.begin(), i_dp->m_dk.end(), i->m_modifiedKey);\r
459                 if (j != i_dp->m_dk.end())\r
460                         continue;                                       // yes!\r
461 \r
462                 // check if the key is an event\r
463                 Key **e;\r
464                 for (e = Event::events; *e; ++ e)\r
465                         if (i->m_modifiedKey.m_key == *e)\r
466                                 break;\r
467                 if (*e)\r
468                         i_ost << _T(" event ") << *i->m_modifiedKey.m_key;\r
469                 else\r
470                         i_ost << _T(" key ") << i->m_modifiedKey;\r
471                 i_ost << _T("\t= ") << *i->m_keySeq << std::endl;\r
472                 i_dp->m_dk.push_back(i->m_modifiedKey);\r
473         }\r
474 \r
475         i_ost << std::endl;\r
476 \r
477         if (m_parentKeymap)\r
478                 m_parentKeymap->describe(i_ost, i_dp);\r
479 }\r
480 \r
481 // set default keySeq and parent keymap if default keySeq has not been set\r
482 bool Keymap::setIfNotYet(KeySeq *i_keySeq, Keymap *i_parentKeymap)\r
483 {\r
484         if (m_defaultKeySeq)\r
485                 return false;\r
486         m_defaultKeySeq = i_keySeq;\r
487         m_parentKeymap = i_parentKeymap;\r
488         return true;\r
489 }\r
490 \r
491 // stream output\r
492 extern tostream &operator<<(tostream &i_ost, const Keymap *i_keymap)\r
493 {\r
494         return i_ost << i_keymap->getName();\r
495 }\r
496 \r
497 \r
498 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
499 // Keymaps\r
500 \r
501 \r
502 Keymaps::Keymaps()\r
503 {\r
504 }\r
505 \r
506 \r
507 // search by name\r
508 Keymap *Keymaps::searchByName(const tstringi &i_name)\r
509 {\r
510         for (KeymapList::iterator\r
511                         i = m_keymapList.begin(); i != m_keymapList.end(); ++ i)\r
512                 if ((*i).getName() == i_name)\r
513                         return &*i;\r
514         return NULL;\r
515 }\r
516 \r
517 \r
518 // search window\r
519 void Keymaps::searchWindow(KeymapPtrList *o_keymapPtrList,\r
520                                                    const tstringi &i_className,\r
521                                                    const tstringi &i_titleName)\r
522 {\r
523         o_keymapPtrList->clear();\r
524         for (KeymapList::iterator\r
525                         i = m_keymapList.begin(); i != m_keymapList.end(); ++ i)\r
526                 if ((*i).doesSameWindow(i_className, i_titleName))\r
527                         o_keymapPtrList->push_back(&(*i));\r
528 }\r
529 \r
530 \r
531 // add keymap\r
532 Keymap *Keymaps::add(const Keymap &i_keymap)\r
533 {\r
534         if (Keymap *k = searchByName(i_keymap.getName()))\r
535                 return k;\r
536         m_keymapList.push_front(i_keymap);\r
537         return &m_keymapList.front();\r
538 }\r
539 \r
540 \r
541 // adjust modifier\r
542 void Keymaps::adjustModifier(Keyboard &i_keyboard)\r
543 {\r
544         for (KeymapList::reverse_iterator i = m_keymapList.rbegin();\r
545                         i != m_keymapList.rend(); ++ i)\r
546                 (*i).adjustModifier(i_keyboard);\r
547 }\r
548 \r
549 \r
550 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
551 // KeySeqs\r
552 \r
553 \r
554 // add a named keyseq (name can be empty)\r
555 KeySeq *KeySeqs::add(const KeySeq &i_keySeq)\r
556 {\r
557         if (!i_keySeq.getName().empty()) {\r
558                 KeySeq *ks = searchByName(i_keySeq.getName());\r
559                 if (ks)\r
560                         return &(*ks = i_keySeq);\r
561         }\r
562         m_keySeqList.push_front(i_keySeq);\r
563         return &m_keySeqList.front();\r
564 }\r
565 \r
566 \r
567 // search by name\r
568 KeySeq *KeySeqs::searchByName(const tstringi &i_name)\r
569 {\r
570         for (KeySeqList::iterator\r
571                         i = m_keySeqList.begin(); i != m_keySeqList.end(); ++ i)\r
572                 if ((*i).getName() == i_name)\r
573                         return &(*i);\r
574         return NULL;\r
575 }\r