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];
79 snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
81 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
85 Keyboard::~Keyboard ()
87 gtk_key_snooper_remove (snooper_id);
91 Keyboard::get_state (void)
93 XMLNode* node = new XMLNode ("Keyboard");
96 snprintf (buf, sizeof (buf), "%d", edit_but);
97 node->add_property ("edit-button", buf);
98 snprintf (buf, sizeof (buf), "%d", edit_mod);
99 node->add_property ("edit-modifier", buf);
100 snprintf (buf, sizeof (buf), "%d", delete_but);
101 node->add_property ("delete-button", buf);
102 snprintf (buf, sizeof (buf), "%d", delete_mod);
103 node->add_property ("delete-modifier", buf);
104 snprintf (buf, sizeof (buf), "%d", snap_mod);
105 node->add_property ("snap-modifier", buf);
111 Keyboard::set_state (const XMLNode& node)
113 const XMLProperty* prop;
115 if ((prop = node.property ("edit-button")) != 0) {
116 sscanf (prop->value().c_str(), "%d", &edit_but);
119 if ((prop = node.property ("edit-modifier")) != 0) {
120 sscanf (prop->value().c_str(), "%d", &edit_mod);
123 if ((prop = node.property ("delete-button")) != 0) {
124 sscanf (prop->value().c_str(), "%d", &delete_but);
127 if ((prop = node.property ("delete-modifier")) != 0) {
128 sscanf (prop->value().c_str(), "%d", &delete_mod);
131 if ((prop = node.property ("snap-modifier")) != 0) {
132 sscanf (prop->value().c_str(), "%d", &snap_mod);
139 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
141 return ((Keyboard *) data)->snooper (widget, event);
145 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
150 if (debug_keyboard) {
151 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
156 if (event->keyval == GDK_Shift_R) {
157 keyval = GDK_Shift_L;
159 } else if (event->keyval == GDK_Control_R) {
160 keyval = GDK_Control_L;
163 keyval = event->keyval;
166 if (event->type == GDK_KEY_PRESS) {
168 if (find (state.begin(), state.end(), keyval) == state.end()) {
169 state.push_back (keyval);
170 sort (state.begin(), state.end());
173 } else if (event->type == GDK_KEY_RELEASE) {
177 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
179 sort (state.begin(), state.end());
188 Keyboard::key_is_down (uint32_t keyval)
190 return find (state.begin(), state.end(), keyval) != state.end();
194 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
200 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
202 switch (ev->detail) {
203 case GDK_NOTIFY_INFERIOR:
204 if (debug_keyboard) {
205 cerr << "INFERIOR crossing ... out\n";
209 case GDK_NOTIFY_VIRTUAL:
210 if (debug_keyboard) {
211 cerr << "VIRTUAL crossing ... out\n";
216 if (debug_keyboard) {
217 cerr << "REAL CROSSING ... out\n";
218 cerr << "clearing current target\n";
227 Keyboard::set_edit_button (guint but)
233 Keyboard::set_edit_modifier (guint mod)
235 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
237 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
241 Keyboard::set_delete_button (guint but)
247 Keyboard::set_delete_modifier (guint mod)
249 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
251 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
255 Keyboard::set_meta_modifier (guint mod)
257 /* we don't include Meta in the RelevantModifierKeyMask because its not used
258 in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
259 set at all is that X Window has no convention for the keyboard modifier
260 that Meta should use. Some Linux distributions bind NumLock to Mod2, which
261 is our default Meta modifier, and this causes severe problems.
267 Keyboard::set_snap_modifier (guint mod)
269 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
271 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
275 Keyboard::is_edit_event (GdkEventButton *ev)
278 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
279 (ev->button == Keyboard::edit_button()) &&
280 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
284 Keyboard::is_delete_event (GdkEventButton *ev)
286 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
287 (ev->button == Keyboard::delete_button()) &&
288 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
292 Keyboard::is_context_menu_event (GdkEventButton *ev)
294 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
296 ((ev->state & RelevantModifierKeyMask) == 0);
300 Keyboard::no_modifiers_active (guint state)
302 return (state & RelevantModifierKeyMask) == 0;
306 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
308 return (state & mask) == (guint) mask;
312 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
314 return (state & RelevantModifierKeyMask) == (guint) mask;
318 Keyboard::selection_type (guint state)
320 /* note that there is no modifier for "Add" */
322 if (modifier_state_equals (state, Shift)) {
323 return Selection::Extend;
324 } else if (modifier_state_equals (state, Control)) {
325 return Selection::Toggle;
327 return Selection::Set;