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 if (debug_keyboard) {
170 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
175 if (event->keyval == GDK_Shift_R) {
176 keyval = GDK_Shift_L;
178 } else if (event->keyval == GDK_Control_R) {
179 keyval = GDK_Control_L;
182 keyval = event->keyval;
185 if (event->type == GDK_KEY_PRESS) {
187 if (find (state.begin(), state.end(), keyval) == state.end()) {
188 state.push_back (keyval);
189 sort (state.begin(), state.end());
192 } else if (event->type == GDK_KEY_RELEASE) {
196 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
198 sort (state.begin(), state.end());
203 if (event->type == GDK_KEY_RELEASE && event->keyval == GDK_w && modifier_state_equals (event->state, Control)) {
204 if (current_window) {
205 current_window->hide ();
214 Keyboard::key_is_down (uint32_t keyval)
216 return find (state.begin(), state.end(), keyval) != state.end();
220 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
222 current_window = win;
227 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
229 switch (ev->detail) {
230 case GDK_NOTIFY_INFERIOR:
231 if (debug_keyboard) {
232 cerr << "INFERIOR crossing ... out\n";
236 case GDK_NOTIFY_VIRTUAL:
237 if (debug_keyboard) {
238 cerr << "VIRTUAL crossing ... out\n";
243 if (debug_keyboard) {
244 cerr << "REAL CROSSING ... out\n";
245 cerr << "clearing current target\n";
255 Keyboard::set_edit_button (guint but)
261 Keyboard::set_edit_modifier (guint mod)
263 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
265 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
269 Keyboard::set_delete_button (guint but)
275 Keyboard::set_delete_modifier (guint mod)
277 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
279 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
283 Keyboard::set_meta_modifier (guint mod)
285 /* we don't include Meta in the RelevantModifierKeyMask because its not used
286 in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
287 set at all is that X Window has no convention for the keyboard modifier
288 that Meta should use. Some Linux distributions bind NumLock to Mod2, which
289 is our default Meta modifier, and this causes severe problems.
295 Keyboard::set_snap_modifier (guint mod)
297 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
299 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
303 Keyboard::is_edit_event (GdkEventButton *ev)
306 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
307 (ev->button == Keyboard::edit_button()) &&
308 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
312 Keyboard::is_delete_event (GdkEventButton *ev)
314 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
315 (ev->button == Keyboard::delete_button()) &&
316 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
320 Keyboard::is_context_menu_event (GdkEventButton *ev)
322 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
324 ((ev->state & RelevantModifierKeyMask) == 0);
328 Keyboard::no_modifiers_active (guint state)
330 return (state & RelevantModifierKeyMask) == 0;
334 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
336 return (state & mask) == (guint) mask;
340 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
342 return (state & RelevantModifierKeyMask) == (guint) mask;
346 Keyboard::selection_type (guint state)
348 /* note that there is no modifier for "Add" */
350 if (modifier_state_equals (state, Shift)) {
351 return Selection::Extend;
352 } else if (modifier_state_equals (state, Control)) {
353 return Selection::Toggle;
355 return Selection::Set;