strip keyboard.cc of noxious focus handling stuff, and cleanup
[ardour.git] / gtk2_ardour / keyboard.cc
1 /*
2     Copyright (C) 2001 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include "ardour_ui.h"
22
23 #include <algorithm>
24 #include <fstream>
25
26 #include <ctype.h>
27
28 #include <X11/keysymdef.h>
29 #include <gdk/gdkx.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <pbd/error.h>
32
33 #include "keyboard.h"
34 #include "gui_thread.h"
35
36 #include "i18n.h"
37
38 #define KBD_DEBUG 1
39 bool debug_keyboard = false;
40
41 guint Keyboard::edit_but = 3;
42 guint Keyboard::edit_mod = GDK_CONTROL_MASK;
43 guint Keyboard::delete_but = 3;
44 guint Keyboard::delete_mod = GDK_SHIFT_MASK;
45 guint Keyboard::snap_mod = GDK_MOD3_MASK;
46
47 uint32_t Keyboard::Control = GDK_CONTROL_MASK;
48 uint32_t Keyboard::Shift = GDK_SHIFT_MASK;
49 uint32_t Keyboard::Alt = GDK_MOD1_MASK;
50 uint32_t Keyboard::Meta = GDK_MOD2_MASK;
51
52 Keyboard* Keyboard::_the_keyboard = 0;
53
54 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
55
56 GdkModifierType Keyboard::RelevantModifierKeyMask = 
57                                GdkModifierType (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_MOD3_MASK);
58
59
60 Keyboard::Keyboard ()
61 {
62         if (_the_keyboard == 0) {
63                 _the_keyboard = this;
64         }
65
66         collecting_prefix = false;
67
68         get_modifier_masks ();
69
70         snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
71
72         XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
73         set_state (*node);
74 }
75
76 Keyboard::~Keyboard ()
77 {
78         gtk_key_snooper_remove (snooper_id);
79         delete [] modifier_masks;
80 }
81
82 XMLNode& 
83 Keyboard::get_state (void)
84 {
85         XMLNode* node = new XMLNode ("Keyboard");
86         char buf[32];
87
88         snprintf (buf, sizeof (buf), "%d", edit_but);
89         node->add_property ("edit-button", buf);
90         snprintf (buf, sizeof (buf), "%d", edit_mod);
91         node->add_property ("edit-modifier", buf);
92         snprintf (buf, sizeof (buf), "%d", delete_but);
93         node->add_property ("delete-button", buf);
94         snprintf (buf, sizeof (buf), "%d", delete_mod);
95         node->add_property ("delete-modifier", buf);
96         snprintf (buf, sizeof (buf), "%d", snap_mod);
97         node->add_property ("snap-modifier", buf);
98
99         return *node;
100 }
101
102 int 
103 Keyboard::set_state (const XMLNode& node)
104 {
105         const XMLProperty* prop;
106
107         if ((prop = node.property ("edit-button")) != 0) {
108                 sscanf (prop->value().c_str(), "%d", &edit_but);
109         } 
110
111         if ((prop = node.property ("edit-modifier")) != 0) {
112                 sscanf (prop->value().c_str(), "%d", &edit_mod);
113         } 
114
115         if ((prop = node.property ("delete-button")) != 0) {
116                 sscanf (prop->value().c_str(), "%d", &delete_but);
117         } 
118
119         if ((prop = node.property ("delete-modifier")) != 0) {
120                 sscanf (prop->value().c_str(), "%d", &delete_mod);
121         } 
122
123         if ((prop = node.property ("snap-modifier")) != 0) {
124                 sscanf (prop->value().c_str(), "%d", &snap_mod);
125         } 
126
127         return 0;
128 }
129
130 gint
131 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
132 {
133         return ((Keyboard *) data)->snooper (widget, event);
134 }
135
136 gint
137 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
138 {
139         uint32_t keyval;
140
141 #if KBD_DEBUG
142         if (debug_keyboard) {
143                 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type 
144                      << endl;
145         }
146 #endif
147
148         if (event->keyval == GDK_Shift_R) {
149                 keyval = GDK_Shift_L;
150
151         } else  if (event->keyval == GDK_Control_R) {
152                 keyval = GDK_Control_L;
153
154         } else {
155                 keyval = event->keyval;
156         }
157                 
158         if (event->type == GDK_KEY_PRESS) {
159                 bool was_prefix = false;
160
161                 if (collecting_prefix) {
162                         switch (keyval) {
163                         case GDK_0:
164                                 current_prefix += '0';
165                                 was_prefix = true;
166                                 break;
167                         case GDK_1:
168                                 current_prefix += '1';
169                                 was_prefix = true;
170                                 break;
171                         case GDK_2:
172                                 current_prefix += '2';
173                                 was_prefix = true;
174                                 break;
175                         case GDK_3:
176                                 current_prefix += '3';
177                                 was_prefix = true;
178                                 break;
179                         case GDK_4:
180                                 current_prefix += '4';
181                                 was_prefix = true;
182                                 break;
183                         case GDK_5:
184                                 current_prefix += '5';
185                                 was_prefix = true;
186                                 break;
187                         case GDK_6:
188                                 current_prefix += '6';
189                                 was_prefix = true;
190                                 break;
191                         case GDK_7:
192                                 current_prefix += '7';
193                                 was_prefix = true;
194                                 break;
195                         case GDK_8:
196                                 current_prefix += '8';
197                                 was_prefix = true;
198                                 break;
199                         case GDK_9:
200                                 current_prefix += '9';
201                                 was_prefix = true;
202                                 break;
203                         case GDK_period:
204                                 current_prefix += '.';
205                                 was_prefix = true;
206                                 break;
207                         default:
208                                 was_prefix = false;
209                                 collecting_prefix = false;
210                                 break;
211                         }
212                 }
213
214                 if (find (state.begin(), state.end(), keyval) == state.end()) {
215                         state.push_back (keyval);
216                         sort (state.begin(), state.end());
217                 }
218
219         } else if (event->type == GDK_KEY_RELEASE) {
220
221                 State::iterator i;
222                 
223                 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
224                         state.erase (i);
225                         sort (state.begin(), state.end());
226                 } 
227
228         }
229
230         return false;
231 }
232
233 bool
234 Keyboard::key_is_down (uint32_t keyval)
235 {
236         return find (state.begin(), state.end(), keyval) != state.end();
237 }
238
239 Keyboard::State
240 Keyboard::translate_key_name (const string& name)
241
242 {
243         string::size_type i;
244         string::size_type len;
245         bool at_end;
246         string::size_type hyphen;
247         string keyname;
248         string whatevers_left;
249         State result;
250         guint keycode;
251         
252         i = 0;
253         len = name.length();
254         at_end = (len == 0);
255
256         while (!at_end) {
257
258                 whatevers_left = name.substr (i);
259
260                 if ((hyphen = whatevers_left.find_first_of ('-')) == string::npos) {
261                         
262                         /* no hyphen, so use the whole thing */
263                         
264                         keyname = whatevers_left;
265                         at_end = true;
266
267                 } else {
268
269                         /* There is a hyphen. */
270                         
271                         if (hyphen == 0 && whatevers_left.length() == 1) {
272                                 /* its the first and only character */
273                         
274                                 keyname = "-";
275                                 at_end = true;
276
277                         } else {
278
279                                 /* use the text before the hypen */
280                                 
281                                 keyname = whatevers_left.substr (0, hyphen);
282                                 
283                                 if (hyphen == len - 1) {
284                                         at_end = true;
285                                 } else {
286                                         i += hyphen + 1;
287                                         at_end = (i >= len);
288                                 }
289                         }
290                 }
291                 
292                 if (keyname.length() == 1 && isupper (keyname[0])) {
293                         result.push_back (GDK_Shift_L);
294                 }
295                 
296                 if ((keycode = gdk_keyval_from_name(get_real_keyname (keyname).c_str())) == GDK_VoidSymbol) {
297                         error << string_compose(_("KeyboardTarget: keyname \"%1\" is unknown."), keyname) << endmsg;
298                         result.clear();
299                         return result;
300                 }
301                 
302                 result.push_back (keycode);
303         }
304
305         sort (result.begin(), result.end());
306
307         return result;
308 }
309
310 string
311 Keyboard::get_real_keyname (const string& name)
312 {
313
314         if (name == "Control" || name == "Ctrl") {
315                 return "Control_L";
316         } 
317         if (name == "Meta" || name == "MetaL") {
318                 return "Meta_L";
319         } 
320         if (name == "MetaR") {
321                 return "Meta_R";
322         } 
323         if (name == "Alt" || name == "AltL") {
324                 return "Alt_L";
325         } 
326         if (name == "AltR") {
327                 return "Alt_R";
328         } 
329         if (name == "Shift") {
330                 return "Shift_L";
331         }
332         if (name == "Shift_R") {
333                 return "Shift_L";
334         }
335         if (name == " ") {
336                 return "space";
337         }
338         if (name == "!") {
339                 return "exclam";
340         }
341         if (name == "\"") {
342                 return "quotedbl";
343         }
344         if (name == "#") {
345                 return "numbersign";
346         }
347         if (name == "$") {
348                 return "dollar";
349         }
350         if (name == "%") {
351                 return "percent";
352         }
353         if (name == "&") {
354                 return "ampersand";
355         }
356         if (name == "'") {
357                 return "apostrophe";
358         }
359         if (name == "'") {
360                 return "quoteright";
361         }
362         if (name == "(") {
363                 return "parenleft";
364         }
365         if (name == ")") {
366                 return "parenright";
367         }
368         if (name == "*") {
369                 return "asterisk";
370         }
371         if (name == "+") {
372                 return "plus";
373         }
374         if (name == ",") {
375                 return "comma";
376         }
377         if (name == "-") {
378                 return "minus";
379         }
380         if (name == ".") {
381                 return "period";
382         }
383         if (name == "/") {
384                 return "slash";
385         }
386         if (name == ":") {
387                 return "colon";
388         }
389         if (name == ";") {
390                 return "semicolon";
391         }
392         if (name == "<") {
393                 return "less";
394         }
395         if (name == "=") {
396                 return "equal";
397         }
398         if (name == ">") {
399                 return "greater";
400         }
401         if (name == "?") {
402                 return "question";
403         }
404         if (name == "@") {
405                 return "at";
406         }
407         if (name == "[") {
408                 return "bracketleft";
409         }
410         if (name == "\\") {
411                 return "backslash";
412         }
413         if (name == "]") {
414                 return "bracketright";
415         }
416         if (name == "^") {
417                 return "asciicircum";
418         }
419         if (name == "_") {
420                 return "underscore";
421         }
422         if (name == "`") {
423                 return "grave";
424         }
425         if (name == "`") {
426                 return "quoteleft";
427         }
428         if (name == "{") {
429                 return "braceleft";
430         }
431         if (name == "|") {
432                 return "bar";
433         }
434         if (name == "}") {
435                 return "braceright";
436         }
437         if (name == "~") {
438                 return "asciitilde";
439         }
440
441         return name;
442 }
443
444 int
445 Keyboard::get_prefix (float& val, bool& was_floating)
446 {
447         if (current_prefix.length()) {
448                 if (current_prefix.find ('.') != string::npos) {
449                         was_floating = true;
450                 } else {
451                         was_floating = false;
452                 }
453                 if (sscanf (current_prefix.c_str(), "%f", &val) == 1) {
454                         return 0;
455                 }
456                 current_prefix = "";
457         }
458         return -1;
459 }
460
461 void
462 Keyboard::start_prefix ()
463 {
464         collecting_prefix = true;
465         current_prefix = "";
466 }
467
468 void
469 Keyboard::clear_modifier_state ()
470 {
471         modifier_mask = 0;
472 }
473
474 void
475 Keyboard::check_modifier_state ()
476 {
477         char keys[32];
478         int i, j;
479
480         clear_modifier_state ();
481         XQueryKeymap (GDK_DISPLAY(), keys);
482
483         for (i = 0; i < 32; ++i) {
484                 for (j = 0; j < 8; ++j) {
485
486                         if (keys[i] & (1<<j)) {
487                                 modifier_mask |= modifier_masks[(i*8)+j];
488                         }
489                 }
490         }
491 }
492
493 void
494 Keyboard::check_meta_numlock (char keycode, guint mod, string modname)
495 {
496         guint alternate_meta_mod;
497         string alternate_meta_modname;
498
499         if (mod == Meta) {
500                 
501                 guint keysym = XKeycodeToKeysym  (GDK_DISPLAY(), keycode, 0);
502                 
503                 if (keysym == GDK_Num_Lock) {
504
505                         switch (mod) {
506                         case GDK_MOD2_MASK:
507                                 alternate_meta_mod = GDK_MOD3_MASK;
508                                 alternate_meta_modname = "Mod3";
509                                 break;
510                         case GDK_MOD3_MASK:
511                                 alternate_meta_mod = GDK_MOD2_MASK;
512                                 alternate_meta_modname = "Mod2";
513                                 break;
514                         case GDK_MOD4_MASK:
515                                 alternate_meta_mod = GDK_MOD2_MASK;
516                                 alternate_meta_modname = "Mod2";
517                                 break;
518                         case GDK_MOD5_MASK:
519                                 alternate_meta_mod = GDK_MOD2_MASK;
520                                 alternate_meta_modname = "Mod2";
521                                 break;
522                         default:
523                                 error << string_compose (_("Your system is completely broken - NumLock uses \"%1\""
524                                                     "as its modifier. This is madness - see the man page "
525                                                     "for xmodmap to find out how to fix this."),
526                                                   modname)
527                                       << endmsg;
528                                 return;
529                         }
530
531                         warning << string_compose (_("Your system generates \"%1\" when the NumLock key "
532                                               "is pressed. This can cause problems when editing "
533                                               "so Ardour will use %2 to mean Meta rather than %1"),
534                                             modname, alternate_meta_modname)
535                                 << endmsg;
536
537                         set_meta_modifier (alternate_meta_mod);
538                 }
539         }
540 }
541
542 void
543 Keyboard::get_modifier_masks ()
544 {
545         XModifierKeymap *modifiers;
546         KeyCode *keycode;
547         int i;
548         int bound;
549
550         XDisplayKeycodes (GDK_DISPLAY(), &min_keycode, &max_keycode);
551
552         /* This function builds a lookup table to provide rapid answers to
553            the question: what, if any, modmask, is associated with a given
554            keycode ?
555         */
556         
557         modifiers = XGetModifierMapping (GDK_DISPLAY());
558         
559         modifier_masks = new int32_t [max_keycode+1];
560         
561         keycode = modifiers->modifiermap;
562
563         for (i = 0; i < modifiers->max_keypermod; ++i) { /* shift */
564                 if (*keycode) {
565                         modifier_masks[*keycode] = GDK_SHIFT_MASK;
566                         // cerr << "Shift = " << XKeysymToString (XKeycodeToKeysym  (GDK_DISPLAY(), *keycode, 0)) << endl;
567                 }
568                 keycode++;
569         }
570     
571         for (i = 0; i < modifiers->max_keypermod; ++i) keycode++; /* skip lock */
572     
573         for (i = 0; i < modifiers->max_keypermod; ++i) { /* control */
574                 if (*keycode) {
575                         modifier_masks[*keycode] = GDK_CONTROL_MASK;
576                         // cerr << "Control = " << XKeysymToString (XKeycodeToKeysym  (GDK_DISPLAY(), *keycode, 0)) << endl;
577                 }
578                 keycode++;
579         }
580
581         bound = 0;
582         for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 1 */
583                 if (*keycode) {
584                         modifier_masks[*keycode] = GDK_MOD1_MASK;
585                         // cerr << "Mod1 = " << XKeysymToString (XKeycodeToKeysym  (GDK_DISPLAY(), *keycode, 0)) << endl;
586                         bound++;
587                 }
588                 keycode++;
589         }
590 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
591         if (bound > 1) {
592                 warning << string_compose (_("You have %1 keys bound to \"mod1\""), bound) << endmsg;
593         }
594 #endif
595         bound = 0;
596         for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod2 */
597                 if (*keycode) {
598                         modifier_masks[*keycode] = GDK_MOD2_MASK;
599                         check_meta_numlock (*keycode, GDK_MOD2_MASK, "Mod2");
600                         //cerr << "Mod2 = " << std::hex << (int) *keycode << std::dec << " = " << XKeysymToString (XKeycodeToKeysym  (GDK_DISPLAY(), *keycode, 0)) << endl;
601                         bound++;
602                 }
603                 keycode++; 
604         }
605 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
606         if (bound > 1) {
607                 warning << string_compose (_("You have %1 keys bound to \"mod2\""), bound) << endmsg;
608         }
609 #endif
610         bound = 0;
611         for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod3 */
612                 if (*keycode) {
613                         modifier_masks[*keycode] = GDK_MOD3_MASK;
614                         check_meta_numlock (*keycode, GDK_MOD3_MASK, "Mod3");
615                         // cerr << "Mod3 = " << XKeysymToString (XKeycodeToKeysym  (GDK_DISPLAY(), *keycode, 0)) << endl;
616                         bound++;
617                 }
618                 keycode++; 
619         }
620 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
621         if (bound > 1) {
622                 warning << string_compose (_("You have %1 keys bound to \"mod3\""), bound) << endmsg;
623         }
624 #endif
625         bound = 0;
626         for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 4 */
627                 if (*keycode) {
628                         modifier_masks[*keycode] = GDK_MOD4_MASK;
629                         check_meta_numlock (*keycode, GDK_MOD4_MASK, "Mod4");
630                         // cerr << "Mod4 = " << XKeysymToString (XKeycodeToKeysym  (GDK_DISPLAY(), *keycode, 0)) << endl;
631                         bound++;
632                 }
633                 keycode++;
634         }
635 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
636         if (bound > 1) {
637                 warning << string_compose (_("You have %1 keys bound to \"mod4\""), bound) << endmsg;
638         }
639 #endif
640         bound = 0;
641         for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 5 */
642                 if (*keycode) {
643                         modifier_masks[*keycode] = GDK_MOD5_MASK;
644                         check_meta_numlock (*keycode, GDK_MOD5_MASK, "Mod5");
645                         // cerr << "Mod5 = " << XKeysymToString (XKeycodeToKeysym  (GDK_DISPLAY(), *keycode, 0)) << endl;
646                         bound++;
647                 }
648                 keycode++;
649         }
650 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
651         if (bound > 1) {
652                 warning << string_compose (_("You have %1 keys bound to \"mod5\""), bound) << endmsg;
653         }
654 #endif
655
656         XFreeModifiermap (modifiers);
657 }
658
659 bool
660 Keyboard::enter_window (GdkEventCrossing *ev)
661 {
662         switch (ev->detail) {
663         case GDK_NOTIFY_INFERIOR:
664                 break;
665
666         case GDK_NOTIFY_VIRTUAL:
667                 /* fallthru */
668
669         default:
670                 check_modifier_state ();
671         }
672
673         return FALSE;
674 }
675
676 bool
677 Keyboard::leave_window (GdkEventCrossing *ev)
678 {
679         switch (ev->detail) {
680         case GDK_NOTIFY_INFERIOR:
681                 if (debug_keyboard) {
682                         cerr << "INFERIOR crossing ... out\n";
683                 }
684                 break;
685
686         case GDK_NOTIFY_VIRTUAL:
687                 if (debug_keyboard) {
688                         cerr << "VIRTUAL crossing ... out\n";
689                 }
690                 /* fallthru */
691
692         default:
693                 if (debug_keyboard) {
694                         cerr << "REAL CROSSING ... out\n";
695                         cerr << "clearing current target\n";
696                 }
697                 state.clear ();
698                 clear_modifier_state ();
699         }
700         return FALSE;
701
702 }
703
704 void
705 Keyboard::set_edit_button (guint but)
706 {
707         edit_but = but;
708 }
709
710 void
711 Keyboard::set_edit_modifier (guint mod)
712 {
713         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
714         edit_mod = mod;
715         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
716 }
717
718 void
719 Keyboard::set_delete_button (guint but)
720 {
721         delete_but = but;
722 }
723
724 void
725 Keyboard::set_delete_modifier (guint mod)
726 {
727         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
728         delete_mod = mod;
729         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
730 }
731
732 void
733 Keyboard::set_meta_modifier (guint mod)
734 {
735         /* we don't include Meta in the RelevantModifierKeyMask because its not used
736            in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
737            set at all is that X Window has no convention for the keyboard modifier
738            that Meta should use. Some Linux distributions bind NumLock to Mod2, which
739            is our default Meta modifier, and this causes severe problems.
740         */
741         Meta = mod;
742 }
743
744 void
745 Keyboard::set_snap_modifier (guint mod)
746 {
747         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
748         snap_mod = mod;
749         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
750 }
751
752 bool
753 Keyboard::is_edit_event (GdkEventButton *ev)
754 {
755         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
756                 (ev->button == Keyboard::edit_button()) && 
757                 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
758 }
759
760 bool
761 Keyboard::is_delete_event (GdkEventButton *ev)
762 {
763         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
764                 (ev->button == Keyboard::delete_button()) && 
765                 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
766 }
767
768 bool
769 Keyboard::is_context_menu_event (GdkEventButton *ev)
770 {
771         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
772                 (ev->button == 3) && 
773                 ((ev->state & RelevantModifierKeyMask) == 0);
774 }
775
776 bool 
777 Keyboard::no_modifiers_active (guint state)
778 {
779         return (state & RelevantModifierKeyMask) == 0;
780 }
781
782 bool
783 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
784 {
785         return (state & mask) == (guint) mask;
786 }
787
788 bool
789 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
790 {
791         return (state & RelevantModifierKeyMask) == (guint) mask;
792 }
793