#define EXECUTIVE_MODE_ENABLED #define E_COMP_X #include "e.h" typedef enum { DEVICE_FLAG_NONE, DEVICE_FLAG_TOUCHPAD } Device_Flags; static char *devstring = NULL; static void _handle_dev_prop(int dev_slot, const char *dev, const char *prop, Device_Flags dev_flags) { int num, size; Ecore_X_Atom fmt; /////////////////////////////////////////////////////////////////////////// // libinput devices if (!strcmp(prop, "libinput Middle Emulation Enabled")) { unsigned char cfval = 0; unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if (dev_flags == DEVICE_FLAG_TOUCHPAD) cfval = e_config->touch_emulate_middle_button; else cfval = e_config->mouse_emulate_middle_button; if ((val) && (size == 8) && (num == 1) && (cfval != val[0])) { val[0] = cfval; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "libinput Accel Speed")) { float cfval = 0.0; float *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if (dev_flags == DEVICE_FLAG_TOUCHPAD) cfval = e_config->touch_accel; else cfval = e_config->mouse_accel; if ((val) && (size == 32) && (num == 1) && (fabs(cfval - val[0]) >= 0.01)) { val[0] = cfval; printf("DEV: change [%s] [%s] -> %1.3f\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "libinput Tapping Enabled")) { if (dev_flags == DEVICE_FLAG_TOUCHPAD) { unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num == 1) && (e_config->touch_tap_to_click != val[0])) { val[0] = e_config->touch_tap_to_click; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } } // else if (!strcmp(prop, "libinput Tapping Button Mapping Enabled")) // { // // 1 bool, 0 = LRM, 1 = LMR // } else if ((!strcmp(prop, "libinput Horizontal Scrolling Enabled")) || (!strcmp(prop, "libinput Horizontal Scroll Enabled"))) { if (dev_flags == DEVICE_FLAG_TOUCHPAD) { unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num == 1) && (e_config->touch_scrolling_horiz != val[0])) { val[0] = e_config->touch_scrolling_horiz; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } } else if (!strcmp(prop, "libinput Scroll Method Enabled")) { if (dev_flags == DEVICE_FLAG_TOUCHPAD) { // 3 bool, 2 finger, edge, button unsigned char *val0 = ecore_x_input_device_property_get (dev_slot, "libinput Scroll Methods Available", &num, &fmt, &size); if ((val0) && (size == 8) && (num >= 3)) { unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num >= 3)) { unsigned char cf_2finger = 0, cf_edge = 0; if (val0[0]) cf_2finger = e_config->touch_scrolling_2finger; else cf_2finger = val[0]; if (val0[1]) cf_edge = e_config->touch_scrolling_edge; else cf_edge = val[1]; if ((cf_2finger != val[0]) || (cf_edge != val[1])) { val[0] = cf_2finger; val[1] = cf_edge; printf("DEV: change [%s] [%s] -> %i %i %i\n", dev, prop, val[0], val[1], val[2]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } } free(val); } free(val0); } } else if (!strcmp(prop, "libinput Natural Scrolling Enabled")) { unsigned char cfval = 0; unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if (dev_flags == DEVICE_FLAG_TOUCHPAD) cfval = e_config->touch_natural_scroll; else cfval = e_config->mouse_natural_scroll; if ((val) && (size == 8) && (num == 1) && (cfval != val[0])) { val[0] = cfval; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "libinput Accel Profile Enabled")) { // 1 bool, 0 = adaptive, 1 = flat unsigned char cfval = 0; unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if (dev_flags == DEVICE_FLAG_TOUCHPAD) cfval = e_config->touch_flat_accel; else cfval = e_config->mouse_flat_accel; if ((val) && (size == 8) && (num == 2) && (((cfval == 1) && (val[0] == 1)) || ((cfval == 0) && (val[0] == 0)))) { // Does a little flip-flop for each variable val[0] = !cfval; val[1] = cfval; printf("DEV: change [%s] [%s] -> %i, %i\n", dev, prop, val[0], val[1]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "libinput High Resolution Wheel Scroll Enabled")) { unsigned char cfval = e_config->mouse_hires_scroll; unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num == 1) && (cfval != val[0])) { val[0] = cfval; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } // do via button mapping for now - not sure about this evdev can't do this // else if (!strcmp(prop, "libinput Left Handed Enabled")) // { // // 1 bool // } /////////////////////////////////////////////////////////////////////////// // synaptics devices else if (!strcmp(prop, "Synaptics Middle Button Timeout")) { // 1 int - in ms unsigned int *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 32) && (num == 1) && (e_config->touch_emulate_middle_button && (val[0] != 50))) { val[0] = 50; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Synaptics Move Speed")) { float chval[4] = { 0.0 }; // 4 val float min, max, accel, unused chval[0] = 1.0; chval[1] = 1.75; chval[2] = 0.15 + (e_config->touch_accel * 0.15); float *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 32) && (num == 4) && ((fabs(chval[0] - val[0]) >= 0.01) || (fabs(chval[1] - val[1]) >= 0.01) || (fabs(chval[2] - val[2]) >= 0.01))) { val[0] = chval[0]; val[1] = chval[1]; val[2] = chval[2]; printf("DEV: change [%s] [%s] -> %1.3f %1.3f %1.3f %1.3f\n", dev, prop, val[1], val[1], val[2], val[3]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Synaptics Tap Action")) { // 7 val, 8 bit bit 0 = off, >0 mouse button reported // TR, BR, TL, BL, F1, F2, F3 // 1, 1, 1, 0, 1, 3, 2 <- tap to click unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); const char tapval[7] = { 1, 1, 1, 0, 1, 3, 2 }; const char notapval[7] = { 0, 0, 0, 0, 0, 0, 0 }; Eina_Bool have_tapval = EINA_FALSE; Eina_Bool have_notapval = EINA_FALSE; int i; if (num >= 7) { have_tapval = EINA_TRUE; for (i = 0; i < 7; i++) if (val[i] != tapval[i]) have_tapval = EINA_FALSE; have_notapval = EINA_TRUE; for (i = 0; i < 7; i++) if (val[i] != notapval[i]) have_notapval = EINA_FALSE; } if ((val) && (size == 8) && (num >= 7) && (((e_config->touch_tap_to_click) && (!have_tapval)) || ((!e_config->touch_tap_to_click) && (!have_notapval)))) { if (e_config->touch_tap_to_click) { for (i = 0; i < 7; i++) val[i] = tapval[i]; } else { for (i = 0; i < 7; i++) val[i] = notapval[i]; } printf("DEV: change [%s] [%s] -> %i %i %i %i %i %i %i\n", dev, prop, val[0], val[1], val[2], val[3], val[4], val[5], val[6]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Synaptics ClickPad")) { // 1 bool unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num == 1) && (e_config->touch_clickpad) != (val[0])) { val[0] = e_config->touch_clickpad; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Synaptics Edge Scrolling")) { // 3 bool - v, h, corner unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num >= 2) && (((e_config->touch_scrolling_edge) && ((!val[0]) || (val[1] != e_config->touch_scrolling_horiz))) || ((!e_config->touch_scrolling_edge) && ((val[0]) || (val[1]))))) { if (e_config->touch_scrolling_edge) { val[0] = 1; val[1] = e_config->touch_scrolling_horiz; } else { val[0] = 0; val[1] = 0; } printf("DEV: change [%s] [%s] -> %i %i\n", dev, prop, val[0], val[1]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Synaptics Two-Finger Scrolling")) { // 2 bool - h, v unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num >= 2) && (((e_config->touch_scrolling_2finger) && ((!val[0]) || (val[1] != e_config->touch_scrolling_horiz))) || ((!e_config->touch_scrolling_2finger) && ((val[0]) || (val[1]))))) { if (e_config->touch_scrolling_2finger) { val[0] = 1; val[1] = e_config->touch_scrolling_horiz; } else { val[0] = 0; val[1] = 0; } printf("DEV: change [%s] [%s] -> %i %i\n", dev, prop, val[0], val[1]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Synaptics Circular Scrolling")) { // 1 bool unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num == 1) && (e_config->touch_scrolling_circular != val[0])) { val[0] = e_config->touch_scrolling_circular; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Synaptics Palm Detection")) { // 1 bool - always turn on unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num == 1) && (e_config->touch_palm_detect) != (val[0])) { val[0] = e_config->touch_palm_detect; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Synaptics Scrolling Distance")) { // 2 ints v, h - invert them for natural (negative) int *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 32) && (num == 2) && (((e_config->touch_natural_scroll && ((val[0] > 0) || (val[1] > 0)))) || ((!e_config->touch_natural_scroll && ((val[0] < 0) || (val[1] < 0)))))) { if (e_config->mouse_natural_scroll) { if (val[0] > 0) val[0] = -val[0]; if (val[1] > 0) val[1] = -val[1]; } else { if (val[0] < 0) val[0] = -val[0]; if (val[1] < 0) val[1] = -val[1]; } printf("DEV: change [%s] [%s] -> %i %i\n", dev, prop, val[0], val[1]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } // else if (!strcmp(prop, "Synaptics Off")) // { // // 8 bit 0 = on, 1 = off (except physical clicks), 2 = // } /////////////////////////////////////////////////////////////////////////// // evdev devices else if (!strcmp(prop, "Evdev Middle Button Emulation")) { unsigned char *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 8) && (num == 1) && (e_config->mouse_emulate_middle_button) != (val[0])) { val[0] = e_config->mouse_emulate_middle_button; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } else if (!strcmp(prop, "Evdev Middle Button Timeout")) { unsigned short *val = ecore_x_input_device_property_get (dev_slot, prop, &num, &fmt, &size); if ((val) && (size == 16) && (num == 1) && (e_config->mouse_emulate_middle_button && (val[0] != 50))) { val[0] = 50; printf("DEV: change [%s] [%s] -> %i\n", dev, prop, val[0]); ecore_x_input_device_property_set (dev_slot, prop, val, num, fmt, size); } free(val); } } E_API void e_comp_x_devices_config_apply(Eina_Bool force) { int num_devs, i; Eina_Bool driver_evdev = EINA_FALSE; Eina_Bool driver_libinput = EINA_FALSE; Eina_Bool driver_synaptics = EINA_FALSE; Eina_Strbuf *sbuf; Eina_Bool changed = EINA_TRUE; num_devs = ecore_x_input_device_num_get(); sbuf = eina_strbuf_new(); if (!sbuf) return; for (i = 0; i < num_devs; i++) { eina_strbuf_append(sbuf, ecore_x_input_device_name_get(i)); } if ((devstring) && (!strcmp(devstring, eina_strbuf_string_get(sbuf)))) changed = EINA_FALSE; else { free(devstring); devstring = eina_strbuf_string_steal(sbuf); } eina_strbuf_free(sbuf); changed |= force; printf("DEV: CHANGES ... have %i devices, changed=%i\n", num_devs, changed); if (!changed) return; for (i = 0; i < num_devs; i++) { const char *name; char **props; int num_props, j; Device_Flags dev_flags = 0; name = ecore_x_input_device_name_get(i); // printf("DEV: DEV=%i: [%s]\n", i, name); props = ecore_x_input_device_properties_list(i, &num_props); if (props) { int num, size; Ecore_X_Atom fmt; unsigned char *val; // figure out device flags - for now is it a mouse or touchpad val = ecore_x_input_device_property_get (i, "libinput Scroll Methods Available", &num, &fmt, &size); if ((val) && (size == 8) && (num >= 3)) { if ((!val[2]) && (val[0] || val[1])) { dev_flags = DEVICE_FLAG_TOUCHPAD; } } if (!val) { val = ecore_x_input_device_property_get (i, "Synaptics Move Speed", &num, &fmt, &size); if ((val) && (size == 32) && (num == 4)) { dev_flags = DEVICE_FLAG_TOUCHPAD; } } free(val); for (j = 0; j < num_props; j++) { // printf("DEV: PROP=%i: [%s]\n", j, props[j]); if ((!driver_evdev) && (!strncmp(props[j], "Evdev ", 6))) driver_evdev = EINA_TRUE; else if ((!driver_libinput) && (!strncmp(props[j], "libinput ", 9))) driver_libinput = EINA_TRUE; else if ((!driver_synaptics) && (!strncmp(props[j], "Synaptics ", 10))) driver_synaptics = EINA_TRUE; _handle_dev_prop(i, name, props[j], dev_flags); } ecore_x_input_device_properties_free(props, num_props); } } // generic accel - if synatics or evdev props found? { int accel_numerator, accel_denominator; accel_numerator = 20 + (e_config->mouse_accel * 20.0); accel_denominator = 10; ecore_x_pointer_control_set(accel_numerator, accel_denominator, e_config->mouse_accel_threshold); } // button mapping - for mouse hand and natural scroll { unsigned char map[256] = { 0 }; int n; if (ecore_x_pointer_mapping_get(map, 256)) { for (n = 0; n < 256; n++) { if (!map[n]) break; } if (n < 3) { map[0] = 1; map[1] = 2; map[2] = 3; n = 3; } if (e_config->mouse_hand == E_MOUSE_HAND_RIGHT) { map[0] = 1; map[2] = 3; } else if (e_config->mouse_hand == E_MOUSE_HAND_LEFT) { map[0] = 3; map[2] = 1; } // if we are not on libinput or synaptics drivers anywehre then // swap buttons the old fashioned way if ((n >= 5) && (!driver_libinput) && (!driver_synaptics)) { if (e_config->mouse_natural_scroll) { map[3] = 5; map[4] = 4; } else { map[3] = 4; map[4] = 5; } } ecore_x_pointer_mapping_set(map, n); } } }