1 /*
2 * Copyright (C) 2005-2007 Doug McLain <doug@nostar.net>
3 * Copyright (C) 2005-2017 Tim Mayberry <mojofunk@gmail.com>
4 * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com>
5 * Copyright (C) 2005 Karsten Wiese <fzuuzf@googlemail.com>
6 * Copyright (C) 2005 Taybin Rutkin <taybin@taybin.com>
7 * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
8 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
9 * Copyright (C) 2008-2010 Sakari Bergen <sakari.bergen@beatwaves.net>
10 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
11 * Copyright (C) 2013-2015 Colin Fletcher <colin.m.fletcher@googlemail.com>
12 * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
13 * Copyright (C) 2013-2016 Nick Mainsbridge <mainsbridge@gmail.com>
14 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
15 * Copyright (C) 2015 André Nusser <andre.nusser@googlemail.com>
16 * Copyright (C) 2016-2018 Len Ovens <len@ovenwerks.net>
17 * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 */
33
34 #ifdef WAF_BUILD
35 #include "gtk2ardour-config.h"
36 #include "gtk2ardour-version.h"
37 #endif
38
39 #include "ardour_ui.h"
40 #include "debug.h"
41 #include "keyboard.h"
42 #include "public_editor.h"
43 #include "virtual_keyboard_window.h"
44
45 using namespace ARDOUR;
46 using namespace PBD;
47 using namespace Gtkmm2ext;
48 using namespace ArdourWidgets;
49 using namespace Gtk;
50 using namespace std;
51
52 bool
key_event_handler(GdkEventKey * ev,Gtk::Window * event_window)53 ARDOUR_UI::key_event_handler (GdkEventKey* ev, Gtk::Window* event_window)
54 {
55 Gtkmm2ext::Bindings* bindings = 0;
56 Gtk::Window* window = 0;
57
58 if (virtual_keyboard_window && virtual_keyboard_window->is_visible()) {
59 if (gtk_window_propagate_key_event (virtual_keyboard_window->gobj(), ev)) {
60 return true;
61 }
62 }
63
64 /* until we get ardour bindings working, we are not handling key
65 * releases yet.
66 */
67
68 if (ev->type != GDK_KEY_PRESS) {
69 return false;
70 }
71
72 if (event_window == &_main_window) {
73
74 window = event_window;
75
76 /* find current tab contents */
77
78 Gtk::Widget* w = _tabs.get_nth_page (_tabs.get_current_page());
79
80 /* see if it uses the ardour binding system */
81
82 if (w) {
83 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(w->get_data ("ardour-bindings"));
84 }
85
86 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("main window key event, bindings = %1, global = %2\n", bindings, &global_bindings));
87
88 } else {
89
90 window = event_window;
91
92 /* see if window uses ardour binding system */
93
94 bindings = reinterpret_cast<Gtkmm2ext::Bindings*>(window->get_data ("ardour-bindings"));
95 }
96
97 /* An empty binding set is treated as if it doesn't exist */
98
99 if (bindings && bindings->empty()) {
100 bindings = 0;
101 }
102
103 return key_press_focus_accelerator_handler (*window, ev, bindings);
104 }
105
106 static Gtkmm2ext::Bindings*
get_bindings_from_widget_heirarchy(GtkWidget ** w)107 get_bindings_from_widget_heirarchy (GtkWidget** w)
108 {
109 void* p = NULL;
110
111 while (*w) {
112 if ((p = g_object_get_data (G_OBJECT(*w), "ardour-bindings")) != 0) {
113 break;
114 }
115 *w = gtk_widget_get_parent (*w);
116 }
117
118 return reinterpret_cast<Gtkmm2ext::Bindings*> (p);
119 }
120
121 bool
key_press_focus_accelerator_handler(Gtk::Window & window,GdkEventKey * ev,Gtkmm2ext::Bindings * top_level_bindings)122 ARDOUR_UI::key_press_focus_accelerator_handler (Gtk::Window& window, GdkEventKey* ev, Gtkmm2ext::Bindings* top_level_bindings)
123 {
124 GtkWindow* win = window.gobj();
125 GtkWidget* focus = gtk_window_get_focus (win);
126 bool special_handling_of_unmodified_accelerators = false;
127 const guint mask = (Keyboard::RelevantModifierKeyMask & ~(Gdk::SHIFT_MASK|Gdk::LOCK_MASK));
128
129 if (focus) {
130
131 /* some widget has keyboard focus */
132
133 if (GTK_IS_ENTRY(focus) || Keyboard::some_magic_widget_has_focus()) {
134
135 /* A particular kind of focusable widget currently has keyboard
136 * focus. All unmodified key events should go to that widget
137 * first and not be used as an accelerator by default
138 */
139
140 special_handling_of_unmodified_accelerators = true;
141
142 }
143 }
144
145 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("Win = %1 [title = %9] focus = %7 (%8) Key event: code = %2 [%10] state = %3 special handling ? %4 magic widget focus ? %5 focus widget %6 named %7 mods ? %8\n",
146 win,
147 ev->keyval,
148 Gtkmm2ext::show_gdk_event_state (ev->state),
149 special_handling_of_unmodified_accelerators,
150 Keyboard::some_magic_widget_has_focus(),
151 focus,
152 (focus ? gtk_widget_get_name (focus) : "no focus widget"),
153 ((ev->state & mask) ? "yes" : "no"),
154 window.get_title(),
155 gdk_keyval_name (ev->keyval)))
156
157 /* This exists to allow us to override the way GTK handles
158 key events. The normal sequence is:
159
160 a) event is delivered to a GtkWindow
161 b) accelerators/mnemonics are activated
162 c) if (b) didn't handle the event, propagate to
163 the focus widget and/or focus chain
164
165 The problem with this is that if the accelerators include
166 keys without modifiers, such as the space bar or the
167 letter "e", then pressing the key while typing into
168 a text entry widget results in the accelerator being
169 activated, instead of the desired letter appearing
170 in the text entry.
171
172 There is no good way of fixing this, but this
173 represents a compromise. The idea is that
174 key events involving modifiers (not Shift)
175 get routed into the activation pathway first, then
176 get propagated to the focus widget if necessary.
177
178 If the key event doesn't involve modifiers,
179 we deliver to the focus widget first, thus allowing
180 it to get "normal text" without interference
181 from acceleration.
182
183 Of course, this can also be problematic: if there
184 is a widget with focus, then it will swallow
185 all "normal text" accelerators.
186 */
187
188
189 if (!special_handling_of_unmodified_accelerators || (ev->state & mask)) {
190
191 /* no special handling or there are modifiers in effect: accelerate first */
192
193 DEBUG_TRACE (DEBUG::Accelerators, "\tactivate, then propagate\n");
194
195 KeyboardKey k (ev->state, ev->keyval);
196
197 /* Check heirarchy from current focus widget upwards */
198
199 while (focus) {
200
201 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&focus);
202
203 if (focus_bindings) {
204 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing widget bindings %1 @ %2 for this event\n", focus_bindings->name(), focus_bindings));
205 if (focus_bindings->activate (k, Bindings::Press)) {
206 return true;
207 }
208 }
209
210 if (focus) {
211 focus = gtk_widget_get_parent (focus);
212 }
213 }
214
215 /* Use any "top level" bindings passed to us (could be from a
216 * top level tab or a top level window)
217 */
218
219 if (top_level_bindings) {
220 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing top level bindings %1 @ %2 for this event\n", top_level_bindings->name(), top_level_bindings));
221 }
222
223 if (top_level_bindings && top_level_bindings->activate (k, Bindings::Press)) {
224 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
225 return true;
226 }
227
228 /* Use any global bindings */
229
230 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
231
232 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
233 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
234 return true;
235 }
236
237 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled by binding activation, now propagate to window\n");
238
239 if (gtk_window_propagate_key_event (win, ev)) {
240 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate handled\n");
241 return true;
242 }
243
244 } else {
245
246 /* no modifiers, propagate first */
247
248 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagate, then activate\n");
249
250 if (gtk_window_propagate_key_event (win, ev)) {
251 DEBUG_TRACE (DEBUG::Accelerators, "\thandled by propagate\n");
252 return true;
253 }
254
255 DEBUG_TRACE (DEBUG::Accelerators, "\tpropagation didn't handle, so activate\n");
256 KeyboardKey k (ev->state, ev->keyval);
257
258 while (focus) {
259
260 Gtkmm2ext::Bindings* focus_bindings = get_bindings_from_widget_heirarchy (&focus);
261
262 if (focus_bindings) {
263 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing widget bindings %1 @ %2 for this event\n", focus_bindings->name(), focus_bindings));
264 if (focus_bindings->activate (k, Bindings::Press)) {
265 return true;
266 }
267 }
268
269 if (focus) {
270 focus = gtk_widget_get_parent (focus);
271 }
272 }
273
274 /* Use any "top level" bindings passed to us (could be from a
275 * top level tab or a top level window)
276 */
277
278 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tusing top level bindings %1 @ %2 for this event\n", top_level_bindings->name(), top_level_bindings));
279
280 if (top_level_bindings && top_level_bindings->activate (k, Bindings::Press)) {
281 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
282 return true;
283 }
284
285 DEBUG_TRACE (DEBUG::Accelerators, string_compose ("\tnot yet handled, try global bindings (%1)\n", global_bindings));
286
287 if (global_bindings && global_bindings->activate (k, Bindings::Press)) {
288 DEBUG_TRACE (DEBUG::Accelerators, "\t\thandled\n");
289 return true;
290 }
291 }
292
293 DEBUG_TRACE (DEBUG::Accelerators, "\tnot handled\n");
294 return true;
295 }
296
297
298 gint
transport_numpad_timeout()299 ARDOUR_UI::transport_numpad_timeout ()
300 {
301 _numpad_locate_happening = false;
302 if (_numpad_timeout_connection.connected() )
303 _numpad_timeout_connection.disconnect();
304 return 1;
305 }
306
307 void
transport_numpad_decimal()308 ARDOUR_UI::transport_numpad_decimal ()
309 {
310 _numpad_timeout_connection.disconnect();
311
312 if (_numpad_locate_happening) {
313 if (editor) editor->goto_nth_marker(_pending_locate_num - 1);
314 _numpad_locate_happening = false;
315 } else {
316 _pending_locate_num = 0;
317 _numpad_locate_happening = true;
318 _numpad_timeout_connection = Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::transport_numpad_timeout), 2*1000);
319 }
320 }
321
322 void
transport_numpad_event(int num)323 ARDOUR_UI::transport_numpad_event (int num)
324 {
325 if ( _numpad_locate_happening ) {
326 _pending_locate_num = _pending_locate_num*10 + num;
327 } else {
328 switch (num) {
329 case 0: toggle_roll(false, false); break;
330 case 1: transport_rewind(); break;
331 case 2: transport_forward(); break;
332 case 3: transport_record(true); break;
333 case 4: toggle_session_auto_loop(); break;
334 case 5: transport_record(false); toggle_session_auto_loop(); break;
335 case 6: toggle_punch(); break;
336 case 7: toggle_click(); break;
337 case 8: toggle_auto_return(); break;
338 case 9: toggle_follow_edits(); break;
339 }
340 }
341 }
342