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 <gdk/gdkkeysyms.h>
29 #include <pbd/error.h>
32 #include "gui_thread.h"
39 bool debug_keyboard = false;
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;
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;
52 Keyboard* Keyboard::_the_keyboard = 0;
54 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
56 GdkModifierType Keyboard::RelevantModifierKeyMask;
61 if (_the_keyboard == 0) {
65 RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
69 uint32_t possible_meta[] = { GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK, 0};
72 for (i = 0; possible_meta[i]; ++i) {
73 if (!(RelevantModifierKeyMask & possible_meta[i])) {
77 Meta = possible_meta[i];
80 cerr << "Using " << possible_meta[i] << " for Meta\n";
85 snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
87 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
91 Keyboard::~Keyboard ()
93 gtk_key_snooper_remove (snooper_id);
97 Keyboard::get_state (void)
99 XMLNode* node = new XMLNode ("Keyboard");
102 snprintf (buf, sizeof (buf), "%d", edit_but);
103 node->add_property ("edit-button", buf);
104 snprintf (buf, sizeof (buf), "%d", edit_mod);
105 node->add_property ("edit-modifier", buf);
106 snprintf (buf, sizeof (buf), "%d", delete_but);
107 node->add_property ("delete-button", buf);
108 snprintf (buf, sizeof (buf), "%d", delete_mod);
109 node->add_property ("delete-modifier", buf);
110 snprintf (buf, sizeof (buf), "%d", snap_mod);
111 node->add_property ("snap-modifier", buf);
117 Keyboard::set_state (const XMLNode& node)
119 const XMLProperty* prop;
121 if ((prop = node.property ("edit-button")) != 0) {
122 sscanf (prop->value().c_str(), "%d", &edit_but);
125 if ((prop = node.property ("edit-modifier")) != 0) {
126 sscanf (prop->value().c_str(), "%d", &edit_mod);
129 if ((prop = node.property ("delete-button")) != 0) {
130 sscanf (prop->value().c_str(), "%d", &delete_but);
133 if ((prop = node.property ("delete-modifier")) != 0) {
134 sscanf (prop->value().c_str(), "%d", &delete_mod);
137 if ((prop = node.property ("snap-modifier")) != 0) {
138 sscanf (prop->value().c_str(), "%d", &snap_mod);
145 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
147 return ((Keyboard *) data)->snooper (widget, event);
151 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
156 if (debug_keyboard) {
157 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
162 if (event->keyval == GDK_Shift_R) {
163 keyval = GDK_Shift_L;
165 } else if (event->keyval == GDK_Control_R) {
166 keyval = GDK_Control_L;
169 keyval = event->keyval;
172 if (event->type == GDK_KEY_PRESS) {
174 if (find (state.begin(), state.end(), keyval) == state.end()) {
175 state.push_back (keyval);
176 sort (state.begin(), state.end());
179 } else if (event->type == GDK_KEY_RELEASE) {
183 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
185 sort (state.begin(), state.end());
194 Keyboard::key_is_down (uint32_t keyval)
196 return find (state.begin(), state.end(), keyval) != state.end();
200 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
206 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
208 switch (ev->detail) {
209 case GDK_NOTIFY_INFERIOR:
210 if (debug_keyboard) {
211 cerr << "INFERIOR crossing ... out\n";
215 case GDK_NOTIFY_VIRTUAL:
216 if (debug_keyboard) {
217 cerr << "VIRTUAL crossing ... out\n";
222 if (debug_keyboard) {
223 cerr << "REAL CROSSING ... out\n";
224 cerr << "clearing current target\n";
233 Keyboard::set_edit_button (guint but)
239 Keyboard::set_edit_modifier (guint mod)
241 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
243 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
247 Keyboard::set_delete_button (guint but)
253 Keyboard::set_delete_modifier (guint mod)
255 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
257 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
261 Keyboard::set_meta_modifier (guint mod)
263 /* we don't include Meta in the RelevantModifierKeyMask because its not used
264 in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
265 set at all is that X Window has no convention for the keyboard modifier
266 that Meta should use. Some Linux distributions bind NumLock to Mod2, which
267 is our default Meta modifier, and this causes severe problems.
273 Keyboard::set_snap_modifier (guint mod)
275 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
277 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
281 Keyboard::is_edit_event (GdkEventButton *ev)
284 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
285 (ev->button == Keyboard::edit_button()) &&
286 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
290 Keyboard::is_delete_event (GdkEventButton *ev)
292 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
293 (ev->button == Keyboard::delete_button()) &&
294 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
298 Keyboard::is_context_menu_event (GdkEventButton *ev)
300 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
302 ((ev->state & RelevantModifierKeyMask) == 0);
306 Keyboard::no_modifiers_active (guint state)
308 return (state & RelevantModifierKeyMask) == 0;
312 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
314 return (state & mask) == (guint) mask;
318 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
320 return (state & RelevantModifierKeyMask) == (guint) mask;
324 Keyboard::selection_type (guint state)
326 /* note that there is no modifier for "Add" */
328 if (modifier_state_equals (state, Shift)) {
329 return Selection::Extend;
330 } else if (modifier_state_equals (state, Control)) {
331 return Selection::Toggle;
333 return Selection::Set;