remove all lines to avoid recompiles after commits
[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
53 /* set this to initially contain the modifiers we care about, then track changes in ::set_edit_modifier() etc. */
54
55 GdkModifierType Keyboard::RelevantModifierKeyMask;
56
57
58 Keyboard::Keyboard ()
59 {
60         if (_the_keyboard == 0) {
61                 _the_keyboard = this;
62         }
63
64         RelevantModifierKeyMask = (GdkModifierType) gtk_accelerator_get_default_mod_mask ();
65
66         /* figure out Meta */
67
68         uint32_t possible_meta[] = { GDK_MOD2_MASK, GDK_MOD3_MASK, GDK_MOD4_MASK, GDK_MOD5_MASK, 0};
69         int i;
70
71         for (i = 0; possible_meta[i]; ++i) {
72                 if (!(RelevantModifierKeyMask & possible_meta[i])) {
73                         break;
74                 }
75         }
76         Meta = possible_meta[i];
77
78         snooper_id = gtk_key_snooper_install (_snooper, (gpointer) this);
79
80         XMLNode* node = ARDOUR_UI::instance()->keyboard_settings();
81         set_state (*node);
82 }
83
84 Keyboard::~Keyboard ()
85 {
86         gtk_key_snooper_remove (snooper_id);
87 }
88
89 XMLNode& 
90 Keyboard::get_state (void)
91 {
92         XMLNode* node = new XMLNode ("Keyboard");
93         char buf[32];
94
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);
105
106         return *node;
107 }
108
109 int 
110 Keyboard::set_state (const XMLNode& node)
111 {
112         const XMLProperty* prop;
113
114         if ((prop = node.property ("edit-button")) != 0) {
115                 sscanf (prop->value().c_str(), "%d", &edit_but);
116         } 
117
118         if ((prop = node.property ("edit-modifier")) != 0) {
119                 sscanf (prop->value().c_str(), "%d", &edit_mod);
120         } 
121
122         if ((prop = node.property ("delete-button")) != 0) {
123                 sscanf (prop->value().c_str(), "%d", &delete_but);
124         } 
125
126         if ((prop = node.property ("delete-modifier")) != 0) {
127                 sscanf (prop->value().c_str(), "%d", &delete_mod);
128         } 
129
130         if ((prop = node.property ("snap-modifier")) != 0) {
131                 sscanf (prop->value().c_str(), "%d", &snap_mod);
132         } 
133
134         return 0;
135 }
136
137 gint
138 Keyboard::_snooper (GtkWidget *widget, GdkEventKey *event, gpointer data)
139 {
140         return ((Keyboard *) data)->snooper (widget, event);
141 }
142
143 gint
144 Keyboard::snooper (GtkWidget *widget, GdkEventKey *event)
145 {
146         uint32_t keyval;
147
148 #if KBD_DEBUG
149         if (debug_keyboard) {
150                 cerr << "snoop widget " << widget << " key " << event->keyval << " type: " << event->type 
151                      << endl;
152         }
153 #endif
154
155         if (event->keyval == GDK_Shift_R) {
156                 keyval = GDK_Shift_L;
157
158         } else  if (event->keyval == GDK_Control_R) {
159                 keyval = GDK_Control_L;
160
161         } else {
162                 keyval = event->keyval;
163         }
164                 
165         if (event->type == GDK_KEY_PRESS) {
166
167                 if (find (state.begin(), state.end(), keyval) == state.end()) {
168                         state.push_back (keyval);
169                         sort (state.begin(), state.end());
170                 }
171
172         } else if (event->type == GDK_KEY_RELEASE) {
173
174                 State::iterator i;
175                 
176                 if ((i = find (state.begin(), state.end(), keyval)) != state.end()) {
177                         state.erase (i);
178                         sort (state.begin(), state.end());
179                 } 
180
181         }
182
183         return false;
184 }
185
186 bool
187 Keyboard::key_is_down (uint32_t keyval)
188 {
189         return find (state.begin(), state.end(), keyval) != state.end();
190 }
191
192 bool
193 Keyboard::enter_window (GdkEventCrossing *ev, Gtk::Window* win)
194 {
195         return false;
196 }
197
198 bool
199 Keyboard::leave_window (GdkEventCrossing *ev, Gtk::Window* win)
200 {
201         switch (ev->detail) {
202         case GDK_NOTIFY_INFERIOR:
203                 if (debug_keyboard) {
204                         cerr << "INFERIOR crossing ... out\n";
205                 }
206                 break;
207
208         case GDK_NOTIFY_VIRTUAL:
209                 if (debug_keyboard) {
210                         cerr << "VIRTUAL crossing ... out\n";
211                 }
212                 /* fallthru */
213
214         default:
215                 if (debug_keyboard) {
216                         cerr << "REAL CROSSING ... out\n";
217                         cerr << "clearing current target\n";
218                 }
219                 state.clear ();
220         }
221
222         return false;
223 }
224
225 void
226 Keyboard::set_edit_button (guint but)
227 {
228         edit_but = but;
229 }
230
231 void
232 Keyboard::set_edit_modifier (guint mod)
233 {
234         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~edit_mod);
235         edit_mod = mod;
236         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | edit_mod);
237 }
238
239 void
240 Keyboard::set_delete_button (guint but)
241 {
242         delete_but = but;
243 }
244
245 void
246 Keyboard::set_delete_modifier (guint mod)
247 {
248         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~delete_mod);
249         delete_mod = mod;
250         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | delete_mod);
251 }
252
253 void
254 Keyboard::set_meta_modifier (guint mod)
255 {
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.
261         */
262         Meta = mod;
263 }
264
265 void
266 Keyboard::set_snap_modifier (guint mod)
267 {
268         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask & ~snap_mod);
269         snap_mod = mod;
270         RelevantModifierKeyMask = GdkModifierType (RelevantModifierKeyMask | snap_mod);
271 }
272
273 bool
274 Keyboard::is_edit_event (GdkEventButton *ev)
275 {
276
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());
280 }
281
282 bool
283 Keyboard::is_delete_event (GdkEventButton *ev)
284 {
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());
288 }
289
290 bool
291 Keyboard::is_context_menu_event (GdkEventButton *ev)
292 {
293         return (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_BUTTON_RELEASE) && 
294                 (ev->button == 3) && 
295                 ((ev->state & RelevantModifierKeyMask) == 0);
296 }
297
298 bool 
299 Keyboard::no_modifiers_active (guint state)
300 {
301         return (state & RelevantModifierKeyMask) == 0;
302 }
303
304 bool
305 Keyboard::modifier_state_contains (guint state, ModifierMask mask)
306 {
307         return (state & mask) == (guint) mask;
308 }
309
310 bool
311 Keyboard::modifier_state_equals (guint state, ModifierMask mask)
312 {
313         return (state & RelevantModifierKeyMask) == (guint) mask;
314 }
315
316 Selection::Operation
317 Keyboard::selection_type (guint state)
318 {
319         /* note that there is no modifier for "Add" */
320
321         if (modifier_state_equals (state, Shift)) {
322                 return Selection::Extend;
323         } else if (modifier_state_equals (state, Control)) {
324                 return Selection::Toggle;
325         } else {
326                 return Selection::Set;
327         }
328 }