MESCLUN: new SAE-specific bindings file; parametized binding files; fix handling...
[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 0
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
60 void
61 Keyboard::magic_widget_grab_focus () 
62 {
63         _some_magic_widget_has_focus = true;
64 }
65
66 void
67 Keyboard::magic_widget_drop_focus ()
68 {
69         _some_magic_widget_has_focus = false;
70 }
71
72 bool
73 Keyboard::some_magic_widget_has_focus ()
74 {
75         return _some_magic_widget_has_focus;
76 }
77
78 Keyboard::Keyboard ()
79 {
80         if (_the_keyboard == 0) {
81                 _the_keyboard = this;
82         }
83
84         RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
85
86         /* figure out Meta */
87
88         uint32_t possible_meta[] = { GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK, 0};
89         int i;
90
91         for (i = 0; possible_meta[i]; ++i) {
92                 if (!(RelevantModifierKeyMask & possible_meta[i])) {
93                         break;
94                 }
95         }
96         Meta = possible_meta[i];
97
98         snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
99
100         XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
101         set_state (*node);
102 }
103
104 Keyboard::~Keyboard ()
105 {
106         gtk_key_snooper_remove (snooper_id);
107 }
108
109 XMLNode& 
110 Keyboard::get_state (void)
111 {
112         XMLNode* node = new XMLNode ("Keyboard");
113         char buf[32];
114
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);
125
126         return *node;
127 }
128
129 int 
130 Keyboard::set_state (const XMLNode& node)
131 {
132         const XMLProperty* prop;
133
134         if ((prop = node.property ("edit-button")) != 0) {
135                 sscanf (prop->value().c_str(), "%d", &edit_but);
136         } 
137
138         if ((prop = node.property ("edit-modifier")) != 0) {
139                 sscanf (prop->value().c_str(), "%d", &edit_mod);
140         } 
141
142         if ((prop = node.property ("delete-button")) != 0) {
143                 sscanf (prop->value().c_str(), "%d", &delete_but);
144         } 
145
146         if ((prop = node.property ("delete-modifier")) != 0) {
147                 sscanf (prop->value().c_str(), "%d", &delete_mod);
148         } 
149
150         if ((prop = node.property ("snap-modifier")) != 0) {
151                 sscanf (prop->value().c_str(), "%d", &snap_mod);
152         } 
153
154         return 0;
155 }
156
157 gint
158 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
159 {
160         return ((Keyboard *) data)->snooper (widget, event);
161 }
162
163 gint
164 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
165 {
166         uint32_t keyval;
167
168 #if 0
169         cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type 
170              << " state " << std::hex << event->state << std::dec
171              << endl;
172 #endif
173
174 #if KBD_DEBUG
175         if (debug_keyboard) {
176                 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type 
177                      << endl;
178         }
179 #endif
180
181         if (event->keyval == GDK_Shift_R) {
182                 keyval = GDK_Shift_L;
183
184         } else  if (event->keyval == GDK_Control_R) {
185                 keyval = GDK_Control_L;
186
187         } else {
188                 keyval = event->keyval;
189         }
190                 
191         if (event->type == GDK_KEY_PRESS) {
192
193                 if (find (state.begin(), state.end(), keyval) == state.end()) {
194                         state.push_back (keyval);
195                         sort (state.begin(), state.end());
196                 }
197
198         } else if (event->type == GDK_KEY_RELEASE) {
199
200                 State::iterator i;
201                 
202                 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
203                         state.erase (i);
204                         sort (state.begin(), state.end());
205                 } 
206
207         }
208
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 ();
212                         current_window = 0;
213                 }
214         }
215
216         return false;
217 }
218
219 bool
220 Keyboard::key_is_down (uint32_t keyval)
221 {
222         return find (state.begin(), state.end(), keyval) != state.end();
223 }
224
225 bool
226 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
227 {
228         current_window = win;
229         return false;
230 }
231
232 bool
233 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
234 {
235         switch (ev->detail) {
236         case GDK_NOTIFY_INFERIOR:
237                 if (debug_keyboard) {
238                         cerr << "INFERIOR crossing ... out\n";
239                 }
240                 break;
241
242         case GDK_NOTIFY_VIRTUAL:
243                 if (debug_keyboard) {
244                         cerr << "VIRTUAL crossing ... out\n";
245                 }
246                 /* fallthru */
247
248         default:
249                 if (debug_keyboard) {
250                         cerr << "REAL CROSSING ... out\n";
251                         cerr << "clearing current target\n";
252                 }
253                 state.clear ();
254                 current_window = 0;
255         }
256
257         return false;
258 }
259
260 void
261 Keyboard::set_edit_button (guint but)
262 {
263         edit_but = but;
264 }
265
266 void
267 Keyboard::set_edit_modifier (guint mod)
268 {
269         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
270         edit_mod = mod;
271         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
272 }
273
274 void
275 Keyboard::set_delete_button (guint but)
276 {
277         delete_but = but;
278 }
279
280 void
281 Keyboard::set_delete_modifier (guint mod)
282 {
283         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
284         delete_mod = mod;
285         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
286 }
287
288 void
289 Keyboard::set_meta_modifier (guint mod)
290 {
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.
296         */
297         Meta = mod;
298 }
299
300 void
301 Keyboard::set_snap_modifier (guint mod)
302 {
303         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
304         snap_mod = mod;
305         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
306 }
307
308 bool
309 Keyboard::is_edit_event (GdkEventButton *ev)
310 {
311
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());
315 }
316
317 bool
318 Keyboard::is_delete_event (GdkEventButton *ev)
319 {
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());
323 }
324
325 bool
326 Keyboard::is_context_menu_event (GdkEventButton *ev)
327 {
328         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
329                 (ev->button == 3) && 
330                 ((ev->state & RelevantModifierKeyMask) == 0);
331 }
332
333 bool 
334 Keyboard::no_modifiers_active (guint state)
335 {
336         return (state & RelevantModifierKeyMask) == 0;
337 }
338
339 bool
340 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
341 {
342         return (state & mask) == (guint) mask;
343 }
344
345 bool
346 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
347 {
348         return (state & RelevantModifierKeyMask) == (guint) mask;
349 }
350
351 Selection::Operation
352 Keyboard::selection_type (guint state)
353 {
354         /* note that there is no modifier for "Add" */
355
356         if (modifier_state_equals (state, Shift)) {
357                 return Selection::Extend;
358         } else if (modifier_state_equals (state, Control)) {
359                 return Selection::Toggle;
360         } else {
361                 return Selection::Set;
362         }
363 }