2 Copyright (C) 2001 Paul Davis
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.
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.
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.
21 #include "ardour_ui.h"
28 #include <X11/keysymdef.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <pbd/error.h>
34 #include "gui_thread.h"
41 bool debug_keyboard = false;
43 guint Keyboard::edit_but = 3;
44 guint Keyboard::edit_mod = GDK_CONTROL_MASK;
45 guint Keyboard::delete_but = 3;
46 guint Keyboard::delete_mod = GDK_SHIFT_MASK;
47 guint Keyboard::snap_mod = GDK_MOD3_MASK;
49 uint32_t Keyboard::Control = GDK_CONTROL_MASK;
50 uint32_t Keyboard::Shift = GDK_SHIFT_MASK;
51 uint32_t Keyboard::Alt = GDK_MOD1_MASK;
52 uint32_t Keyboard::Meta = GDK_MOD2_MASK;
54 Keyboard* Keyboard::_the_keyboard = 0;
56 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
58 GdkModifierType Keyboard::RelevantModifierKeyMask =
59 GdkModifierType (GDK_SHIFT_MASK|GDK_CONTROL_MASK|GDK_MOD1_MASK|GDK_MOD3_MASK);
64 if (_the_keyboard == 0) {
68 collecting_prefix = false;
70 get_modifier_masks ();
72 snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
74 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
78 Keyboard::~Keyboard ()
80 gtk_key_snooper_remove (snooper_id);
81 delete [] modifier_masks;
85 Keyboard::get_state (void)
87 XMLNode* node = new XMLNode ("Keyboard");
90 snprintf (buf, sizeof (buf), "%d", edit_but);
91 node->add_property ("edit-button", buf);
92 snprintf (buf, sizeof (buf), "%d", edit_mod);
93 node->add_property ("edit-modifier", buf);
94 snprintf (buf, sizeof (buf), "%d", delete_but);
95 node->add_property ("delete-button", buf);
96 snprintf (buf, sizeof (buf), "%d", delete_mod);
97 node->add_property ("delete-modifier", buf);
98 snprintf (buf, sizeof (buf), "%d", snap_mod);
99 node->add_property ("snap-modifier", buf);
105 Keyboard::set_state (const XMLNode& node)
107 const XMLProperty* prop;
109 if ((prop = node.property ("edit-button")) != 0) {
110 sscanf (prop->value().c_str(), "%d", &edit_but);
113 if ((prop = node.property ("edit-modifier")) != 0) {
114 sscanf (prop->value().c_str(), "%d", &edit_mod);
117 if ((prop = node.property ("delete-button")) != 0) {
118 sscanf (prop->value().c_str(), "%d", &delete_but);
121 if ((prop = node.property ("delete-modifier")) != 0) {
122 sscanf (prop->value().c_str(), "%d", &delete_mod);
125 if ((prop = node.property ("snap-modifier")) != 0) {
126 sscanf (prop->value().c_str(), "%d", &snap_mod);
133 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
135 return ((Keyboard *) data)->snooper (widget, event);
139 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
144 if (debug_keyboard) {
145 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
150 if (event->keyval == GDK_Shift_R) {
151 keyval = GDK_Shift_L;
153 } else if (event->keyval == GDK_Control_R) {
154 keyval = GDK_Control_L;
157 keyval = event->keyval;
160 if (event->type == GDK_KEY_PRESS) {
161 bool was_prefix = false;
163 if (collecting_prefix) {
166 current_prefix += '0';
170 current_prefix += '1';
174 current_prefix += '2';
178 current_prefix += '3';
182 current_prefix += '4';
186 current_prefix += '5';
190 current_prefix += '6';
194 current_prefix += '7';
198 current_prefix += '8';
202 current_prefix += '9';
206 current_prefix += '.';
211 collecting_prefix = false;
216 if (find (state.begin(), state.end(), keyval) == state.end()) {
217 state.push_back (keyval);
218 sort (state.begin(), state.end());
221 } else if (event->type == GDK_KEY_RELEASE) {
225 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
227 sort (state.begin(), state.end());
236 Keyboard::key_is_down (uint32_t keyval)
238 return find (state.begin(), state.end(), keyval) != state.end();
242 Keyboard::translate_key_name (const string& name)
246 string::size_type len;
248 string::size_type hyphen;
250 string whatevers_left;
260 whatevers_left = name.substr (i);
262 if ((hyphen = whatevers_left.find_first_of ('-')) == string::npos) {
264 /* no hyphen, so use the whole thing */
266 keyname = whatevers_left;
271 /* There is a hyphen. */
273 if (hyphen == 0 && whatevers_left.length() == 1) {
274 /* its the first and only character */
281 /* use the text before the hypen */
283 keyname = whatevers_left.substr (0, hyphen);
285 if (hyphen == len - 1) {
294 if (keyname.length() == 1 && isupper (keyname[0])) {
295 result.push_back (GDK_Shift_L);
298 if ((keycode = gdk_keyval_from_name(get_real_keyname (keyname).c_str())) == GDK_VoidSymbol) {
299 error << string_compose(_("KeyboardTarget: keyname \"%1\" is unknown."), keyname) << endmsg;
304 result.push_back (keycode);
307 sort (result.begin(), result.end());
313 Keyboard::get_real_keyname (const string& name)
316 if (name == "Control" || name == "Ctrl") {
319 if (name == "Meta" || name == "MetaL") {
322 if (name == "MetaR") {
325 if (name == "Alt" || name == "AltL") {
328 if (name == "AltR") {
331 if (name == "Shift") {
334 if (name == "Shift_R") {
410 return "bracketleft";
416 return "bracketright";
419 return "asciicircum";
447 Keyboard::get_prefix (float& val, bool& was_floating)
449 if (current_prefix.length()) {
450 if (current_prefix.find ('.') != string::npos) {
453 was_floating = false;
455 if (sscanf (current_prefix.c_str(), "%f", &val) == 1) {
464 Keyboard::start_prefix ()
466 collecting_prefix = true;
471 Keyboard::clear_modifier_state ()
477 Keyboard::check_modifier_state ()
482 clear_modifier_state ();
483 XQueryKeymap (GDK_DISPLAY(), keys);
485 for (i = 0; i < 32; ++i) {
486 for (j = 0; j < 8; ++j) {
488 if (keys[i] & (1<<j)) {
489 modifier_mask |= modifier_masks[(i*8)+j];
496 Keyboard::check_meta_numlock (char keycode, guint mod, string modname)
498 guint alternate_meta_mod;
499 string alternate_meta_modname;
503 guint keysym = XKeycodeToKeysym (GDK_DISPLAY(), keycode, 0);
505 if (keysym == GDK_Num_Lock) {
509 alternate_meta_mod = GDK_MOD3_MASK;
510 alternate_meta_modname = "Mod3";
513 alternate_meta_mod = GDK_MOD2_MASK;
514 alternate_meta_modname = "Mod2";
517 alternate_meta_mod = GDK_MOD2_MASK;
518 alternate_meta_modname = "Mod2";
521 alternate_meta_mod = GDK_MOD2_MASK;
522 alternate_meta_modname = "Mod2";
525 error << string_compose (_("Your system is completely broken - NumLock uses \"%1\""
526 "as its modifier. This is madness - see the man page "
527 "for xmodmap to find out how to fix this."),
533 warning << string_compose (_("Your system generates \"%1\" when the NumLock key "
534 "is pressed. This can cause problems when editing "
535 "so Ardour will use %2 to mean Meta rather than %1"),
536 modname, alternate_meta_modname)
539 set_meta_modifier (alternate_meta_mod);
545 Keyboard::get_modifier_masks ()
547 XModifierKeymap *modifiers;
552 XDisplayKeycodes (GDK_DISPLAY(), &min_keycode, &max_keycode);
554 /* This function builds a lookup table to provide rapid answers to
555 the question: what, if any, modmask, is associated with a given
559 modifiers = XGetModifierMapping (GDK_DISPLAY());
561 modifier_masks = new int32_t [max_keycode+1];
563 keycode = modifiers->modifiermap;
565 for (i = 0; i < modifiers->max_keypermod; ++i) { /* shift */
567 modifier_masks[*keycode] = GDK_SHIFT_MASK;
568 // cerr << "Shift = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
573 for (i = 0; i < modifiers->max_keypermod; ++i) keycode++; /* skip lock */
575 for (i = 0; i < modifiers->max_keypermod; ++i) { /* control */
577 modifier_masks[*keycode] = GDK_CONTROL_MASK;
578 // cerr << "Control = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
584 for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 1 */
586 modifier_masks[*keycode] = GDK_MOD1_MASK;
587 // cerr << "Mod1 = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
592 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
594 warning << string_compose (_("You have %1 keys bound to \"mod1\""), bound) << endmsg;
598 for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod2 */
600 modifier_masks[*keycode] = GDK_MOD2_MASK;
601 check_meta_numlock (*keycode, GDK_MOD2_MASK, "Mod2");
602 //cerr << "Mod2 = " << std::hex << (int) *keycode << std::dec << " = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
607 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
609 warning << string_compose (_("You have %1 keys bound to \"mod2\""), bound) << endmsg;
613 for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod3 */
615 modifier_masks[*keycode] = GDK_MOD3_MASK;
616 check_meta_numlock (*keycode, GDK_MOD3_MASK, "Mod3");
617 // cerr << "Mod3 = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
622 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
624 warning << string_compose (_("You have %1 keys bound to \"mod3\""), bound) << endmsg;
628 for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 4 */
630 modifier_masks[*keycode] = GDK_MOD4_MASK;
631 check_meta_numlock (*keycode, GDK_MOD4_MASK, "Mod4");
632 // cerr << "Mod4 = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
637 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
639 warning << string_compose (_("You have %1 keys bound to \"mod4\""), bound) << endmsg;
643 for (i = 0; i < modifiers->max_keypermod; ++i) { /* mod 5 */
645 modifier_masks[*keycode] = GDK_MOD5_MASK;
646 check_meta_numlock (*keycode, GDK_MOD5_MASK, "Mod5");
647 // cerr << "Mod5 = " << XKeysymToString (XKeycodeToKeysym (GDK_DISPLAY(), *keycode, 0)) << endl;
652 #ifdef WARN_ABOUT_DUPLICATE_MODIFIERS
654 warning << string_compose (_("You have %1 keys bound to \"mod5\""), bound) << endmsg;
658 XFreeModifiermap (modifiers);
662 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
664 switch (ev->detail) {
665 case GDK_NOTIFY_INFERIOR:
668 case GDK_NOTIFY_VIRTUAL:
672 check_modifier_state ();
679 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
681 switch (ev->detail) {
682 case GDK_NOTIFY_INFERIOR:
683 if (debug_keyboard) {
684 cerr << "INFERIOR crossing ... out\n";
688 case GDK_NOTIFY_VIRTUAL:
689 if (debug_keyboard) {
690 cerr << "VIRTUAL crossing ... out\n";
695 if (debug_keyboard) {
696 cerr << "REAL CROSSING ... out\n";
697 cerr << "clearing current target\n";
700 clear_modifier_state ();
707 Keyboard::set_edit_button (guint but)
713 Keyboard::set_edit_modifier (guint mod)
715 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
717 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
721 Keyboard::set_delete_button (guint but)
727 Keyboard::set_delete_modifier (guint mod)
729 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
731 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
735 Keyboard::set_meta_modifier (guint mod)
737 /* we don't include Meta in the RelevantModifierKeyMask because its not used
738 in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
739 set at all is that X Window has no convention for the keyboard modifier
740 that Meta should use. Some Linux distributions bind NumLock to Mod2, which
741 is our default Meta modifier, and this causes severe problems.
747 Keyboard::set_snap_modifier (guint mod)
749 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
751 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
755 Keyboard::is_edit_event (GdkEventButton *ev)
757 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
758 (ev->button == Keyboard::edit_button()) &&
759 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
763 Keyboard::is_delete_event (GdkEventButton *ev)
765 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
766 (ev->button == Keyboard::delete_button()) &&
767 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
771 Keyboard::is_context_menu_event (GdkEventButton *ev)
773 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
775 ((ev->state & RelevantModifierKeyMask) == 0);
779 Keyboard::no_modifiers_active (guint state)
781 return (state & RelevantModifierKeyMask) == 0;
785 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
787 return (state & mask) == (guint) mask;
791 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
793 return (state & RelevantModifierKeyMask) == (guint) mask;
797 Keyboard::selection_type (guint state)
799 /* note that there is no modifier for "Add" */
801 if (modifier_state_equals (state, Shift)) {
802 return Selection::Extend;
803 } else if (modifier_state_equals (state, Control)) {
804 return Selection::Toggle;
806 return Selection::Set;