| /* |
| * Copyright © 2014-2015 Red Hat, Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the next |
| * paragraph) shall be included in all copies or substantial portions of the |
| * Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| * DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #include "config.h" |
| |
| #include <stdint.h> |
| |
| #include "evdev.h" |
| |
| #define MIDDLEBUTTON_TIMEOUT ms2us(50) |
| |
| /***************************************** |
| * BEFORE YOU EDIT THIS FILE, look at the state diagram in |
| * doc/middle-button-emulation-state-machine.svg, or online at |
| * https://drive.google.com/file/d/0B1NwWmji69nodUJncXRMc1FvY1k/view?usp=sharing |
| * (it's a http://draw.io diagram) |
| * |
| * Any changes in this file must be represented in the diagram. |
| * |
| * Note in regards to the state machine: it only handles left, right and |
| * emulated middle button clicks, all other button events are passed |
| * through. When in the PASSTHROUGH state, all events are passed through |
| * as-is. |
| */ |
| |
| static inline const char* |
| middlebutton_state_to_str(enum evdev_middlebutton_state state) |
| { |
| switch (state) { |
| CASE_RETURN_STRING(MIDDLEBUTTON_IDLE); |
| CASE_RETURN_STRING(MIDDLEBUTTON_LEFT_DOWN); |
| CASE_RETURN_STRING(MIDDLEBUTTON_RIGHT_DOWN); |
| CASE_RETURN_STRING(MIDDLEBUTTON_MIDDLE); |
| CASE_RETURN_STRING(MIDDLEBUTTON_LEFT_UP_PENDING); |
| CASE_RETURN_STRING(MIDDLEBUTTON_RIGHT_UP_PENDING); |
| CASE_RETURN_STRING(MIDDLEBUTTON_PASSTHROUGH); |
| CASE_RETURN_STRING(MIDDLEBUTTON_IGNORE_LR); |
| CASE_RETURN_STRING(MIDDLEBUTTON_IGNORE_L); |
| CASE_RETURN_STRING(MIDDLEBUTTON_IGNORE_R); |
| } |
| |
| return NULL; |
| } |
| |
| static inline const char* |
| middlebutton_event_to_str(enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_L_DOWN); |
| CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_R_DOWN); |
| CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_OTHER); |
| CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_L_UP); |
| CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_R_UP); |
| CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_TIMEOUT); |
| CASE_RETURN_STRING(MIDDLEBUTTON_EVENT_ALL_UP); |
| } |
| |
| return NULL; |
| } |
| |
| static void |
| middlebutton_state_error(struct evdev_device *device, |
| enum evdev_middlebutton_event event) |
| { |
| log_bug_libinput(device->base.seat->libinput, |
| "Invalid event %s in middle btn state %s\n", |
| middlebutton_event_to_str(event), |
| middlebutton_state_to_str(device->middlebutton.state)); |
| } |
| |
| static void |
| middlebutton_timer_set(struct evdev_device *device, uint64_t now) |
| { |
| libinput_timer_set(&device->middlebutton.timer, |
| now + MIDDLEBUTTON_TIMEOUT); |
| } |
| |
| static void |
| middlebutton_timer_cancel(struct evdev_device *device) |
| { |
| libinput_timer_cancel(&device->middlebutton.timer); |
| } |
| |
| static inline void |
| middlebutton_set_state(struct evdev_device *device, |
| enum evdev_middlebutton_state state, |
| uint64_t now) |
| { |
| switch (state) { |
| case MIDDLEBUTTON_LEFT_DOWN: |
| case MIDDLEBUTTON_RIGHT_DOWN: |
| middlebutton_timer_set(device, now); |
| device->middlebutton.first_event_time = now; |
| break; |
| case MIDDLEBUTTON_IDLE: |
| case MIDDLEBUTTON_MIDDLE: |
| case MIDDLEBUTTON_LEFT_UP_PENDING: |
| case MIDDLEBUTTON_RIGHT_UP_PENDING: |
| case MIDDLEBUTTON_PASSTHROUGH: |
| case MIDDLEBUTTON_IGNORE_LR: |
| case MIDDLEBUTTON_IGNORE_L: |
| case MIDDLEBUTTON_IGNORE_R: |
| middlebutton_timer_cancel(device); |
| break; |
| } |
| |
| device->middlebutton.state = state; |
| } |
| |
| static void |
| middlebutton_post_event(struct evdev_device *device, |
| uint64_t now, |
| int button, |
| enum libinput_button_state state) |
| { |
| evdev_pointer_notify_button(device, |
| now, |
| button, |
| state); |
| } |
| |
| static int |
| evdev_middlebutton_idle_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| middlebutton_set_state(device, MIDDLEBUTTON_LEFT_DOWN, time); |
| break; |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| middlebutton_set_state(device, MIDDLEBUTTON_RIGHT_DOWN, time); |
| break; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_UP: |
| case MIDDLEBUTTON_EVENT_L_UP: |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_ldown_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| middlebutton_post_event(device, time, |
| BTN_MIDDLE, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_set_state(device, MIDDLEBUTTON_MIDDLE, time); |
| break; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| middlebutton_post_event(device, time, |
| BTN_LEFT, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_set_state(device, |
| MIDDLEBUTTON_PASSTHROUGH, |
| time); |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_UP: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_L_UP: |
| middlebutton_post_event(device, |
| device->middlebutton.first_event_time, |
| BTN_LEFT, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_post_event(device, time, |
| BTN_LEFT, |
| LIBINPUT_BUTTON_STATE_RELEASED); |
| middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time); |
| break; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| middlebutton_post_event(device, |
| device->middlebutton.first_event_time, |
| BTN_LEFT, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_set_state(device, |
| MIDDLEBUTTON_PASSTHROUGH, |
| time); |
| break; |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| middlebutton_state_error(device, event); |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_rdown_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| middlebutton_post_event(device, time, |
| BTN_MIDDLE, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_set_state(device, MIDDLEBUTTON_MIDDLE, time); |
| break; |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| middlebutton_post_event(device, |
| device->middlebutton.first_event_time, |
| BTN_RIGHT, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_set_state(device, |
| MIDDLEBUTTON_PASSTHROUGH, |
| time); |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_UP: |
| middlebutton_post_event(device, |
| device->middlebutton.first_event_time, |
| BTN_RIGHT, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_post_event(device, time, |
| BTN_RIGHT, |
| LIBINPUT_BUTTON_STATE_RELEASED); |
| middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time); |
| break; |
| case MIDDLEBUTTON_EVENT_L_UP: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| middlebutton_post_event(device, |
| device->middlebutton.first_event_time, |
| BTN_RIGHT, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_set_state(device, |
| MIDDLEBUTTON_PASSTHROUGH, |
| time); |
| break; |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| middlebutton_state_error(device, event); |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_middle_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| middlebutton_post_event(device, time, |
| BTN_MIDDLE, |
| LIBINPUT_BUTTON_STATE_RELEASED); |
| middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_LR, time); |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_UP: |
| middlebutton_post_event(device, time, |
| BTN_MIDDLE, |
| LIBINPUT_BUTTON_STATE_RELEASED); |
| middlebutton_set_state(device, |
| MIDDLEBUTTON_LEFT_UP_PENDING, |
| time); |
| break; |
| case MIDDLEBUTTON_EVENT_L_UP: |
| middlebutton_post_event(device, time, |
| BTN_MIDDLE, |
| LIBINPUT_BUTTON_STATE_RELEASED); |
| middlebutton_set_state(device, |
| MIDDLEBUTTON_RIGHT_UP_PENDING, |
| time); |
| break; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| middlebutton_state_error(device, event); |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_lup_pending_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| middlebutton_post_event(device, time, |
| BTN_MIDDLE, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_set_state(device, MIDDLEBUTTON_MIDDLE, time); |
| break; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_L, time); |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_UP: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_L_UP: |
| middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time); |
| break; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| middlebutton_state_error(device, event); |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_rup_pending_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| middlebutton_post_event(device, time, |
| BTN_MIDDLE, |
| LIBINPUT_BUTTON_STATE_PRESSED); |
| middlebutton_set_state(device, MIDDLEBUTTON_MIDDLE, time); |
| break; |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_R, time); |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_UP: |
| middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time); |
| break; |
| case MIDDLEBUTTON_EVENT_L_UP: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| middlebutton_state_error(device, event); |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_passthrough_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| case MIDDLEBUTTON_EVENT_OTHER: |
| case MIDDLEBUTTON_EVENT_R_UP: |
| case MIDDLEBUTTON_EVENT_L_UP: |
| return 0; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| middlebutton_set_state(device, MIDDLEBUTTON_IDLE, time); |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_ignore_lr_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_UP: |
| middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_L, time); |
| break; |
| case MIDDLEBUTTON_EVENT_L_UP: |
| middlebutton_set_state(device, MIDDLEBUTTON_IGNORE_R, time); |
| break; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| middlebutton_state_error(device, event); |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_ignore_l_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| return 0; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| case MIDDLEBUTTON_EVENT_R_UP: |
| return 0; |
| case MIDDLEBUTTON_EVENT_L_UP: |
| middlebutton_set_state(device, |
| MIDDLEBUTTON_PASSTHROUGH, |
| time); |
| break; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| middlebutton_state_error(device, event); |
| break; |
| } |
| |
| return 1; |
| } |
| static int |
| evdev_middlebutton_ignore_r_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| switch (event) { |
| case MIDDLEBUTTON_EVENT_L_DOWN: |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_DOWN: |
| middlebutton_state_error(device, event); |
| break; |
| case MIDDLEBUTTON_EVENT_OTHER: |
| return 0; |
| case MIDDLEBUTTON_EVENT_R_UP: |
| middlebutton_set_state(device, |
| MIDDLEBUTTON_PASSTHROUGH, |
| time); |
| break; |
| case MIDDLEBUTTON_EVENT_L_UP: |
| return 0; |
| case MIDDLEBUTTON_EVENT_TIMEOUT: |
| case MIDDLEBUTTON_EVENT_ALL_UP: |
| break; |
| } |
| |
| return 1; |
| } |
| |
| static int |
| evdev_middlebutton_handle_event(struct evdev_device *device, |
| uint64_t time, |
| enum evdev_middlebutton_event event) |
| { |
| int rc; |
| enum evdev_middlebutton_state current; |
| |
| current = device->middlebutton.state; |
| |
| switch (current) { |
| case MIDDLEBUTTON_IDLE: |
| rc = evdev_middlebutton_idle_handle_event(device, time, event); |
| break; |
| case MIDDLEBUTTON_LEFT_DOWN: |
| rc = evdev_middlebutton_ldown_handle_event(device, time, event); |
| break; |
| case MIDDLEBUTTON_RIGHT_DOWN: |
| rc = evdev_middlebutton_rdown_handle_event(device, time, event); |
| break; |
| case MIDDLEBUTTON_MIDDLE: |
| rc = evdev_middlebutton_middle_handle_event(device, time, event); |
| break; |
| case MIDDLEBUTTON_LEFT_UP_PENDING: |
| rc = evdev_middlebutton_lup_pending_handle_event(device, |
| time, |
| event); |
| break; |
| case MIDDLEBUTTON_RIGHT_UP_PENDING: |
| rc = evdev_middlebutton_rup_pending_handle_event(device, |
| time, |
| event); |
| break; |
| case MIDDLEBUTTON_PASSTHROUGH: |
| rc = evdev_middlebutton_passthrough_handle_event(device, |
| time, |
| event); |
| break; |
| case MIDDLEBUTTON_IGNORE_LR: |
| rc = evdev_middlebutton_ignore_lr_handle_event(device, |
| time, |
| event); |
| break; |
| case MIDDLEBUTTON_IGNORE_L: |
| rc = evdev_middlebutton_ignore_l_handle_event(device, |
| time, |
| event); |
| break; |
| case MIDDLEBUTTON_IGNORE_R: |
| rc = evdev_middlebutton_ignore_r_handle_event(device, |
| time, |
| event); |
| break; |
| } |
| |
| log_debug(device->base.seat->libinput, |
| "middlebuttonstate: %s → %s → %s, rc %d\n", |
| middlebutton_state_to_str(current), |
| middlebutton_event_to_str(event), |
| middlebutton_state_to_str(device->middlebutton.state), |
| rc); |
| |
| return rc; |
| } |
| |
| static inline void |
| evdev_middlebutton_apply_config(struct evdev_device *device) |
| { |
| if (device->middlebutton.want_enabled == |
| device->middlebutton.enabled) |
| return; |
| |
| if (device->middlebutton.button_mask != 0) |
| return; |
| |
| device->middlebutton.enabled = device->middlebutton.want_enabled; |
| } |
| |
| bool |
| evdev_middlebutton_filter_button(struct evdev_device *device, |
| uint64_t time, |
| int button, |
| enum libinput_button_state state) |
| { |
| enum evdev_middlebutton_event event; |
| bool is_press = state == LIBINPUT_BUTTON_STATE_PRESSED; |
| int rc; |
| unsigned int bit = (button - BTN_LEFT); |
| uint32_t old_mask = 0; |
| |
| if (!device->middlebutton.enabled) |
| return false; |
| |
| switch (button) { |
| case BTN_LEFT: |
| if (is_press) |
| event = MIDDLEBUTTON_EVENT_L_DOWN; |
| else |
| event = MIDDLEBUTTON_EVENT_L_UP; |
| break; |
| case BTN_RIGHT: |
| if (is_press) |
| event = MIDDLEBUTTON_EVENT_R_DOWN; |
| else |
| event = MIDDLEBUTTON_EVENT_R_UP; |
| break; |
| |
| /* BTN_MIDDLE counts as "other" and resets middle button |
| * emulation */ |
| case BTN_MIDDLE: |
| default: |
| event = MIDDLEBUTTON_EVENT_OTHER; |
| break; |
| } |
| |
| if (button < BTN_LEFT || |
| bit >= sizeof(device->middlebutton.button_mask) * 8) { |
| log_bug_libinput(device->base.seat->libinput, |
| "Button mask too small for %s\n", |
| libevdev_event_code_get_name(EV_KEY, |
| button)); |
| return true; |
| } |
| |
| rc = evdev_middlebutton_handle_event(device, time, event); |
| |
| old_mask = device->middlebutton.button_mask; |
| if (is_press) |
| device->middlebutton.button_mask |= 1 << bit; |
| else |
| device->middlebutton.button_mask &= ~(1 << bit); |
| |
| if (old_mask != device->middlebutton.button_mask && |
| device->middlebutton.button_mask == 0) { |
| evdev_middlebutton_handle_event(device, |
| time, |
| MIDDLEBUTTON_EVENT_ALL_UP); |
| evdev_middlebutton_apply_config(device); |
| } |
| |
| return rc; |
| } |
| |
| static void |
| evdev_middlebutton_handle_timeout(uint64_t now, void *data) |
| { |
| struct evdev_device *device = (struct evdev_device*)data; |
| |
| evdev_middlebutton_handle_event(device, now, MIDDLEBUTTON_EVENT_TIMEOUT); |
| } |
| |
| static int |
| evdev_middlebutton_is_available(struct libinput_device *device) |
| { |
| return 1; |
| } |
| |
| static enum libinput_config_status |
| evdev_middlebutton_set(struct libinput_device *device, |
| enum libinput_config_middle_emulation_state enable) |
| { |
| struct evdev_device *evdev = (struct evdev_device*)device; |
| |
| switch (enable) { |
| case LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED: |
| evdev->middlebutton.want_enabled = true; |
| break; |
| case LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED: |
| evdev->middlebutton.want_enabled = false; |
| break; |
| default: |
| return LIBINPUT_CONFIG_STATUS_INVALID; |
| } |
| |
| evdev_middlebutton_apply_config(evdev); |
| |
| return LIBINPUT_CONFIG_STATUS_SUCCESS; |
| } |
| |
| static enum libinput_config_middle_emulation_state |
| evdev_middlebutton_get(struct libinput_device *device) |
| { |
| struct evdev_device *evdev = (struct evdev_device*)device; |
| |
| return evdev->middlebutton.enabled ? |
| LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED : |
| LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; |
| } |
| |
| static enum libinput_config_middle_emulation_state |
| evdev_middlebutton_get_default(struct libinput_device *device) |
| { |
| struct evdev_device *evdev = (struct evdev_device*)device; |
| |
| return evdev->middlebutton.enabled_default ? |
| LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED : |
| LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; |
| } |
| |
| void |
| evdev_init_middlebutton(struct evdev_device *device, |
| bool enable, |
| bool want_config) |
| { |
| libinput_timer_init(&device->middlebutton.timer, |
| device->base.seat->libinput, |
| evdev_middlebutton_handle_timeout, |
| device); |
| device->middlebutton.enabled_default = enable; |
| device->middlebutton.want_enabled = enable; |
| device->middlebutton.enabled = enable; |
| |
| if (!want_config) |
| return; |
| |
| device->middlebutton.config.available = evdev_middlebutton_is_available; |
| device->middlebutton.config.set = evdev_middlebutton_set; |
| device->middlebutton.config.get = evdev_middlebutton_get; |
| device->middlebutton.config.get_default = evdev_middlebutton_get_default; |
| device->base.config.middle_emulation = &device->middlebutton.config; |
| } |