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.
20 #include "ardour_ui.h"
27 #include <gdk/gdkkeysyms.h>
28 #include <pbd/error.h>
31 #include "gui_thread.h"
38 bool debug_keyboard = false;
40 guint Keyboard::edit_but = 3;
41 guint Keyboard::edit_mod = GDK_CONTROL_MASK;
42 guint Keyboard::delete_but = 3;
43 guint Keyboard::delete_mod = GDK_SHIFT_MASK;
44 guint Keyboard::snap_mod = GDK_MOD3_MASK;
46 uint32_t Keyboard::Control = GDK_CONTROL_MASK;
47 uint32_t Keyboard::Shift = GDK_SHIFT_MASK;
48 uint32_t Keyboard::Alt = GDK_MOD1_MASK;
49 uint32_t Keyboard::Meta;
51 Keyboard* Keyboard::_the_keyboard = 0;
53 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
55 GdkModifierType Keyboard::RelevantModifierKeyMask;
57 bool Keyboard::_some_magic_widget_has_focus = false;
60 Keyboard::magic_widget_grab_focus ()
62 _some_magic_widget_has_focus = true;
66 Keyboard::magic_widget_drop_focus ()
68 _some_magic_widget_has_focus = false;
72 Keyboard::some_magic_widget_has_focus ()
74 return _some_magic_widget_has_focus;
79 if (_the_keyboard == 0) {
83 RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
87 uint32_t possible_meta[] = { GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK, 0};
90 for (i = 0; possible_meta[i]; ++i) {
91 if (!(RelevantModifierKeyMask & possible_meta[i])) {
95 Meta = possible_meta[i];
97 snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
99 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
103 Keyboard::~Keyboard ()
105 gtk_key_snooper_remove (snooper_id);
109 Keyboard::get_state (void)
111 XMLNode* node = new XMLNode ("Keyboard");
114 snprintf (buf, sizeof (buf), "%d", edit_but);
115 node->add_property ("edit-button", buf);
116 snprintf (buf, sizeof (buf), "%d", edit_mod);
117 node->add_property ("edit-modifier", buf);
118 snprintf (buf, sizeof (buf), "%d", delete_but);
119 node->add_property ("delete-button", buf);
120 snprintf (buf, sizeof (buf), "%d", delete_mod);
121 node->add_property ("delete-modifier", buf);
122 snprintf (buf, sizeof (buf), "%d", snap_mod);
123 node->add_property ("snap-modifier", buf);
129 Keyboard::set_state (const XMLNode& node)
131 const XMLProperty* prop;
133 if ((prop = node.property ("edit-button")) != 0) {
134 sscanf (prop->value().c_str(), "%d", &edit_but);
137 if ((prop = node.property ("edit-modifier")) != 0) {
138 sscanf (prop->value().c_str(), "%d", &edit_mod);
141 if ((prop = node.property ("delete-button")) != 0) {
142 sscanf (prop->value().c_str(), "%d", &delete_but);
145 if ((prop = node.property ("delete-modifier")) != 0) {
146 sscanf (prop->value().c_str(), "%d", &delete_mod);
149 if ((prop = node.property ("snap-modifier")) != 0) {
150 sscanf (prop->value().c_str(), "%d", &snap_mod);
157 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
159 return ((Keyboard *) data)->snooper (widget, event);
163 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
168 if (debug_keyboard) {
169 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
174 if (event->keyval == GDK_Shift_R) {
175 keyval = GDK_Shift_L;
177 } else if (event->keyval == GDK_Control_R) {
178 keyval = GDK_Control_L;
181 keyval = event->keyval;
184 if (event->type == GDK_KEY_PRESS) {
186 if (find (state.begin(), state.end(), keyval) == state.end()) {
187 state.push_back (keyval);
188 sort (state.begin(), state.end());
191 } else if (event->type == GDK_KEY_RELEASE) {
195 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
197 sort (state.begin(), state.end());
206 Keyboard::key_is_down (uint32_t keyval)
208 return find (state.begin(), state.end(), keyval) != state.end();
212 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
218 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
220 switch (ev->detail) {
221 case GDK_NOTIFY_INFERIOR:
222 if (debug_keyboard) {
223 cerr << "INFERIOR crossing ... out\n";
227 case GDK_NOTIFY_VIRTUAL:
228 if (debug_keyboard) {
229 cerr << "VIRTUAL crossing ... out\n";
234 if (debug_keyboard) {
235 cerr << "REAL CROSSING ... out\n";
236 cerr << "clearing current target\n";
245 Keyboard::set_edit_button (guint but)
251 Keyboard::set_edit_modifier (guint mod)
253 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
255 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
259 Keyboard::set_delete_button (guint but)
265 Keyboard::set_delete_modifier (guint mod)
267 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
269 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
273 Keyboard::set_meta_modifier (guint mod)
275 /* we don't include Meta in the RelevantModifierKeyMask because its not used
276 in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
277 set at all is that X Window has no convention for the keyboard modifier
278 that Meta should use. Some Linux distributions bind NumLock to Mod2, which
279 is our default Meta modifier, and this causes severe problems.
285 Keyboard::set_snap_modifier (guint mod)
287 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
289 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
293 Keyboard::is_edit_event (GdkEventButton *ev)
296 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
297 (ev->button == Keyboard::edit_button()) &&
298 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
302 Keyboard::is_delete_event (GdkEventButton *ev)
304 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
305 (ev->button == Keyboard::delete_button()) &&
306 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
310 Keyboard::is_context_menu_event (GdkEventButton *ev)
312 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
314 ((ev->state & RelevantModifierKeyMask) == 0);
318 Keyboard::no_modifiers_active (guint state)
320 return (state & RelevantModifierKeyMask) == 0;
324 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
326 return (state & mask) == (guint) mask;
330 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
332 return (state & RelevantModifierKeyMask) == (guint) mask;
336 Keyboard::selection_type (guint state)
338 /* note that there is no modifier for "Add" */
340 if (modifier_state_equals (state, Shift)) {
341 return Selection::Extend;
342 } else if (modifier_state_equals (state, Control)) {
343 return Selection::Toggle;
345 return Selection::Set;