2 terminatorX - realtime audio scratching software
3 Copyright (C) 1999-2016 Alexander König
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Description: This implements the mouse AND keyboard Input handling in
26 #define __STDC_FORMAT_MACROS
36 #include "tX_mastergui.h"
37 #include "tX_global.h"
38 #include "tX_engine.h"
44 #define TX_MOUSE_SPEED_NORMAL 0.05
45 #define TX_MOUSE_SPEED_WARP 250000
47 tx_mouse :: tx_mouse()
51 linux_input_channel = NULL;
52 grab_mode = LINUX_INPUT;
55 warp=TX_MOUSE_SPEED_NORMAL;
56 enable_auto_mnemonics = FALSE;
58 last_button_press = 0;
59 last_button_release = 0;
63 int tx_mouse :: grab()
65 if (grabbed) return 0;
68 memset(key_pressed, 0, sizeof(key_pressed));
72 if (grab_linux_input()) {
73 grab_mode = LINUX_INPUT;
78 window = gtk_widget_get_window(main_window);
79 GdkDisplay* gdk_dpy = gdk_window_get_display(window);
80 GdkDeviceManager *device_manager = gdk_display_get_device_manager(gdk_dpy);
83 fputs("GrabMode Error: couldn't access GDKDisplay.", stderr);
84 return(ENG_ERR_XOPEN);
87 gtk_window_present(GTK_WINDOW(main_window));
89 savedEventMask = gdk_window_get_events(window);
90 GdkEventMask newEventMask = GdkEventMask ((int) savedEventMask | GDK_POINTER_MOTION_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
91 gdk_window_set_events(top_window, newEventMask);
93 g_object_get (gtk_widget_get_settings (main_window), "gtk-auto-mnemonics", &enable_auto_mnemonics, NULL);
95 if (enable_auto_mnemonics) {
97 g_object_set (gtk_widget_get_settings (main_window), "gtk-auto-mnemonics", off, NULL);
100 pointer = gdk_device_manager_get_client_pointer(device_manager);
101 GdkGrabStatus grab_status = gdk_device_grab(pointer, top_window, GDK_OWNERSHIP_APPLICATION, FALSE, GdkEventMask (GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK), NULL, GDK_CURRENT_TIME);
103 gdk_device_get_position(pointer, &screen, &x_restore, &y_restore);
105 gint x = gdk_screen_get_width(screen) / 2;
106 gint y = gdk_screen_get_height(screen) / 2;
111 gdk_device_warp(pointer, screen, x_abs, y_abs);
113 if (grab_status != GDK_GRAB_SUCCESS) {
117 GList *list = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
118 for (GList *link = list; link != NULL; link = g_list_next (link)) {
119 GdkDevice *device = GDK_DEVICE (link->data);
121 if (gdk_device_get_source (device) != GDK_SOURCE_KEYBOARD)
128 grab_status = gdk_device_grab(keyboard, top_window, GDK_OWNERSHIP_APPLICATION, FALSE, GdkEventMask (GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK), NULL, GDK_CURRENT_TIME);
130 if (grab_status != GDK_GRAB_SUCCESS) {
131 gdk_device_ungrab(pointer, GDK_CURRENT_TIME);
135 cursor = gdk_window_get_cursor(window);
136 gdk_window_set_cursor(window, gdk_cursor_new_for_display(gdk_dpy, GDK_BLANK_CURSOR));
140 std::list<vtt_class *> :: iterator v;
143 for (v=vtt_class::main_list.begin(); v!=vtt_class::main_list.end(); v++) {
144 if (!(*v)->audio_hidden) {
145 vtt_class::focus_no(c);
151 warp=TX_MOUSE_SPEED_NORMAL;
156 void tx_mouse :: ungrab()
158 if (!grabbed) return;
160 tX_debug("tX_mouse::ungrab(): this: %016" PRIxPTR, (uintptr_t) this);
162 gdk_device_ungrab(keyboard, GDK_CURRENT_TIME);
163 gdk_device_ungrab(pointer, GDK_CURRENT_TIME);
165 gdk_window_set_cursor(window, cursor);
167 vtt_class::unfocus();
169 gdk_window_set_events(top_window, savedEventMask);
171 if (enable_auto_mnemonics) {
172 g_object_set (gtk_widget_get_settings (main_window), "gtk-auto-mnemonics", enable_auto_mnemonics, NULL);
175 ungrab_linux_input();
177 tX_debug("tX_mouse::ungrab(): done");
182 GError *tx_mouse::open_channel() {
183 GError *error = NULL;
185 linux_input_channel = g_io_channel_new_file("/dev/input/mice", "r", &error);
186 if (linux_input_channel) {
187 g_io_channel_set_flags(linux_input_channel, G_IO_FLAG_NONBLOCK, NULL);
196 void tx_mouse::close_channel() {
197 if (linux_input_channel) {
198 g_io_channel_shutdown(linux_input_channel, false, NULL);
199 g_io_channel_unref(linux_input_channel);
200 linux_input_channel = NULL;
204 int tx_mouse::grab_linux_input() {
206 if (linux_input_channel) {
207 linux_input_watch = g_io_add_watch_full(linux_input_channel, G_PRIORITY_HIGH, G_IO_IN, tx_mouse::linux_input_wrap, this, NULL);
209 tX_msg("Linux input channel not available, falling back to pointer warping.");
215 void tx_mouse::ungrab_linux_input() {
216 if (grab_mode == LINUX_INPUT) {
217 // only remove the watch, we keep the channel as we dropped root and might fail to re-open it
218 g_source_remove(linux_input_watch);
222 #define vtt vtt_class::focused_vtt
224 void tx_mouse::motion_notify(GtkWidget *widget, GdkEventMotion *eventMotion) {
225 if ((grab_mode == FALLBACK) && vtt) {
226 gdouble d_x = eventMotion->x_root - x_abs;
227 gdouble d_y = eventMotion->y_root - y_abs;
229 if ((d_x != 0.0) || (d_y != 0.0)) {
230 //gdouble xnow, ynow;
231 //gdk_device_get_position_double(pointer, NULL, &xnow, &ynow);
232 //printf("%lf -> %lf, %lf -> %lf\n", eventMotion->x_root, xnow, eventMotion->y_root, ynow);
233 gdk_device_warp(pointer, screen, x_abs, y_abs);
236 f_prec value=(fabs(d_x)>fabs(d_y)) ? d_x : d_y;
237 vtt->sp_speed.handle_mouse_input(value*globals.mouse_speed*warp);
239 vtt->xy_input((f_prec) d_x*warp, (f_prec) d_y*warp);
245 void tx_mouse::linux_input(tx_input_event *event) {
246 if ((grab_mode == LINUX_INPUT) && vtt) {
247 if ((event->x_motion != 0) || (event->y_motion != 0)) {
248 // gdk_device_warp(pointer, screen, x_abs, y_abs);
249 gdouble d_x = event->x_motion;
250 gdouble d_y = event->y_motion;
253 f_prec value=(fabs(d_x)>fabs(d_y)) ? d_x : d_y;
254 vtt->sp_speed.handle_mouse_input(value*globals.mouse_speed*warp);
256 vtt->xy_input((f_prec) d_x*warp, (f_prec) d_y*warp);
262 void tx_mouse::button_press(GtkWidget *widget, GdkEventButton *eventButton) {
264 switch(eventButton->button) {
265 case 1: if (vtt->is_playing)
268 vtt->sp_trigger.receive_input_value(1);
270 case 2: vtt->sp_mute.receive_input_value(1); break;
271 case 3: vtt_class::focus_next(); break;
276 void tx_mouse::button_release(GtkWidget *widget, GdkEventButton *eventButton) {
278 switch (eventButton->button) {
279 case 1: vtt->set_scratch(0); break;
280 case 2: vtt->sp_mute.receive_input_value(0); break;
285 void tx_mouse::key_press(GtkWidget *widget, GdkEventKey *eventKey) {
287 switch(eventKey->keyval) {
288 case GDK_KEY_space: if (press_key(KEY_space)) { vtt->set_scratch(1); } break;
289 case GDK_KEY_Escape: if (press_key(KEY_Escape)) { ungrab(); } break;
291 case GDK_KEY_Return: if (press_key(KEY_Return)) { vtt->sp_trigger.receive_input_value(1); } break;
292 case GDK_KEY_BackSpace: if (press_key(KEY_BackSpace)) { vtt->sp_trigger.receive_input_value(0); } break;
294 case GDK_KEY_Tab: if (press_key(KEY_Tab)) { vtt_class::focus_next(); } break;
296 case GDK_KEY_s: if (press_key(KEY_s)) { vtt->sp_sync_client.receive_input_value(!vtt->is_sync_client); } break;
298 case GDK_KEY_m: if (press_key(KEY_m)) { vtt->sp_mute.receive_input_value(1); } break;
299 case GDK_KEY_Control_L: if (press_key(KEY_Control_L)) { vtt->sp_mute.receive_input_value(1); } break;
300 case GDK_KEY_Control_R: if (press_key(KEY_Control_R)) { vtt->sp_mute.receive_input_value(1); } break;
302 case GDK_KEY_Alt_L: if (press_key(KEY_Alt_L)) { vtt->sp_mute.receive_input_value(0); } break;
303 case GDK_KEY_Alt_R: if (press_key(KEY_Alt_R)) { vtt->sp_mute.receive_input_value(0); } break;
305 case GDK_KEY_w: if (press_key(KEY_w)) {
306 vtt->sp_mute.receive_input_value(1);
308 warp=((float) vtt->samples_in_buffer)/TX_MOUSE_SPEED_WARP;
312 case GDK_KEY_f: if (press_key(KEY_f)) {
314 warp=((float) vtt->samples_in_buffer)/TX_MOUSE_SPEED_WARP;
319 case GDK_KEY_F1: if (press_key(KEY_F1)) { vtt_class::focus_no(0); } break;
320 case GDK_KEY_F2: if (press_key(KEY_F2)) { vtt_class::focus_no(1); } break;
321 case GDK_KEY_F3: if (press_key(KEY_F3)) { vtt_class::focus_no(2); } break;
322 case GDK_KEY_F4: if (press_key(KEY_F4)) { vtt_class::focus_no(3); } break;
323 case GDK_KEY_F5: if (press_key(KEY_F5)) { vtt_class::focus_no(4); } break;
324 case GDK_KEY_F6: if (press_key(KEY_F6)) { vtt_class::focus_no(5); } break;
325 case GDK_KEY_F7: if (press_key(KEY_F7)) { vtt_class::focus_no(6); } break;
326 case GDK_KEY_F8: if (press_key(KEY_F8)) { vtt_class::focus_no(7); } break;
327 case GDK_KEY_F9: if (press_key(KEY_F9)) { vtt_class::focus_no(8); } break;
328 case GDK_KEY_F10: if (press_key(KEY_F10)) { vtt_class::focus_no(9); } break;
329 case GDK_KEY_F11: if (press_key(KEY_F11)) { vtt_class::focus_no(10); } break;
330 case GDK_KEY_F12: if (press_key(KEY_F12)) { vtt_class::focus_no(11); } break;
335 void tx_mouse::key_release(GtkWidget *widget, GdkEventKey *eventKey) {
337 switch(eventKey->keyval) {
338 case GDK_KEY_space: if (release_key(KEY_space)) { vtt->set_scratch(0); } break;
339 case GDK_KEY_Escape: release_key(KEY_Escape); break;
341 case GDK_KEY_Return: release_key(KEY_Return); break;
342 case GDK_KEY_BackSpace: release_key(KEY_BackSpace); break;
344 case GDK_KEY_Tab: release_key(KEY_Tab); break;
346 case GDK_KEY_s: release_key(KEY_s); break;
349 case GDK_KEY_m: if (release_key(KEY_m)) { vtt->sp_mute.receive_input_value(0); } break;
350 case GDK_KEY_Control_L: if (release_key(KEY_Control_L)) { vtt->sp_mute.receive_input_value(0); } break;
351 case GDK_KEY_Control_R: if (release_key(KEY_Control_R)) { vtt->sp_mute.receive_input_value(0); } break;
353 case GDK_KEY_Alt_L: if (release_key(KEY_Alt_L)) { vtt->sp_mute.receive_input_value(1); } break;
354 case GDK_KEY_Alt_R: if (release_key(KEY_Alt_R)) { vtt->sp_mute.receive_input_value(1); } break;
356 case GDK_KEY_w: if (release_key(KEY_w)) {
357 vtt->sp_mute.receive_input_value(0);
358 warp=TX_MOUSE_SPEED_NORMAL;
364 case GDK_KEY_f: if (release_key(KEY_f)) {
365 warp=TX_MOUSE_SPEED_NORMAL;
371 case GDK_KEY_F1: release_key(KEY_F1); break;
372 case GDK_KEY_F2: release_key(KEY_F2); break;
373 case GDK_KEY_F3: release_key(KEY_F3); break;
374 case GDK_KEY_F4: release_key(KEY_F4); break;
375 case GDK_KEY_F5: release_key(KEY_F5); break;
376 case GDK_KEY_F6: release_key(KEY_F6); break;
377 case GDK_KEY_F7: release_key(KEY_F7); break;
378 case GDK_KEY_F8: release_key(KEY_F8); break;
379 case GDK_KEY_F9: release_key(KEY_F9); break;
380 case GDK_KEY_F10: release_key(KEY_F10); break;
381 case GDK_KEY_F11: release_key(KEY_F11); break;
382 case GDK_KEY_F12: release_key(KEY_F12); break;
387 gboolean tx_mouse::motion_notify_wrap(GtkWidget *widget, GdkEventMotion *eventMotion, void *data) {
388 tx_mouse* mouse = (tx_mouse *) data;
389 if (mouse->grabbed) {
390 mouse->motion_notify(widget, eventMotion);
397 gboolean tx_mouse::linux_input_wrap(GIOChannel *source, GIOCondition condition, gpointer data) {
398 if (condition == G_IO_IN) {
400 tx_input_event eventbuffer[512];
401 tx_mouse* mouse = (tx_mouse *) data;
402 gint fd = g_io_channel_unix_get_fd(mouse->linux_input_channel);
403 ssize_t bytes_read = read(fd, &eventbuffer, sizeof(eventbuffer));
405 //printf("read %lu bytes, %lu events\n", bytes_read, bytes_read / sizeof(tx_input_event));
410 for (ssize_t i = 0; i < bytes_read / ((ssize_t) sizeof(tx_input_event)); i++) {
411 sum.x_motion += eventbuffer[i].x_motion;
412 sum.y_motion += eventbuffer[i].y_motion;
414 mouse->linux_input(&sum);
419 gboolean tx_mouse::button_press_wrap(GtkWidget *widget, GdkEventButton *eventButton, void *data) {
420 tx_mouse* mouse = (tx_mouse *) data;
421 if (mouse->grabbed) {
422 if (mouse->last_button_press != eventButton->time) {
423 mouse->last_button_press = eventButton->time;
425 tX_debug("tX_mouse::button-press-event (%u)", eventButton->button);
426 mouse->button_press(widget, eventButton);
428 tX_debug("tX_mouse::button-press-event (%u) identical event skipped", eventButton->button);
435 gboolean tx_mouse::button_release_wrap(GtkWidget *widget, GdkEventButton *eventButton, void *data) {
436 tx_mouse* mouse = (tx_mouse *) data;
437 if (mouse->grabbed) {
438 if (mouse->last_button_release != eventButton->time) {
439 mouse->last_button_release = eventButton->time;
441 tX_debug("tX_mouse::button-release-event (%u)", eventButton->button);
442 mouse->button_release(widget, eventButton);
444 tX_debug("tX_mouse::button-release-event (%u) identical event skipped", eventButton->button);
453 gboolean tx_mouse::key_press_wrap(GtkWidget *widget, GdkEventKey *eventKey, void *data) {
454 tx_mouse* mouse = (tx_mouse *) data;
455 if (mouse->grabbed) {
456 tX_debug("tX_mouse::key-press-event (%u)", eventKey->keyval);
457 mouse->key_press(widget, eventKey);
464 gboolean tx_mouse::key_release_wrap(GtkWidget *widget, GdkEventKey *eventKey, void *data) {
465 tx_mouse* mouse = (tx_mouse *) data;
466 if (mouse->grabbed) {
467 tX_debug("tX_mouse::key-release-event (%u)", eventKey->keyval);
468 mouse->key_release(widget, eventKey);