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;
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());
202 if (event->type == GDK_KEY_RELEASE && event->keyval == GDK_w && modifier_state_equals (event->state, Control)) {
203 if (current_window) {
204 current_window->hide ();
213 Keyboard::key_is_down (uint32_t keyval)
215 return find (state.begin(), state.end(), keyval) != state.end();
219 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
221 current_window = win;
226 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
228 switch (ev->detail) {
229 case GDK_NOTIFY_INFERIOR:
230 if (debug_keyboard) {
231 cerr << "INFERIOR crossing ... out\n";
235 case GDK_NOTIFY_VIRTUAL:
236 if (debug_keyboard) {
237 cerr << "VIRTUAL crossing ... out\n";
242 if (debug_keyboard) {
243 cerr << "REAL CROSSING ... out\n";
244 cerr << "clearing current target\n";
254 Keyboard::set_edit_button (guint but)
260 Keyboard::set_edit_modifier (guint mod)
262 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
264 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
268 Keyboard::set_delete_button (guint but)
274 Keyboard::set_delete_modifier (guint mod)
276 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
278 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
282 Keyboard::set_meta_modifier (guint mod)
284 /* we don't include Meta in the RelevantModifierKeyMask because its not used
285 in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
286 set at all is that X Window has no convention for the keyboard modifier
287 that Meta should use. Some Linux distributions bind NumLock to Mod2, which
288 is our default Meta modifier, and this causes severe problems.
294 Keyboard::set_snap_modifier (guint mod)
296 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
298 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
302 Keyboard::is_edit_event (GdkEventButton *ev)
305 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
306 (ev->button == Keyboard::edit_button()) &&
307 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
311 Keyboard::is_delete_event (GdkEventButton *ev)
313 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
314 (ev->button == Keyboard::delete_button()) &&
315 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
319 Keyboard::is_context_menu_event (GdkEventButton *ev)
321 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
323 ((ev->state & RelevantModifierKeyMask) == 0);
327 Keyboard::no_modifiers_active (guint state)
329 return (state & RelevantModifierKeyMask) == 0;
333 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
335 return (state & mask) == (guint) mask;
339 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
341 return (state & RelevantModifierKeyMask) == (guint) mask;
345 Keyboard::selection_type (guint state)
347 /* note that there is no modifier for "Add" */
349 if (modifier_state_equals (state, Shift)) {
350 return Selection::Extend;
351 } else if (modifier_state_equals (state, Control)) {
352 return Selection::Toggle;
354 return Selection::Set;