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;
52 Gtk::Window* Keyboard::current_window = 0;
53 bool Keyboard::_some_magic_widget_has_focus = false;
55 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
57 GdkModifierType Keyboard::RelevantModifierKeyMask;
61 Keyboard::magic_widget_grab_focus ()
63 _some_magic_widget_has_focus = true;
67 Keyboard::magic_widget_drop_focus ()
69 _some_magic_widget_has_focus = false;
73 Keyboard::some_magic_widget_has_focus ()
75 return _some_magic_widget_has_focus;
80 if (_the_keyboard == 0) {
84 RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
88 uint32_t possible_meta[] = { GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK, 0};
91 for (i = 0; possible_meta[i]; ++i) {
92 if (!(RelevantModifierKeyMask & possible_meta[i])) {
96 Meta = possible_meta[i];
98 snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
100 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
104 Keyboard::~Keyboard ()
106 gtk_key_snooper_remove (snooper_id);
110 Keyboard::get_state (void)
112 XMLNode* node = new XMLNode ("Keyboard");
115 snprintf (buf, sizeof (buf), "%d", edit_but);
116 node->add_property ("edit-button", buf);
117 snprintf (buf, sizeof (buf), "%d", edit_mod);
118 node->add_property ("edit-modifier", buf);
119 snprintf (buf, sizeof (buf), "%d", delete_but);
120 node->add_property ("delete-button", buf);
121 snprintf (buf, sizeof (buf), "%d", delete_mod);
122 node->add_property ("delete-modifier", buf);
123 snprintf (buf, sizeof (buf), "%d", snap_mod);
124 node->add_property ("snap-modifier", buf);
130 Keyboard::set_state (const XMLNode& node)
132 const XMLProperty* prop;
134 if ((prop = node.property ("edit-button")) != 0) {
135 sscanf (prop->value().c_str(), "%d", &edit_but);
138 if ((prop = node.property ("edit-modifier")) != 0) {
139 sscanf (prop->value().c_str(), "%d", &edit_mod);
142 if ((prop = node.property ("delete-button")) != 0) {
143 sscanf (prop->value().c_str(), "%d", &delete_but);
146 if ((prop = node.property ("delete-modifier")) != 0) {
147 sscanf (prop->value().c_str(), "%d", &delete_mod);
150 if ((prop = node.property ("snap-modifier")) != 0) {
151 sscanf (prop->value().c_str(), "%d", &snap_mod);
158 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
160 return ((Keyboard *) data)->snooper (widget, event);
164 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
169 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
170 << " state " << std::hex << event->state << std::dec
175 if (debug_keyboard) {
176 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
181 if (event->keyval == GDK_Shift_R) {
182 keyval = GDK_Shift_L;
184 } else if (event->keyval == GDK_Control_R) {
185 keyval = GDK_Control_L;
188 keyval = event->keyval;
191 if (event->type == GDK_KEY_PRESS) {
193 if (find (state.begin(), state.end(), keyval) == state.end()) {
194 state.push_back (keyval);
195 sort (state.begin(), state.end());
198 } else if (event->type == GDK_KEY_RELEASE) {
202 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
204 sort (state.begin(), state.end());
209 if (event->type == GDK_KEY_RELEASE && event->keyval == GDK_w && modifier_state_equals (event->state, Control)) {
210 if (current_window) {
211 current_window->hide ();
220 Keyboard::key_is_down (uint32_t keyval)
222 return find (state.begin(), state.end(), keyval) != state.end();
226 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
228 current_window = win;
233 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
235 switch (ev->detail) {
236 case GDK_NOTIFY_INFERIOR:
237 if (debug_keyboard) {
238 cerr << "INFERIOR crossing ... out\n";
242 case GDK_NOTIFY_VIRTUAL:
243 if (debug_keyboard) {
244 cerr << "VIRTUAL crossing ... out\n";
249 if (debug_keyboard) {
250 cerr << "REAL CROSSING ... out\n";
251 cerr << "clearing current target\n";
261 Keyboard::set_edit_button (guint but)
267 Keyboard::set_edit_modifier (guint mod)
269 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
271 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
275 Keyboard::set_delete_button (guint but)
281 Keyboard::set_delete_modifier (guint mod)
283 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
285 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
289 Keyboard::set_meta_modifier (guint mod)
291 /* we don't include Meta in the RelevantModifierKeyMask because its not used
292 in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
293 set at all is that X Window has no convention for the keyboard modifier
294 that Meta should use. Some Linux distributions bind NumLock to Mod2, which
295 is our default Meta modifier, and this causes severe problems.
301 Keyboard::set_snap_modifier (guint mod)
303 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
305 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
309 Keyboard::is_edit_event (GdkEventButton *ev)
312 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
313 (ev->button == Keyboard::edit_button()) &&
314 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
318 Keyboard::is_delete_event (GdkEventButton *ev)
320 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
321 (ev->button == Keyboard::delete_button()) &&
322 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
326 Keyboard::is_context_menu_event (GdkEventButton *ev)
328 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
330 ((ev->state & RelevantModifierKeyMask) == 0);
334 Keyboard::no_modifiers_active (guint state)
336 return (state & RelevantModifierKeyMask) == 0;
340 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
342 return (state & mask) == (guint) mask;
346 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
348 return (state & RelevantModifierKeyMask) == (guint) mask;
352 Keyboard::selection_type (guint state)
354 /* note that there is no modifier for "Add" */
356 if (modifier_state_equals (state, Shift)) {
357 return Selection::Extend;
358 } else if (modifier_state_equals (state, Control)) {
359 return Selection::Toggle;
361 return Selection::Set;