e6eaffefcbfd0e1fc6807410802991bd9a027418
[ardour.git] / gtk2_ardour / keyboard.cc
1 /*
2     Copyright (C) 2001 Paul Davis 
3
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.
8
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.
13
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.
17
18 */
19
20 #include "ardour_ui.h"
21
22 #include <algorithm>
23 #include <fstream>
24
25 #include <ctype.h>
26
27 #include <gdk/gdkkeysyms.h>
28 #include <pbd/error.h>
29
30 #include "keyboard.h"
31 #include "gui_thread.h"
32
33 #include "i18n.h"
34
35 using namespace PBD;
36
37 #define KBD_DEBUG 1
38 bool debug_keyboard = false;
39
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;
45
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;
50
51 Keyboard*    Keyboard::_the_keyboard = 0;
52 Gtk::Window* Keyboard::current_window = 0;
53 bool         Keyboard::_some_magic_widget_has_focus = false;
54
55 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
56
57 GdkModifierType Keyboard::RelevantModifierKeyMask;
58
59 void
60 Keyboard::magic_widget_grab_focus () 
61 {
62         _some_magic_widget_has_focus = true;
63 }
64
65 void
66 Keyboard::magic_widget_drop_focus ()
67 {
68         _some_magic_widget_has_focus = false;
69 }
70
71 bool
72 Keyboard::some_magic_widget_has_focus ()
73 {
74         return _some_magic_widget_has_focus;
75 }
76
77 Keyboard::Keyboard ()
78 {
79         if (_the_keyboard == 0) {
80                 _the_keyboard = this;
81         }
82
83         RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
84
85         /* figure out Meta */
86
87         uint32_t possible_meta[] = { GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK, 0};
88         int i;
89
90         for (i = 0; possible_meta[i]; ++i) {
91                 if (!(RelevantModifierKeyMask & possible_meta[i])) {
92                         break;
93                 }
94         }
95         Meta = possible_meta[i];
96
97         snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
98
99         XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
100         set_state (*node);
101 }
102
103 Keyboard::~Keyboard ()
104 {
105         gtk_key_snooper_remove (snooper_id);
106 }
107
108 XMLNode& 
109 Keyboard::get_state (void)
110 {
111         XMLNode* node = new XMLNode ("Keyboard");
112         char buf[32];
113
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);
124
125         return *node;
126 }
127
128 int 
129 Keyboard::set_state (const XMLNode& node)
130 {
131         const XMLProperty* prop;
132
133         if ((prop = node.property ("edit-button")) != 0) {
134                 sscanf (prop->value().c_str(), "%d", &edit_but);
135         } 
136
137         if ((prop = node.property ("edit-modifier")) != 0) {
138                 sscanf (prop->value().c_str(), "%d", &edit_mod);
139         } 
140
141         if ((prop = node.property ("delete-button")) != 0) {
142                 sscanf (prop->value().c_str(), "%d", &delete_but);
143         } 
144
145         if ((prop = node.property ("delete-modifier")) != 0) {
146                 sscanf (prop->value().c_str(), "%d", &delete_mod);
147         } 
148
149         if ((prop = node.property ("snap-modifier")) != 0) {
150                 sscanf (prop->value().c_str(), "%d", &snap_mod);
151         } 
152
153         return 0;
154 }
155
156 gint
157 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
158 {
159         return ((Keyboard *) data)->snooper (widget, event);
160 }
161
162 gint
163 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
164 {
165         uint32_t keyval;
166
167 #if KBD_DEBUG
168         if (debug_keyboard) {
169                 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type 
170                      << endl;
171         }
172 #endif
173
174         if (event->keyval == GDK_Shift_R) {
175                 keyval = GDK_Shift_L;
176
177         } else  if (event->keyval == GDK_Control_R) {
178                 keyval = GDK_Control_L;
179
180         } else {
181                 keyval = event->keyval;
182         }
183                 
184         if (event->type == GDK_KEY_PRESS) {
185
186                 if (find (state.begin(), state.end(), keyval) == state.end()) {
187                         state.push_back (keyval);
188                         sort (state.begin(), state.end());
189                 }
190
191         } else if (event->type == GDK_KEY_RELEASE) {
192
193                 State::iterator i;
194                 
195                 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
196                         state.erase (i);
197                         sort (state.begin(), state.end());
198                 } 
199
200         }
201
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 ();
205                         current_window = 0;
206                 }
207         }
208
209         return false;
210 }
211
212 bool
213 Keyboard::key_is_down (uint32_t keyval)
214 {
215         return find (state.begin(), state.end(), keyval) != state.end();
216 }
217
218 bool
219 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
220 {
221         current_window = win;
222         return false;
223 }
224
225 bool
226 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
227 {
228         switch (ev->detail) {
229         case GDK_NOTIFY_INFERIOR:
230                 if (debug_keyboard) {
231                         cerr << "INFERIOR crossing ... out\n";
232                 }
233                 break;
234
235         case GDK_NOTIFY_VIRTUAL:
236                 if (debug_keyboard) {
237                         cerr << "VIRTUAL crossing ... out\n";
238                 }
239                 /* fallthru */
240
241         default:
242                 if (debug_keyboard) {
243                         cerr << "REAL CROSSING ... out\n";
244                         cerr << "clearing current target\n";
245                 }
246                 state.clear ();
247                 current_window = 0;
248         }
249
250         return false;
251 }
252
253 void
254 Keyboard::set_edit_button (guint but)
255 {
256         edit_but = but;
257 }
258
259 void
260 Keyboard::set_edit_modifier (guint mod)
261 {
262         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
263         edit_mod = mod;
264         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
265 }
266
267 void
268 Keyboard::set_delete_button (guint but)
269 {
270         delete_but = but;
271 }
272
273 void
274 Keyboard::set_delete_modifier (guint mod)
275 {
276         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
277         delete_mod = mod;
278         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
279 }
280
281 void
282 Keyboard::set_meta_modifier (guint mod)
283 {
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.
289         */
290         Meta = mod;
291 }
292
293 void
294 Keyboard::set_snap_modifier (guint mod)
295 {
296         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
297         snap_mod = mod;
298         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
299 }
300
301 bool
302 Keyboard::is_edit_event (GdkEventButton *ev)
303 {
304
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());
308 }
309
310 bool
311 Keyboard::is_delete_event (GdkEventButton *ev)
312 {
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());
316 }
317
318 bool
319 Keyboard::is_context_menu_event (GdkEventButton *ev)
320 {
321         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
322                 (ev->button == 3) && 
323                 ((ev->state & RelevantModifierKeyMask) == 0);
324 }
325
326 bool 
327 Keyboard::no_modifiers_active (guint state)
328 {
329         return (state & RelevantModifierKeyMask) == 0;
330 }
331
332 bool
333 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
334 {
335         return (state & mask) == (guint) mask;
336 }
337
338 bool
339 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
340 {
341         return (state & RelevantModifierKeyMask) == (guint) mask;
342 }
343
344 Selection::Operation
345 Keyboard::selection_type (guint state)
346 {
347         /* note that there is no modifier for "Add" */
348
349         if (modifier_state_equals (state, Shift)) {
350                 return Selection::Extend;
351         } else if (modifier_state_equals (state, Control)) {
352                 return Selection::Toggle;
353         } else {
354                 return Selection::Set;
355         }
356 }