cc94dc155f08bb82ee1943344fc683d00e6b2273
[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
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 KBD_DEBUG
169         if (debug_keyboard) {
170                 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type 
171                      << endl;
172         }
173 #endif
174
175         if (event->keyval == GDK_Shift_R) {
176                 keyval = GDK_Shift_L;
177
178         } else  if (event->keyval == GDK_Control_R) {
179                 keyval = GDK_Control_L;
180
181         } else {
182                 keyval = event->keyval;
183         }
184                 
185         if (event->type == GDK_KEY_PRESS) {
186
187                 if (find (state.begin(), state.end(), keyval) == state.end()) {
188                         state.push_back (keyval);
189                         sort (state.begin(), state.end());
190                 }
191
192         } else if (event->type == GDK_KEY_RELEASE) {
193
194                 State::iterator i;
195                 
196                 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
197                         state.erase (i);
198                         sort (state.begin(), state.end());
199                 } 
200
201         }
202
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 ();
206                         current_window = 0;
207                 }
208         }
209
210         return false;
211 }
212
213 bool
214 Keyboard::key_is_down (uint32_t keyval)
215 {
216         return find (state.begin(), state.end(), keyval) != state.end();
217 }
218
219 bool
220 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
221 {
222         current_window = win;
223         return false;
224 }
225
226 bool
227 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
228 {
229         switch (ev->detail) {
230         case GDK_NOTIFY_INFERIOR:
231                 if (debug_keyboard) {
232                         cerr << "INFERIOR crossing ... out\n";
233                 }
234                 break;
235
236         case GDK_NOTIFY_VIRTUAL:
237                 if (debug_keyboard) {
238                         cerr << "VIRTUAL crossing ... out\n";
239                 }
240                 /* fallthru */
241
242         default:
243                 if (debug_keyboard) {
244                         cerr << "REAL CROSSING ... out\n";
245                         cerr << "clearing current target\n";
246                 }
247                 state.clear ();
248                 current_window = 0;
249         }
250
251         return false;
252 }
253
254 void
255 Keyboard::set_edit_button (guint but)
256 {
257         edit_but = but;
258 }
259
260 void
261 Keyboard::set_edit_modifier (guint mod)
262 {
263         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
264         edit_mod = mod;
265         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
266 }
267
268 void
269 Keyboard::set_delete_button (guint but)
270 {
271         delete_but = but;
272 }
273
274 void
275 Keyboard::set_delete_modifier (guint mod)
276 {
277         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
278         delete_mod = mod;
279         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
280 }
281
282 void
283 Keyboard::set_meta_modifier (guint mod)
284 {
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.
290         */
291         Meta = mod;
292 }
293
294 void
295 Keyboard::set_snap_modifier (guint mod)
296 {
297         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
298         snap_mod = mod;
299         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
300 }
301
302 bool
303 Keyboard::is_edit_event (GdkEventButton *ev)
304 {
305
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());
309 }
310
311 bool
312 Keyboard::is_delete_event (GdkEventButton *ev)
313 {
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());
317 }
318
319 bool
320 Keyboard::is_context_menu_event (GdkEventButton *ev)
321 {
322         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
323                 (ev->button == 3) && 
324                 ((ev->state & RelevantModifierKeyMask) == 0);
325 }
326
327 bool 
328 Keyboard::no_modifiers_active (guint state)
329 {
330         return (state & RelevantModifierKeyMask) == 0;
331 }
332
333 bool
334 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
335 {
336         return (state & mask) == (guint) mask;
337 }
338
339 bool
340 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
341 {
342         return (state & RelevantModifierKeyMask) == (guint) mask;
343 }
344
345 Selection::Operation
346 Keyboard::selection_type (guint state)
347 {
348         /* note that there is no modifier for "Add" */
349
350         if (modifier_state_equals (state, Shift)) {
351                 return Selection::Extend;
352         } else if (modifier_state_equals (state, Control)) {
353                 return Selection::Toggle;
354         } else {
355                 return Selection::Set;
356         }
357 }