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