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;
60 if (_the_keyboard == 0) {
64 RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
68 uint32_t possible_meta[] = { GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK, 0};
71 for (i = 0; possible_meta[i]; ++i) {
72 if (!(RelevantModifierKeyMask & possible_meta[i])) {
76 Meta = possible_meta[i];
78 snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
80 XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
84 Keyboard::~Keyboard ()
86 gtk_key_snooper_remove (snooper_id);
90 Keyboard::get_state (void)
92 XMLNode* node = new XMLNode ("Keyboard");
95 snprintf (buf, sizeof (buf), "%d", edit_but);
96 node->add_property ("edit-button", buf);
97 snprintf (buf, sizeof (buf), "%d", edit_mod);
98 node->add_property ("edit-modifier", buf);
99 snprintf (buf, sizeof (buf), "%d", delete_but);
100 node->add_property ("delete-button", buf);
101 snprintf (buf, sizeof (buf), "%d", delete_mod);
102 node->add_property ("delete-modifier", buf);
103 snprintf (buf, sizeof (buf), "%d", snap_mod);
104 node->add_property ("snap-modifier", buf);
110 Keyboard::set_state (const XMLNode& node)
112 const XMLProperty* prop;
114 if ((prop = node.property ("edit-button")) != 0) {
115 sscanf (prop->value().c_str(), "%d", &edit_but);
118 if ((prop = node.property ("edit-modifier")) != 0) {
119 sscanf (prop->value().c_str(), "%d", &edit_mod);
122 if ((prop = node.property ("delete-button")) != 0) {
123 sscanf (prop->value().c_str(), "%d", &delete_but);
126 if ((prop = node.property ("delete-modifier")) != 0) {
127 sscanf (prop->value().c_str(), "%d", &delete_mod);
130 if ((prop = node.property ("snap-modifier")) != 0) {
131 sscanf (prop->value().c_str(), "%d", &snap_mod);
138 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
140 return ((Keyboard *) data)->snooper (widget, event);
144 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
149 if (debug_keyboard) {
150 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type
155 if (event->keyval == GDK_Shift_R) {
156 keyval = GDK_Shift_L;
158 } else if (event->keyval == GDK_Control_R) {
159 keyval = GDK_Control_L;
162 keyval = event->keyval;
165 if (event->type == GDK_KEY_PRESS) {
167 if (find (state.begin(), state.end(), keyval) == state.end()) {
168 state.push_back (keyval);
169 sort (state.begin(), state.end());
172 } else if (event->type == GDK_KEY_RELEASE) {
176 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
178 sort (state.begin(), state.end());
187 Keyboard::key_is_down (uint32_t keyval)
189 return find (state.begin(), state.end(), keyval) != state.end();
193 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
199 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
201 switch (ev->detail) {
202 case GDK_NOTIFY_INFERIOR:
203 if (debug_keyboard) {
204 cerr << "INFERIOR crossing ... out\n";
208 case GDK_NOTIFY_VIRTUAL:
209 if (debug_keyboard) {
210 cerr << "VIRTUAL crossing ... out\n";
215 if (debug_keyboard) {
216 cerr << "REAL CROSSING ... out\n";
217 cerr << "clearing current target\n";
226 Keyboard::set_edit_button (guint but)
232 Keyboard::set_edit_modifier (guint mod)
234 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
236 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
240 Keyboard::set_delete_button (guint but)
246 Keyboard::set_delete_modifier (guint mod)
248 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
250 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
254 Keyboard::set_meta_modifier (guint mod)
256 /* we don't include Meta in the RelevantModifierKeyMask because its not used
257 in the same way as snap_mod, delete_mod etc. the only reason we allow it to be
258 set at all is that X Window has no convention for the keyboard modifier
259 that Meta should use. Some Linux distributions bind NumLock to Mod2, which
260 is our default Meta modifier, and this causes severe problems.
266 Keyboard::set_snap_modifier (guint mod)
268 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
270 RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
274 Keyboard::is_edit_event (GdkEventButton *ev)
277 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
278 (ev->button == Keyboard::edit_button()) &&
279 ((ev->state & RelevantModifierKeyMask) == Keyboard::edit_modifier());
283 Keyboard::is_delete_event (GdkEventButton *ev)
285 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
286 (ev->button == Keyboard::delete_button()) &&
287 ((ev->state & RelevantModifierKeyMask) == Keyboard::delete_modifier());
291 Keyboard::is_context_menu_event (GdkEventButton *ev)
293 return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) &&
295 ((ev->state & RelevantModifierKeyMask) == 0);
299 Keyboard::no_modifiers_active (guint state)
301 return (state & RelevantModifierKeyMask) == 0;
305 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
307 return (state & mask) == (guint) mask;
311 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
313 return (state & RelevantModifierKeyMask) == (guint) mask;
317 Keyboard::selection_type (guint state)
319 /* note that there is no modifier for "Add" */
321 if (modifier_state_equals (state, Shift)) {
322 return Selection::Extend;
323 } else if (modifier_state_equals (state, Control)) {
324 return Selection::Toggle;
326 return Selection::Set;