summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/switches.dox16
-rw-r--r--src/Makefile.am1
-rw-r--r--src/evdev-lid.c302
-rw-r--r--src/evdev-middle-button.c8
-rw-r--r--src/evdev-mt-touchpad-buttons.c10
-rw-r--r--src/evdev-mt-touchpad-tap.c58
-rw-r--r--src/evdev-mt-touchpad.c87
-rw-r--r--src/evdev-mt-touchpad.h15
-rw-r--r--src/evdev-tablet-pad.c11
-rw-r--r--src/evdev-tablet-pad.h10
-rw-r--r--src/evdev-tablet.c21
-rw-r--r--src/evdev-tablet.h10
-rw-r--r--src/evdev.c144
-rw-r--r--src/evdev.h44
-rw-r--r--src/libinput-private.h8
-rw-r--r--src/libinput-util.c19
-rw-r--r--src/libinput-util.h10
-rw-r--r--src/libinput.c147
-rw-r--r--src/libinput.h116
-rw-r--r--src/libinput.sym9
-rw-r--r--src/path-seat.c6
-rw-r--r--src/udev-seat.c4
-rw-r--r--test/Makefile.am5
-rw-r--r--test/litest-device-lid-switch-surface3.c71
-rw-r--r--test/litest-device-lid-switch.c70
-rw-r--r--test/litest.c35
-rw-r--r--test/litest.h12
-rw-r--r--test/test-device.c3
-rw-r--r--test/test-lid.c473
-rw-r--r--test/test-misc.c90
-rw-r--r--tools/event-debug.c31
-rw-r--r--tools/event-gui.c2
-rw-r--r--udev/90-libinput-model-quirks.hwdb17
-rwxr-xr-xudev/parse_hwdb.py8
35 files changed, 1697 insertions, 177 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 698a316..a92d791 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -22,6 +22,7 @@ header_files = \
$(srcdir)/reporting-bugs.dox \
$(srcdir)/scrolling.dox \
$(srcdir)/seats.dox \
+ $(srcdir)/switches.dox \
$(srcdir)/t440-support.dox \
$(srcdir)/tablet-support.dox \
$(srcdir)/tapping.dox \
diff --git a/doc/switches.dox b/doc/switches.dox
new file mode 100644
index 0000000..4bb2675
--- /dev/null
+++ b/doc/switches.dox
@@ -0,0 +1,16 @@
+/**
+@page switches Switches
+
+libinput supports a couple of switches. Unlike button events that come in
+press and release pairs, switches are usually toggled once and left at the
+setting for an extended period of time.
+
+Only some switches are handled by libinput, see @ref libinput_switch for a
+list of supported switches. Switch events are exposed to the caller, but
+libinput may handle some switch events internally and enable or disable
+specific features based on a switch state.
+
+The order of switch events is guaranteed to be correct, i.e., a switch will
+never send consecutive switch on, or switch off, events.
+
+*/
diff --git a/src/Makefile.am b/src/Makefile.am
index a7ce472..08e6aa1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,6 +11,7 @@ libinput_la_SOURCES = \
libinput-private.h \
evdev.c \
evdev.h \
+ evdev-lid.c \
evdev-middle-button.c \
evdev-mt-touchpad.c \
evdev-mt-touchpad.h \
diff --git a/src/evdev-lid.c b/src/evdev-lid.c
new file mode 100644
index 0000000..6a2b506
--- /dev/null
+++ b/src/evdev-lid.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright © 2017 James Ye <jye836@gmail.com>
+ * Copyright © 2017 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 "libinput.h"
+#include "evdev.h"
+#include "libinput-private.h"
+
+struct lid_switch_dispatch {
+ struct evdev_dispatch base;
+ struct evdev_device *device;
+ enum switch_reliability reliability;
+
+ bool lid_is_closed;
+
+ struct {
+ struct evdev_device *keyboard;
+ struct libinput_event_listener listener;
+ } keyboard;
+};
+
+static inline struct lid_switch_dispatch*
+lid_dispatch(struct evdev_dispatch *dispatch)
+{
+ struct lid_switch_dispatch *l;
+
+ evdev_verify_dispatch_type(dispatch, DISPATCH_LID_SWITCH);
+
+ return container_of(dispatch, l, base);
+}
+
+static void
+lid_switch_keyboard_event(uint64_t time,
+ struct libinput_event *event,
+ void *data)
+{
+ struct lid_switch_dispatch *dispatch = lid_dispatch(data);
+
+ if (!dispatch->lid_is_closed)
+ return;
+
+ if (event->type != LIBINPUT_EVENT_KEYBOARD_KEY)
+ return;
+
+ if (dispatch->reliability == RELIABILITY_WRITE_OPEN) {
+ int fd = libevdev_get_fd(dispatch->device->evdev);
+ struct input_event ev[2] = {
+ {{ 0, 0 }, EV_SW, SW_LID, 0 },
+ {{ 0, 0 }, EV_SYN, SYN_REPORT, 0 },
+ };
+
+ (void)write(fd, ev, sizeof(ev));
+ /* In case write() fails, we sync the lid state manually
+ * regardless. */
+ }
+
+ dispatch->lid_is_closed = false;
+ switch_notify_toggle(&dispatch->device->base,
+ time,
+ LIBINPUT_SWITCH_LID,
+ dispatch->lid_is_closed);
+}
+
+static void
+lid_switch_toggle_keyboard_listener(struct lid_switch_dispatch *dispatch,
+ bool is_closed)
+{
+ if (!dispatch->keyboard.keyboard)
+ return;
+
+ if (is_closed) {
+ libinput_device_add_event_listener(
+ &dispatch->keyboard.keyboard->base,
+ &dispatch->keyboard.listener,
+ lid_switch_keyboard_event,
+ dispatch);
+ } else {
+ libinput_device_remove_event_listener(
+ &dispatch->keyboard.listener);
+ }
+}
+
+static void
+lid_switch_process_switch(struct lid_switch_dispatch *dispatch,
+ struct evdev_device *device,
+ struct input_event *e,
+ uint64_t time)
+{
+ bool is_closed;
+
+ switch (e->code) {
+ case SW_LID:
+ is_closed = !!e->value;
+
+ if (dispatch->lid_is_closed == is_closed)
+ return;
+
+ lid_switch_toggle_keyboard_listener(dispatch,
+ is_closed);
+
+ dispatch->lid_is_closed = is_closed;
+
+ switch_notify_toggle(&device->base,
+ time,
+ LIBINPUT_SWITCH_LID,
+ dispatch->lid_is_closed);
+ break;
+ }
+}
+
+static void
+lid_switch_process(struct evdev_dispatch *evdev_dispatch,
+ struct evdev_device *device,
+ struct input_event *event,
+ uint64_t time)
+{
+ struct lid_switch_dispatch *dispatch = lid_dispatch(evdev_dispatch);
+
+ switch (event->type) {
+ case EV_SW:
+ lid_switch_process_switch(dispatch, device, event, time);
+ break;
+ case EV_SYN:
+ break;
+ default:
+ assert(0 && "Unknown event type");
+ break;
+ }
+}
+
+static inline enum switch_reliability
+evdev_read_switch_reliability_prop(struct evdev_device *device)
+{
+ const char *prop;
+ enum switch_reliability r;
+
+ prop = udev_device_get_property_value(device->udev_device,
+ "LIBINPUT_ATTR_LID_SWITCH_RELIABILITY");
+ if (!parse_switch_reliability_property(prop, &r)) {
+ log_error(evdev_libinput_context(device),
+ "%s: switch reliability set to unknown value '%s'\n",
+ device->devname,
+ prop);
+ r = RELIABILITY_UNKNOWN;
+ } else if (r == RELIABILITY_WRITE_OPEN) {
+ log_info(evdev_libinput_context(device),
+ "%s: will write switch open events\n",
+ device->devname);
+ }
+
+ return r;
+}
+
+static void
+lid_switch_destroy(struct evdev_dispatch *evdev_dispatch)
+{
+ struct lid_switch_dispatch *dispatch = lid_dispatch(evdev_dispatch);
+
+ free(dispatch);
+}
+
+static void
+lid_switch_pair_keyboard(struct evdev_device *lid_switch,
+ struct evdev_device *keyboard)
+{
+ struct lid_switch_dispatch *dispatch =
+ lid_dispatch(lid_switch->dispatch);
+ unsigned int bus_kbd = libevdev_get_id_bustype(keyboard->evdev);
+
+ if ((keyboard->tags & EVDEV_TAG_KEYBOARD) == 0)
+ return;
+
+ /* If we already have a keyboard paired, override it if the new one
+ * is a serio device. Otherwise keep the current one */
+ if (dispatch->keyboard.keyboard) {
+ if (bus_kbd != BUS_I8042)
+ return;
+ libinput_device_remove_event_listener(&dispatch->keyboard.listener);
+ }
+
+ dispatch->keyboard.keyboard = keyboard;
+ log_debug(evdev_libinput_context(lid_switch),
+ "lid: keyboard paired with %s<->%s\n",
+ lid_switch->devname,
+ keyboard->devname);
+
+ /* We don't init the event listener yet - we don't care about
+ * keyboard events until the lid is closed */
+}
+
+static void
+lid_switch_interface_device_added(struct evdev_device *device,
+ struct evdev_device *added_device)
+{
+ lid_switch_pair_keyboard(device, added_device);
+}
+
+static void
+lid_switch_interface_device_removed(struct evdev_device *device,
+ struct evdev_device *removed_device)
+{
+ struct lid_switch_dispatch *dispatch = lid_dispatch(device->dispatch);
+
+ if (removed_device == dispatch->keyboard.keyboard) {
+ libinput_device_remove_event_listener(
+ &dispatch->keyboard.listener);
+ dispatch->keyboard.keyboard = NULL;
+ }
+}
+
+static void
+lid_switch_sync_initial_state(struct evdev_device *device,
+ struct evdev_dispatch *evdev_dispatch)
+{
+ struct lid_switch_dispatch *dispatch = lid_dispatch(device->dispatch);
+ struct libevdev *evdev = device->evdev;
+ bool is_closed = false;
+
+ dispatch->reliability = evdev_read_switch_reliability_prop(device);
+
+ /* For the initial state sync, we depend on whether the lid switch
+ * is reliable. If we know it's reliable, we sync as expected.
+ * If we're not sure, we ignore the initial state and only sync on
+ * the first future lid close event. Laptops with a broken switch
+ * that always have the switch in 'on' state thus don't mess up our
+ * touchpad.
+ */
+ switch(dispatch->reliability) {
+ case RELIABILITY_UNKNOWN:
+ case RELIABILITY_WRITE_OPEN:
+ is_closed = false;
+ break;
+ case RELIABILITY_RELIABLE:
+ is_closed = libevdev_get_event_value(evdev, EV_SW, SW_LID);
+ break;
+ }
+
+ dispatch->lid_is_closed = is_closed;
+ if (dispatch->lid_is_closed) {
+ uint64_t time;
+ time = libinput_now(evdev_libinput_context(device));
+ switch_notify_toggle(&device->base,
+ time,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_ON);
+ }
+}
+
+struct evdev_dispatch_interface lid_switch_interface = {
+ lid_switch_process,
+ NULL, /* suspend */
+ NULL, /* remove */
+ lid_switch_destroy,
+ lid_switch_interface_device_added,
+ lid_switch_interface_device_removed,
+ lid_switch_interface_device_removed, /* device_suspended, treat as remove */
+ lid_switch_interface_device_added, /* device_resumed, treat as add */
+ lid_switch_sync_initial_state,
+ NULL, /* toggle_touch */
+};
+
+struct evdev_dispatch *
+evdev_lid_switch_dispatch_create(struct evdev_device *lid_device)
+{
+ struct lid_switch_dispatch *dispatch = zalloc(sizeof *dispatch);
+
+ if (dispatch == NULL)
+ return NULL;
+
+ dispatch->base.dispatch_type = DISPATCH_LID_SWITCH;
+ dispatch->base.interface = &lid_switch_interface;
+ dispatch->device = lid_device;
+ libinput_device_init_event_listener(&dispatch->keyboard.listener);
+
+ evdev_init_sendevents(lid_device, &dispatch->base);
+
+ dispatch->lid_is_closed = false;
+
+ return &dispatch->base;
+}
diff --git a/src/evdev-middle-button.c b/src/evdev-middle-button.c
index 09f77de..d9330ba 100644
--- a/src/evdev-middle-button.c
+++ b/src/evdev-middle-button.c
@@ -638,7 +638,7 @@ evdev_middlebutton_filter_button(struct evdev_device *device,
static void
evdev_middlebutton_handle_timeout(uint64_t now, void *data)
{
- struct evdev_device *device = (struct evdev_device*)data;
+ struct evdev_device *device = evdev_device(data);
evdev_middlebutton_handle_event(device, now, MIDDLEBUTTON_EVENT_TIMEOUT);
}
@@ -653,7 +653,7 @@ 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;
+ struct evdev_device *evdev = evdev_device(device);
switch (enable) {
case LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED:
@@ -674,7 +674,7 @@ evdev_middlebutton_set(struct libinput_device *device,
enum libinput_config_middle_emulation_state
evdev_middlebutton_get(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
return evdev->middlebutton.want_enabled ?
LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED :
@@ -684,7 +684,7 @@ evdev_middlebutton_get(struct libinput_device *device)
enum libinput_config_middle_emulation_state
evdev_middlebutton_get_default(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
return evdev->middlebutton.enabled_default ?
LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED :
diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index f4fe6b7..4a68470 100644
--- a/src/evdev-mt-touchpad-buttons.c
+++ b/src/evdev-mt-touchpad-buttons.c
@@ -627,7 +627,7 @@ tp_init_top_softbuttons(struct tp_dispatch *tp,
static inline uint32_t
tp_button_config_click_get_methods(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
uint32_t methods = LIBINPUT_CONFIG_CLICK_METHOD_NONE;
@@ -669,7 +669,7 @@ static enum libinput_config_status
tp_button_config_click_set_method(struct libinput_device *device,
enum libinput_config_click_method method)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
tp->buttons.click_method = method;
@@ -681,7 +681,7 @@ tp_button_config_click_set_method(struct libinput_device *device,
static enum libinput_config_click_method
tp_button_config_click_get_method(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp->buttons.click_method;
@@ -711,7 +711,7 @@ tp_click_get_default_method(struct tp_dispatch *tp)
static enum libinput_config_click_method
tp_button_config_click_get_default_method(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp_click_get_default_method(tp);
@@ -746,7 +746,7 @@ static enum libinput_config_status
tp_clickpad_middlebutton_set(struct libinput_device *device,
enum libinput_config_middle_emulation_state enable)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
switch (enable) {
case LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED:
diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c
index 9fba521..1829732 100644
--- a/src/evdev-mt-touchpad-tap.c
+++ b/src/evdev-mt-touchpad-tap.c
@@ -897,11 +897,8 @@ tp_tap_enabled_update(struct tp_dispatch *tp, bool suspended, bool enabled, uint
static int
tp_tap_config_count(struct libinput_device *device)
{
- struct evdev_dispatch *dispatch;
- struct tp_dispatch *tp = NULL;
-
- dispatch = ((struct evdev_device *) device)->dispatch;
- tp = container_of(dispatch, tp, base);
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
return min(tp->ntouches, 3U); /* we only do up to 3 finger tap */
}
@@ -910,10 +907,9 @@ static enum libinput_config_status
tp_tap_config_set_enabled(struct libinput_device *device,
enum libinput_config_tap_state enabled)
{
- struct evdev_dispatch *dispatch = ((struct evdev_device *) device)->dispatch;
- struct tp_dispatch *tp = NULL;
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
- tp = container_of(dispatch, tp, base);
tp_tap_enabled_update(tp, tp->tap.suspended,
(enabled == LIBINPUT_CONFIG_TAP_ENABLED),
libinput_now(device->seat->libinput));
@@ -924,11 +920,8 @@ tp_tap_config_set_enabled(struct libinput_device *device,
static enum libinput_config_tap_state
tp_tap_config_is_enabled(struct libinput_device *device)
{
- struct evdev_dispatch *dispatch;
- struct tp_dispatch *tp = NULL;
-
- dispatch = ((struct evdev_device *) device)->dispatch;
- tp = container_of(dispatch, tp, base);
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
return tp->tap.enabled ? LIBINPUT_CONFIG_TAP_ENABLED :
LIBINPUT_CONFIG_TAP_DISABLED;
@@ -959,7 +952,7 @@ tp_tap_default(struct evdev_device *evdev)
static enum libinput_config_tap_state
tp_tap_config_get_default(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
return tp_tap_default(evdev);
}
@@ -968,10 +961,9 @@ static enum libinput_config_status
tp_tap_config_set_map(struct libinput_device *device,
enum libinput_config_tap_button_map map)
{
- struct evdev_dispatch *dispatch = ((struct evdev_device *) device)->dispatch;
- struct tp_dispatch *tp = NULL;
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
- tp = container_of(dispatch, tp, base);
tp->tap.want_map = map;
tp_tap_update_map(tp);
@@ -982,10 +974,8 @@ tp_tap_config_set_map(struct libinput_device *device,
static enum libinput_config_tap_button_map
tp_tap_config_get_map(struct libinput_device *device)
{
- struct evdev_dispatch *dispatch = ((struct evdev_device *) device)->dispatch;
- struct tp_dispatch *tp = NULL;
-
- tp = container_of(dispatch, tp, base);
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
return tp->tap.want_map;
}
@@ -1000,10 +990,9 @@ static enum libinput_config_status
tp_tap_config_set_drag_enabled(struct libinput_device *device,
enum libinput_config_drag_state enabled)
{
- struct evdev_dispatch *dispatch = ((struct evdev_device *) device)->dispatch;
- struct tp_dispatch *tp = NULL;
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
- tp = container_of(dispatch, tp, base);
tp->tap.drag_enabled = enabled;
return LIBINPUT_CONFIG_STATUS_SUCCESS;
@@ -1012,10 +1001,8 @@ tp_tap_config_set_drag_enabled(struct libinput_device *device,
static enum libinput_config_drag_state
tp_tap_config_get_drag_enabled(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
- struct tp_dispatch *tp = NULL;
-
- tp = container_of(evdev->dispatch, tp, base);
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
return tp->tap.drag_enabled;
}
@@ -1029,7 +1016,7 @@ tp_drag_default(struct evdev_device *device)
static enum libinput_config_drag_state
tp_tap_config_get_default_drag_enabled(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
return tp_drag_default(evdev);
}
@@ -1038,10 +1025,9 @@ static enum libinput_config_status
tp_tap_config_set_draglock_enabled(struct libinput_device *device,
enum libinput_config_drag_lock_state enabled)
{
- struct evdev_dispatch *dispatch = ((struct evdev_device *) device)->dispatch;
- struct tp_dispatch *tp = NULL;
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
- tp = container_of(dispatch, tp, base);
tp->tap.drag_lock_enabled = enabled;
return LIBINPUT_CONFIG_STATUS_SUCCESS;
@@ -1050,10 +1036,8 @@ tp_tap_config_set_draglock_enabled(struct libinput_device *device,
static enum libinput_config_drag_lock_state
tp_tap_config_get_draglock_enabled(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
- struct tp_dispatch *tp = NULL;
-
- tp = container_of(evdev->dispatch, tp, base);
+ struct evdev_dispatch *dispatch = evdev_device(device)->dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
return tp->tap.drag_lock_enabled;
}
@@ -1067,7 +1051,7 @@ tp_drag_lock_default(struct evdev_device *device)
static enum libinput_config_drag_lock_state
tp_tap_config_get_default_draglock_enabled(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
return tp_drag_lock_default(evdev);
}
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index e43a9ba..b10ac8b 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -1140,8 +1140,7 @@ tp_interface_process(struct evdev_dispatch *dispatch,
struct input_event *e,
uint64_t time)
{
- struct tp_dispatch *tp =
- (struct tp_dispatch *)dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
if (tp->ignore_events)
return;
@@ -1176,13 +1175,16 @@ tp_remove_sendevents(struct tp_dispatch *tp)
if (tp->dwt.keyboard)
libinput_device_remove_event_listener(
&tp->dwt.keyboard_listener);
+
+ if (tp->lid_switch.lid_switch)
+ libinput_device_remove_event_listener(
+ &tp->lid_switch.lid_switch_listener);
}
static void
tp_interface_remove(struct evdev_dispatch *dispatch)
{
- struct tp_dispatch *tp =
- (struct tp_dispatch*)dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
tp_remove_tap(tp);
tp_remove_buttons(tp);
@@ -1194,8 +1196,7 @@ tp_interface_remove(struct evdev_dispatch *dispatch)
static void
tp_interface_destroy(struct evdev_dispatch *dispatch)
{
- struct tp_dispatch *tp =
- (struct tp_dispatch*)dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
free(tp->touches);
free(tp);
@@ -1257,7 +1258,7 @@ static void
tp_interface_suspend(struct evdev_dispatch *dispatch,
struct evdev_device *device)
{
- struct tp_dispatch *tp = (struct tp_dispatch *)dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
tp_clear_state(tp);
}
@@ -1553,6 +1554,50 @@ tp_pair_trackpoint(struct evdev_device *touchpad,
}
static void
+tp_lid_switch_event(uint64_t time, struct libinput_event *event, void *data)
+{
+ struct tp_dispatch *tp = data;
+ struct libinput_event_switch *swev;
+
+ if (libinput_event_get_type(event) != LIBINPUT_EVENT_SWITCH_TOGGLE)
+ return;
+
+ swev = libinput_event_get_switch_event(event);
+ switch (libinput_event_switch_get_switch_state(swev)) {
+ case LIBINPUT_SWITCH_STATE_OFF:
+ tp_resume(tp, tp->device);
+ log_debug(tp_libinput_context(tp), "lid: resume touchpad\n");
+ break;
+ case LIBINPUT_SWITCH_STATE_ON:
+ tp_suspend(tp, tp->device);
+ log_debug(tp_libinput_context(tp), "lid: suspend touchpad\n");
+ break;
+ }
+}
+
+static void
+tp_pair_lid_switch(struct evdev_device *touchpad,
+ struct evdev_device *lid_switch)
+{
+ struct tp_dispatch *tp = (struct tp_dispatch*)touchpad->dispatch;
+
+ if ((lid_switch->tags & EVDEV_TAG_LID_SWITCH) == 0)
+ return;
+
+ if (tp->lid_switch.lid_switch == NULL) {
+ log_debug(tp_libinput_context(tp),
+ "lid_switch: activated for %s<->%s\n",
+ touchpad->devname,
+ lid_switch->devname);
+
+ libinput_device_add_event_listener(&lid_switch->base,
+ &tp->lid_switch.lid_switch_listener,
+ tp_lid_switch_event, tp);
+ tp->lid_switch.lid_switch = lid_switch;
+ }
+}
+
+static void
tp_interface_device_added(struct evdev_device *device,
struct evdev_device *added_device)
{
@@ -1560,6 +1605,7 @@ tp_interface_device_added(struct evdev_device *device,
tp_pair_trackpoint(device, added_device);
tp_dwt_pair_keyboard(device, added_device);
+ tp_pair_lid_switch(device, added_device);
if (tp->sendevents.current_mode !=
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
@@ -1599,7 +1645,7 @@ tp_interface_device_removed(struct evdev_device *device,
return;
list_for_each(dev, &device->base.seat->devices_list, link) {
- struct evdev_device *d = (struct evdev_device*)dev;
+ struct evdev_device *d = evdev_device(dev);
if (d != removed_device &&
(d->tags & EVDEV_TAG_EXTERNAL_MOUSE)) {
return;
@@ -1693,7 +1739,7 @@ tp_interface_toggle_touch(struct evdev_dispatch *dispatch,
struct evdev_device *device,
bool enable)
{
- struct tp_dispatch *tp = (struct tp_dispatch*)dispatch;
+ struct tp_dispatch *tp = tp_dispatch(dispatch);
bool ignore_events = !enable;
if (ignore_events == tp->ignore_events)
@@ -1936,7 +1982,7 @@ tp_scroll_get_methods(struct tp_dispatch *tp)
static uint32_t
tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp_scroll_get_methods(tp);
@@ -1946,7 +1992,7 @@ static enum libinput_config_status
tp_scroll_config_scroll_method_set_method(struct libinput_device *device,
enum libinput_config_scroll_method method)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
uint64_t time = libinput_now(tp_libinput_context(tp));
@@ -1964,7 +2010,7 @@ tp_scroll_config_scroll_method_set_method(struct libinput_device *device,
static enum libinput_config_scroll_method
tp_scroll_config_scroll_method_get_method(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp->scroll.method;
@@ -1993,7 +2039,7 @@ tp_scroll_get_default_method(struct tp_dispatch *tp)
static enum libinput_config_scroll_method
tp_scroll_config_scroll_method_get_default_method(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp_scroll_get_default_method(tp);
@@ -2028,7 +2074,7 @@ static enum libinput_config_status
tp_dwt_config_set(struct libinput_device *device,
enum libinput_config_dwt_state enable)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
switch(enable) {
@@ -2047,7 +2093,7 @@ tp_dwt_config_set(struct libinput_device *device,
static enum libinput_config_dwt_state
tp_dwt_config_get(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp->dwt.dwt_enabled ?
@@ -2064,7 +2110,7 @@ tp_dwt_default_enabled(struct tp_dispatch *tp)
static enum libinput_config_dwt_state
tp_dwt_config_get_default(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
return tp_dwt_default_enabled(tp) ?
@@ -2271,6 +2317,7 @@ static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
{
+ tp->base.dispatch_type = DISPATCH_TOUCHPAD;
tp->base.interface = &tp_interface;
tp->device = device;
@@ -2316,7 +2363,7 @@ tp_init(struct tp_dispatch *tp,
static uint32_t
tp_sendevents_get_modes(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
if (evdev->tags & EVDEV_TAG_INTERNAL_TOUCHPAD)
@@ -2332,7 +2379,7 @@ tp_suspend_conditional(struct tp_dispatch *tp,
struct libinput_device *dev;
list_for_each(dev, &device->base.seat->devices_list, link) {
- struct evdev_device *d = (struct evdev_device*)dev;
+ struct evdev_device *d = evdev_device(dev);
if (d->tags & EVDEV_TAG_EXTERNAL_MOUSE) {
tp_suspend(tp, device);
return;
@@ -2344,7 +2391,7 @@ static enum libinput_config_status
tp_sendevents_set_mode(struct libinput_device *device,
enum libinput_config_send_events_mode mode)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
/* DISABLED overrides any DISABLED_ON_ */
@@ -2377,7 +2424,7 @@ tp_sendevents_set_mode(struct libinput_device *device,
static enum libinput_config_send_events_mode
tp_sendevents_get_mode(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct tp_dispatch *dispatch = (struct tp_dispatch*)evdev->dispatch;
return dispatch->sendevents.current_mode;
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index fb15956..a54eb5c 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -376,8 +376,23 @@ struct tp_dispatch {
*/
unsigned int nonmotion_event_count;
} quirks;
+
+ struct {
+ struct libinput_event_listener lid_switch_listener;
+ struct evdev_device *lid_switch;
+ } lid_switch;
};
+static inline struct tp_dispatch*
+tp_dispatch(struct evdev_dispatch *dispatch)
+{
+ struct tp_dispatch *tp;
+
+ evdev_verify_dispatch_type(dispatch, DISPATCH_TOUCHPAD);
+
+ return container_of(dispatch, tp, base);
+}
+
#define tp_for_each_touch(_tp, _t) \
for (unsigned int _i = 0; _i < (_tp)->ntouches && (_t = &(_tp)->touches[_i]); _i++)
diff --git a/src/evdev-tablet-pad.c b/src/evdev-tablet-pad.c
index 82542bc..bed43b6 100644
--- a/src/evdev-tablet-pad.c
+++ b/src/evdev-tablet-pad.c
@@ -452,7 +452,7 @@ pad_process(struct evdev_dispatch *dispatch,
struct input_event *e,
uint64_t time)
{
- struct pad_dispatch *pad = (struct pad_dispatch *)dispatch;
+ struct pad_dispatch *pad = pad_dispatch(dispatch);
switch (e->type) {
case EV_ABS:
@@ -481,7 +481,7 @@ static void
pad_suspend(struct evdev_dispatch *dispatch,
struct evdev_device *device)
{
- struct pad_dispatch *pad = (struct pad_dispatch *)dispatch;
+ struct pad_dispatch *pad = pad_dispatch(dispatch);
struct libinput *libinput = pad_libinput_context(pad);
unsigned int code;
@@ -496,7 +496,7 @@ pad_suspend(struct evdev_dispatch *dispatch,
static void
pad_destroy(struct evdev_dispatch *dispatch)
{
- struct pad_dispatch *pad = (struct pad_dispatch*)dispatch;
+ struct pad_dispatch *pad = pad_dispatch(dispatch);
pad_destroy_leds(pad);
free(pad);
@@ -556,6 +556,7 @@ pad_init_left_handed(struct evdev_device *device)
static int
pad_init(struct pad_dispatch *pad, struct evdev_device *device)
{
+ pad->base.dispatch_type = DISPATCH_TABLET_PAD;
pad->base.interface = &pad_interface;
pad->device = device;
pad->status = PAD_NONE;
@@ -579,7 +580,7 @@ static enum libinput_config_status
pad_sendevents_set_mode(struct libinput_device *device,
enum libinput_config_send_events_mode mode)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct pad_dispatch *pad = (struct pad_dispatch*)evdev->dispatch;
if (mode == pad->sendevents.current_mode)
@@ -603,7 +604,7 @@ pad_sendevents_set_mode(struct libinput_device *device,
static enum libinput_config_send_events_mode
pad_sendevents_get_mode(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct pad_dispatch *dispatch = (struct pad_dispatch*)evdev->dispatch;
return dispatch->sendevents.current_mode;
diff --git a/src/evdev-tablet-pad.h b/src/evdev-tablet-pad.h
index 9002fca..5569007 100644
--- a/src/evdev-tablet-pad.h
+++ b/src/evdev-tablet-pad.h
@@ -70,6 +70,16 @@ struct pad_dispatch {
} modes;
};
+static inline struct pad_dispatch*
+pad_dispatch(struct evdev_dispatch *dispatch)
+{
+ struct pad_dispatch *p;
+
+ evdev_verify_dispatch_type(dispatch, DISPATCH_TABLET_PAD);
+
+ return container_of(dispatch, p, base);
+}
+
static inline struct libinput *
pad_libinput_context(const struct pad_dispatch *pad)
{
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index b76d8ea..12a014b 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -201,8 +201,7 @@ tablet_process_absolute(struct tablet_dispatch *tablet,
static void
tablet_change_to_left_handed(struct evdev_device *device)
{
- struct tablet_dispatch *tablet =
- (struct tablet_dispatch*)device->dispatch;
+ struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
if (device->left_handed.enabled == device->left_handed.want_enabled)
return;
@@ -1484,8 +1483,7 @@ tablet_process(struct evdev_dispatch *dispatch,
struct input_event *e,
uint64_t time)
{
- struct tablet_dispatch *tablet =
- (struct tablet_dispatch *)dispatch;
+ struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
switch (e->type) {
case EV_ABS:
@@ -1518,8 +1516,7 @@ static void
tablet_suspend(struct evdev_dispatch *dispatch,
struct evdev_device *device)
{
- struct tablet_dispatch *tablet =
- (struct tablet_dispatch *)dispatch;
+ struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
tablet_set_touch_device_enabled(tablet->touch_device, true);
}
@@ -1527,8 +1524,7 @@ tablet_suspend(struct evdev_dispatch *dispatch,
static void
tablet_destroy(struct evdev_dispatch *dispatch)
{
- struct tablet_dispatch *tablet =
- (struct tablet_dispatch*)dispatch;
+ struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
struct libinput_tablet_tool *tool, *tmp;
list_for_each_safe(tool, tmp, &tablet->tool_list, link) {
@@ -1542,8 +1538,7 @@ static void
tablet_device_added(struct evdev_device *device,
struct evdev_device *added_device)
{
- struct tablet_dispatch *tablet =
- (struct tablet_dispatch*)device->dispatch;
+ struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
if (libinput_device_get_device_group(&device->base) !=
libinput_device_get_device_group(&added_device->base))
@@ -1560,8 +1555,7 @@ static void
tablet_device_removed(struct evdev_device *device,
struct evdev_device *removed_device)
{
- struct tablet_dispatch *tablet =
- (struct tablet_dispatch*)device->dispatch;
+ struct tablet_dispatch *tablet = tablet_dispatch(device->dispatch);
if (tablet->touch_device == removed_device)
tablet->touch_device = NULL;
@@ -1571,10 +1565,10 @@ static void
tablet_check_initial_proximity(struct evdev_device *device,
struct evdev_dispatch *dispatch)
{
+ struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
bool tool_in_prox = false;
int code, state;
enum libinput_tablet_tool_type tool;
- struct tablet_dispatch *tablet = (struct tablet_dispatch*)dispatch;
for (tool = LIBINPUT_TABLET_TOOL_TYPE_PEN; tool <= LIBINPUT_TABLET_TOOL_TYPE_MAX; tool++) {
code = tablet_tool_to_evcode(tool);
@@ -1746,6 +1740,7 @@ tablet_init(struct tablet_dispatch *tablet,
enum libinput_tablet_tool_axis axis;
int rc;
+ tablet->base.dispatch_type = DISPATCH_TABLET;
tablet->base.interface = &tablet_interface;
tablet->device = device;
tablet->status = TABLET_NONE;
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index 2279e03..2b2b1a7 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -76,6 +76,16 @@ struct tablet_dispatch {
struct evdev_device *touch_device;
};
+static inline struct tablet_dispatch*
+tablet_dispatch(struct evdev_dispatch *dispatch)
+{
+ struct tablet_dispatch *t;
+
+ evdev_verify_dispatch_type(dispatch, DISPATCH_TABLET);
+
+ return container_of(dispatch, t, base);
+}
+
static inline enum libinput_tablet_tool_axis
evcode_to_axis(const uint32_t evcode)
{
diff --git a/src/evdev.c b/src/evdev.c
index d086c18..afee590 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -68,6 +68,7 @@ enum evdev_device_udev_tags {
EVDEV_UDEV_TAG_TABLET_PAD = (1 << 8),
EVDEV_UDEV_TAG_POINTINGSTICK = (1 << 9),
EVDEV_UDEV_TAG_TRACKBALL = (1 << 10),
+ EVDEV_UDEV_TAG_SWITCH = (1 << 11),
};
struct evdev_udev_tag_match {
@@ -88,6 +89,7 @@ static const struct evdev_udev_tag_match evdev_udev_tag_matches[] = {
{"ID_INPUT_ACCELEROMETER", EVDEV_UDEV_TAG_ACCELEROMETER},
{"ID_INPUT_POINTINGSTICK", EVDEV_UDEV_TAG_POINTINGSTICK},
{"ID_INPUT_TRACKBALL", EVDEV_UDEV_TAG_TRACKBALL},
+ {"ID_INPUT_SWITCH", EVDEV_UDEV_TAG_SWITCH},
/* sentinel value */
{ 0 },
@@ -1083,12 +1085,19 @@ evdev_tag_keyboard(struct evdev_device *device,
}
static void
+evdev_tag_lid_switch(struct evdev_device *device,
+ struct udev_device *udev_device)
+{
+ device->tags |= EVDEV_TAG_LID_SWITCH;
+}
+
+static void
fallback_process(struct evdev_dispatch *evdev_dispatch,
struct evdev_device *device,
struct input_event *event,
uint64_t time)
{
- struct fallback_dispatch *dispatch = (struct fallback_dispatch*)evdev_dispatch;
+ struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
enum evdev_event_type sent;
if (dispatch->ignore_events)
@@ -1217,7 +1226,7 @@ static void
fallback_suspend(struct evdev_dispatch *evdev_dispatch,
struct evdev_device *device)
{
- struct fallback_dispatch *dispatch = (struct fallback_dispatch*)evdev_dispatch;
+ struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
fallback_return_to_neutral_state(dispatch, device);
}
@@ -1227,7 +1236,7 @@ fallback_toggle_touch(struct evdev_dispatch *evdev_dispatch,
struct evdev_device *device,
bool enable)
{
- struct fallback_dispatch *dispatch = (struct fallback_dispatch*)evdev_dispatch;
+ struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
bool ignore_events = !enable;
if (ignore_events == dispatch->ignore_events)
@@ -1242,7 +1251,7 @@ fallback_toggle_touch(struct evdev_dispatch *evdev_dispatch,
static void
fallback_destroy(struct evdev_dispatch *evdev_dispatch)
{
- struct fallback_dispatch *dispatch = (struct fallback_dispatch*)evdev_dispatch;
+ struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
free(dispatch->mt.slots);
free(dispatch);
@@ -1251,7 +1260,7 @@ fallback_destroy(struct evdev_dispatch *evdev_dispatch)
static int
evdev_calibration_has_matrix(struct libinput_device *libinput_device)
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
+ struct evdev_device *device = evdev_device(libinput_device);
return device->abs.absinfo_x && device->abs.absinfo_y;
}
@@ -1260,7 +1269,7 @@ static enum libinput_config_status
evdev_calibration_set_matrix(struct libinput_device *libinput_device,
const float matrix[6])
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
+ struct evdev_device *device = evdev_device(libinput_device);
evdev_device_calibrate(device, matrix);
@@ -1271,7 +1280,7 @@ static int
evdev_calibration_get_matrix(struct libinput_device *libinput_device,
float matrix[6])
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
+ struct evdev_device *device = evdev_device(libinput_device);
matrix_to_farray6(&device->abs.usermatrix, matrix);
@@ -1282,7 +1291,7 @@ static int
evdev_calibration_get_default_matrix(struct libinput_device *libinput_device,
float matrix[6])
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
+ struct evdev_device *device = evdev_device(libinput_device);
matrix_to_farray6(&device->abs.default_calibration, matrix);
@@ -1312,7 +1321,7 @@ static enum libinput_config_status
evdev_sendevents_set_mode(struct libinput_device *device,
enum libinput_config_send_events_mode mode)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct evdev_dispatch *dispatch = evdev->dispatch;
if (mode == dispatch->sendevents.current_mode)
@@ -1337,7 +1346,7 @@ evdev_sendevents_set_mode(struct libinput_device *device,
static enum libinput_config_send_events_mode
evdev_sendevents_get_mode(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct evdev_dispatch *dispatch = evdev->dispatch;
return dispatch->sendevents.current_mode;
@@ -1360,7 +1369,7 @@ evdev_left_handed_has(struct libinput_device *device)
static void
evdev_change_to_left_handed(struct evdev_device *device)
{
- struct fallback_dispatch *dispatch = (struct fallback_dispatch*)device->dispatch;
+ struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
if (device->left_handed.want_enabled == device->left_handed.enabled)
return;
@@ -1374,11 +1383,11 @@ evdev_change_to_left_handed(struct evdev_device *device)
static enum libinput_config_status
evdev_left_handed_set(struct libinput_device *device, int left_handed)
{
- struct evdev_device *evdev_device = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
- evdev_device->left_handed.want_enabled = left_handed ? true : false;
+ evdev->left_handed.want_enabled = left_handed ? true : false;
- evdev_device->left_handed.change_to_enabled(evdev_device);
+ evdev->left_handed.change_to_enabled(evdev);
return LIBINPUT_CONFIG_STATUS_SUCCESS;
}
@@ -1386,11 +1395,11 @@ evdev_left_handed_set(struct libinput_device *device, int left_handed)
static int
evdev_left_handed_get(struct libinput_device *device)
{
- struct evdev_device *evdev_device = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
/* return the wanted configuration, even if it hasn't taken
* effect yet! */
- return evdev_device->left_handed.want_enabled;
+ return evdev->left_handed.want_enabled;
}
static int
@@ -1422,7 +1431,7 @@ evdev_scroll_get_methods(struct libinput_device *device)
static void
evdev_change_scroll_method(struct evdev_device *device)
{
- struct fallback_dispatch *dispatch = (struct fallback_dispatch*)device->dispatch;
+ struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
if (device->scroll.want_method == device->scroll.method &&
device->scroll.want_button == device->scroll.button)
@@ -1439,7 +1448,7 @@ static enum libinput_config_status
evdev_scroll_set_method(struct libinput_device *device,
enum libinput_config_scroll_method method)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
evdev->scroll.want_method = method;
evdev->scroll.change_scroll_method(evdev);
@@ -1450,7 +1459,7 @@ evdev_scroll_set_method(struct libinput_device *device,
static enum libinput_config_scroll_method
evdev_scroll_get_method(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
/* return the wanted configuration, even if it hasn't taken
* effect yet! */
@@ -1460,7 +1469,7 @@ evdev_scroll_get_method(struct libinput_device *device)
static enum libinput_config_scroll_method
evdev_scroll_get_default_method(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
if (evdev->tags & EVDEV_TAG_TRACKPOINT)
return LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN;
@@ -1479,7 +1488,7 @@ static enum libinput_config_status
evdev_scroll_set_button(struct libinput_device *device,
uint32_t button)
{
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
evdev->scroll.want_button = button;
evdev->scroll.change_scroll_method(evdev);
@@ -1490,7 +1499,7 @@ evdev_scroll_set_button(struct libinput_device *device,
static uint32_t
evdev_scroll_get_button(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
/* return the wanted configuration, even if it hasn't taken
* effect yet! */
@@ -1500,7 +1509,7 @@ evdev_scroll_get_button(struct libinput_device *device)
static uint32_t
evdev_scroll_get_default_button(struct libinput_device *device)
{
- struct evdev_device *evdev = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
if (libevdev_has_event_code(evdev->evdev, EV_KEY, BTN_MIDDLE))
return BTN_MIDDLE;
@@ -1542,7 +1551,7 @@ evdev_init_calibration(struct evdev_device *device,
calibration->get_default_matrix = evdev_calibration_get_default_matrix;
}
-static void
+void
evdev_init_sendevents(struct evdev_device *device,
struct evdev_dispatch *dispatch)
{
@@ -1565,7 +1574,7 @@ static enum libinput_config_status
evdev_scroll_config_natural_set(struct libinput_device *device,
int enabled)
{
- struct evdev_device *dev = (struct evdev_device *)device;
+ struct evdev_device *dev = evdev_device(device);
dev->scroll.natural_scrolling_enabled = enabled ? true : false;
@@ -1575,7 +1584,7 @@ evdev_scroll_config_natural_set(struct libinput_device *device,
static int
evdev_scroll_config_natural_get(struct libinput_device *device)
{
- struct evdev_device *dev = (struct evdev_device *)device;
+ struct evdev_device *dev = evdev_device(device);
return dev->scroll.natural_scrolling_enabled ? 1 : 0;
}
@@ -1610,8 +1619,8 @@ static enum libinput_config_status
evdev_rotation_config_set_angle(struct libinput_device *libinput_device,
unsigned int degrees_cw)
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
- struct fallback_dispatch *dispatch = (struct fallback_dispatch*)device->dispatch;
+ struct evdev_device *device = evdev_device(libinput_device);
+ struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
dispatch->rotation.angle = degrees_cw;
matrix_init_rotate(&dispatch->rotation.matrix, degrees_cw);
@@ -1622,8 +1631,8 @@ evdev_rotation_config_set_angle(struct libinput_device *libinput_device,
static unsigned int
evdev_rotation_config_get_angle(struct libinput_device *libinput_device)
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
- struct fallback_dispatch *dispatch = (struct fallback_dispatch*)device->dispatch;
+ struct evdev_device *device = evdev_device(libinput_device);
+ struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
return dispatch->rotation.angle;
}
@@ -1757,53 +1766,54 @@ fallback_dispatch_init_abs(struct fallback_dispatch *dispatch,
}
static struct evdev_dispatch *
-fallback_dispatch_create(struct libinput_device *device)
+fallback_dispatch_create(struct libinput_device *libinput_device)
{
struct fallback_dispatch *dispatch = zalloc(sizeof *dispatch);
- struct evdev_device *evdev_device = (struct evdev_device *)device;
+ struct evdev_device *device = evdev_device(libinput_device);
if (dispatch == NULL)
return NULL;
+ dispatch->base.dispatch_type = DISPATCH_FALLBACK;
dispatch->base.interface = &fallback_interface;
dispatch->pending_event = EVDEV_NONE;
- fallback_dispatch_init_rel(dispatch, evdev_device);
- fallback_dispatch_init_abs(dispatch, evdev_device);
- if (fallback_dispatch_init_slots(dispatch, evdev_device) == -1) {
+ fallback_dispatch_init_rel(dispatch, device);
+ fallback_dispatch_init_abs(dispatch, device);
+ if (fallback_dispatch_init_slots(dispatch, device) == -1) {
free(dispatch);
return NULL;
}
- if (evdev_device->left_handed.want_enabled)
- evdev_init_left_handed(evdev_device,
+ if (device->left_handed.want_enabled)
+ evdev_init_left_handed(device,
evdev_change_to_left_handed);
- if (evdev_device->scroll.want_button)
- evdev_init_button_scroll(evdev_device,
+ if (device->scroll.want_button)
+ evdev_init_button_scroll(device,
evdev_change_scroll_method);
- if (evdev_device->scroll.natural_scrolling_enabled)
- evdev_init_natural_scroll(evdev_device);
+ if (device->scroll.natural_scrolling_enabled)
+ evdev_init_natural_scroll(device);
- evdev_init_calibration(evdev_device, &dispatch->calibration);
- evdev_init_sendevents(evdev_device, &dispatch->base);
- evdev_init_rotation(evdev_device, dispatch);
+ evdev_init_calibration(device, &dispatch->calibration);
+ evdev_init_sendevents(device, &dispatch->base);
+ evdev_init_rotation(device, dispatch);
/* BTN_MIDDLE is set on mice even when it's not present. So
* we can only use the absence of BTN_MIDDLE to mean something, i.e.
* we enable it by default on anything that only has L&R.
* If we have L&R and no middle, we don't expose it as config
* option */
- if (libevdev_has_event_code(evdev_device->evdev, EV_KEY, BTN_LEFT) &&
- libevdev_has_event_code(evdev_device->evdev, EV_KEY, BTN_RIGHT)) {
- bool has_middle = libevdev_has_event_code(evdev_device->evdev,
+ if (libevdev_has_event_code(device->evdev, EV_KEY, BTN_LEFT) &&
+ libevdev_has_event_code(device->evdev, EV_KEY, BTN_RIGHT)) {
+ bool has_middle = libevdev_has_event_code(device->evdev,
EV_KEY,
BTN_MIDDLE);
bool want_config = has_middle;
bool enable_by_default = !has_middle;
- evdev_init_middlebutton(evdev_device,
+ evdev_init_middlebutton(device,
enable_by_default,
want_config);
}
@@ -1942,7 +1952,7 @@ evdev_accel_config_available(struct libinput_device *device)
static enum libinput_config_status
evdev_accel_config_set_speed(struct libinput_device *device, double speed)
{
- struct evdev_device *dev = (struct evdev_device *)device;
+ struct evdev_device *dev = evdev_device(device);
if (!filter_set_speed(dev->pointer.filter, speed))
return LIBINPUT_CONFIG_STATUS_INVALID;
@@ -1953,7 +1963,7 @@ evdev_accel_config_set_speed(struct libinput_device *device, double speed)
static double
evdev_accel_config_get_speed(struct libinput_device *device)
{
- struct evdev_device *dev = (struct evdev_device *)device;
+ struct evdev_device *dev = evdev_device(device);
return filter_get_speed(dev->pointer.filter);
}
@@ -1967,7 +1977,7 @@ evdev_accel_config_get_default_speed(struct libinput_device *device)
static uint32_t
evdev_accel_config_get_profiles(struct libinput_device *libinput_device)
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
+ struct evdev_device *device = evdev_device(libinput_device);
if (!device->pointer.filter)
return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
@@ -1980,7 +1990,7 @@ static enum libinput_config_status
evdev_accel_config_set_profile(struct libinput_device *libinput_device,
enum libinput_config_accel_profile profile)
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
+ struct evdev_device *device = evdev_device(libinput_device);
struct motion_filter *filter;
double speed;
@@ -2004,7 +2014,7 @@ evdev_accel_config_set_profile(struct libinput_device *libinput_device,
static enum libinput_config_accel_profile
evdev_accel_config_get_profile(struct libinput_device *libinput_device)
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
+ struct evdev_device *device = evdev_device(libinput_device);
return filter_get_type(device->pointer.filter);
}
@@ -2012,7 +2022,7 @@ evdev_accel_config_get_profile(struct libinput_device *libinput_device)
static enum libinput_config_accel_profile
evdev_accel_config_get_default_profile(struct libinput_device *libinput_device)
{
- struct evdev_device *device = (struct evdev_device*)libinput_device;
+ struct evdev_device *device = evdev_device(libinput_device);
if (!device->pointer.filter)
return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
@@ -2534,7 +2544,7 @@ evdev_configure_device(struct evdev_device *device)
}
log_info(libinput,
- "input device '%s', %s is tagged by udev as:%s%s%s%s%s%s%s%s%s%s\n",
+ "input device '%s', %s is tagged by udev as:%s%s%s%s%s%s%s%s%s%s%s\n",
device->devname, devnode,
udev_tags & EVDEV_UDEV_TAG_KEYBOARD ? " Keyboard" : "",
udev_tags & EVDEV_UDEV_TAG_MOUSE ? " Mouse" : "",
@@ -2545,7 +2555,8 @@ evdev_configure_device(struct evdev_device *device)
udev_tags & EVDEV_UDEV_TAG_JOYSTICK ? " Joystick" : "",
udev_tags & EVDEV_UDEV_TAG_ACCELEROMETER ? " Accelerometer" : "",
udev_tags & EVDEV_UDEV_TAG_TABLET_PAD ? " TabletPad" : "",
- udev_tags & EVDEV_UDEV_TAG_TRACKBALL ? " Trackball" : "");
+ udev_tags & EVDEV_UDEV_TAG_TRACKBALL ? " Trackball" : "",
+ udev_tags & EVDEV_UDEV_TAG_SWITCH ? " Switch" : "");
if (udev_tags & EVDEV_UDEV_TAG_ACCELEROMETER) {
log_info(libinput,
@@ -2657,6 +2668,17 @@ evdev_configure_device(struct evdev_device *device)
device->devname, devnode);
}
+ if (udev_tags & EVDEV_UDEV_TAG_SWITCH &&
+ libevdev_has_event_code(evdev, EV_SW, SW_LID)) {
+ dispatch = evdev_lid_switch_dispatch_create(device);
+ device->seat_caps |= EVDEV_DEVICE_SWITCH;
+ evdev_tag_lid_switch(device, device->udev_device);
+ log_info(libinput,
+ "input device '%s', %s is a switch device\n",
+ device->devname, devnode);
+ return dispatch;
+ }
+
if (device->seat_caps & EVDEV_DEVICE_POINTER &&
libevdev_has_event_code(evdev, EV_REL, REL_X) &&
libevdev_has_event_code(evdev, EV_REL, REL_Y) &&
@@ -2676,7 +2698,7 @@ evdev_notify_added_device(struct evdev_device *device)
struct libinput_device *dev;
list_for_each(dev, &device->base.seat->devices_list, link) {
- struct evdev_device *d = (struct evdev_device*)dev;
+ struct evdev_device *d = evdev_device(dev);
if (dev == &device->base)
continue;
@@ -3089,6 +3111,8 @@ evdev_device_has_capability(struct evdev_device *device,
return !!(device->seat_caps & EVDEV_DEVICE_TABLET);
case LIBINPUT_DEVICE_CAP_TABLET_PAD:
return !!(device->seat_caps & EVDEV_DEVICE_TABLET_PAD);
+ case LIBINPUT_DEVICE_CAP_SWITCH:
+ return !!(device->seat_caps & EVDEV_DEVICE_SWITCH);
default:
return false;
}
@@ -3258,7 +3282,7 @@ evdev_notify_suspended_device(struct evdev_device *device)
return;
list_for_each(it, &device->base.seat->devices_list, link) {
- struct evdev_device *d = (struct evdev_device*)it;
+ struct evdev_device *d = evdev_device(it);
if (it == &device->base)
continue;
@@ -3278,7 +3302,7 @@ evdev_notify_resumed_device(struct evdev_device *device)
return;
list_for_each(it, &device->base.seat->devices_list, link) {
- struct evdev_device *d = (struct evdev_device*)it;
+ struct evdev_device *d = evdev_device(it);
if (it == &device->base)
continue;
@@ -3385,7 +3409,7 @@ evdev_device_remove(struct evdev_device *device)
struct libinput_device *dev;
list_for_each(dev, &device->base.seat->devices_list, link) {
- struct evdev_device *d = (struct evdev_device*)dev;
+ struct evdev_device *d = evdev_device(dev);
if (dev == &device->base)
continue;
diff --git a/src/evdev.h b/src/evdev.h
index 3fe5d3a..1a24d4b 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -63,6 +63,7 @@ enum evdev_device_seat_capability {
EVDEV_DEVICE_TABLET = (1 << 3),
EVDEV_DEVICE_TABLET_PAD = (1 << 4),
EVDEV_DEVICE_GESTURE = (1 << 5),
+ EVDEV_DEVICE_SWITCH = (1 << 6),
};
enum evdev_device_tags {
@@ -71,6 +72,7 @@ enum evdev_device_tags {
EVDEV_TAG_EXTERNAL_TOUCHPAD = (1 << 2),
EVDEV_TAG_TRACKPOINT = (1 << 3),
EVDEV_TAG_KEYBOARD = (1 << 4),
+ EVDEV_TAG_LID_SWITCH = (1 << 5),
};
enum evdev_middlebutton_state {
@@ -235,6 +237,14 @@ struct evdev_device {
} middlebutton;
};
+static inline struct evdev_device *
+evdev_device(struct libinput_device *device)
+{
+ struct evdev_device *d;
+
+ return container_of(device, d, base);
+}
+
#define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1)
struct evdev_dispatch;
@@ -282,7 +292,16 @@ struct evdev_dispatch_interface {
bool enable);
};
+enum evdev_dispatch_type {
+ DISPATCH_FALLBACK,
+ DISPATCH_TOUCHPAD,
+ DISPATCH_TABLET,
+ DISPATCH_TABLET_PAD,
+ DISPATCH_LID_SWITCH,
+};
+
struct evdev_dispatch {
+ enum evdev_dispatch_type dispatch_type;
struct evdev_dispatch_interface *interface;
struct {
@@ -291,6 +310,14 @@ struct evdev_dispatch {
} sendevents;
};
+static inline void
+evdev_verify_dispatch_type(struct evdev_dispatch *dispatch,
+ enum evdev_dispatch_type type)
+{
+ if (dispatch->dispatch_type != type)
+ abort();
+}
+
struct fallback_dispatch {
struct evdev_dispatch base;
@@ -334,6 +361,16 @@ struct fallback_dispatch {
bool ignore_events;
};
+static inline struct fallback_dispatch*
+fallback_dispatch(struct evdev_dispatch *dispatch)
+{
+ struct fallback_dispatch *f;
+
+ evdev_verify_dispatch_type(dispatch, DISPATCH_FALLBACK);
+
+ return container_of(dispatch, f, base);
+}
+
struct evdev_device *
evdev_device_create(struct libinput_seat *seat,
struct udev_device *device);
@@ -354,6 +391,10 @@ void
evdev_read_calibration_prop(struct evdev_device *device);
void
+evdev_init_sendevents(struct evdev_device *device,
+ struct evdev_dispatch *dispatch);
+
+void
evdev_device_init_pointer_acceleration(struct evdev_device *device,
struct motion_filter *filter);
@@ -369,6 +410,9 @@ evdev_tablet_create(struct evdev_device *device);
struct evdev_dispatch *
evdev_tablet_pad_create(struct evdev_device *device);
+struct evdev_dispatch *
+evdev_lid_switch_dispatch_create(struct evdev_device *device);
+
void
evdev_device_led_update(struct evdev_device *device, enum libinput_led leds);
diff --git a/src/libinput-private.h b/src/libinput-private.h
index 39c169c..205dbf8 100644
--- a/src/libinput-private.h
+++ b/src/libinput-private.h
@@ -467,6 +467,9 @@ libinput_device_set_device_group(struct libinput_device *device,
struct libinput_device_group *group);
void
+libinput_device_init_event_listener(struct libinput_event_listener *listener);
+
+void
libinput_device_add_event_listener(struct libinput_device *device,
struct libinput_event_listener *listener,
void (*notify_func)(
@@ -623,6 +626,11 @@ tablet_pad_notify_strip(struct libinput_device *device,
double value,
enum libinput_tablet_pad_strip_axis_source source,
struct libinput_tablet_pad_mode_group *group);
+void
+switch_notify_toggle(struct libinput_device *device,
+ uint64_t time,
+ enum libinput_switch sw,
+ enum libinput_switch_state state);
static inline uint64_t
libinput_now(struct libinput *libinput)
diff --git a/src/libinput-util.c b/src/libinput-util.c
index 40e1e6e..aa69a37 100644
--- a/src/libinput-util.c
+++ b/src/libinput-util.c
@@ -278,6 +278,25 @@ parse_dimension_property(const char *prop, size_t *w, size_t *h)
return true;
}
+bool
+parse_switch_reliability_property(const char *prop,
+ enum switch_reliability *reliability)
+{
+ if (!prop) {
+ *reliability = RELIABILITY_UNKNOWN;
+ return true;
+ }
+
+ if (streq(prop, "reliable"))
+ *reliability = RELIABILITY_RELIABLE;
+ else if (streq(prop, "write_open"))
+ *reliability = RELIABILITY_WRITE_OPEN;
+ else
+ return false;
+
+ return true;
+}
+
/**
* Return the next word in a string pointed to by state before the first
* separator character. Call repeatedly to tokenize a whole string.
diff --git a/src/libinput-util.h b/src/libinput-util.h
index ba09ab6..1d03ce1 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -377,6 +377,16 @@ int parse_mouse_wheel_click_count_property(const char *prop);
double parse_trackpoint_accel_property(const char *prop);
bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
+enum switch_reliability {
+ RELIABILITY_UNKNOWN,
+ RELIABILITY_RELIABLE,
+ RELIABILITY_WRITE_OPEN,
+};
+
+bool
+parse_switch_reliability_property(const char *prop,
+ enum switch_reliability *reliability);
+
static inline uint64_t
us(uint64_t us)
{
diff --git a/src/libinput.c b/src/libinput.c
index 4daa11d..84e329d 100644
--- a/src/libinput.c
+++ b/src/libinput.c
@@ -159,6 +159,13 @@ struct libinput_event_tablet_pad {
} strip;
};
+struct libinput_event_switch {
+ struct libinput_event base;
+ uint64_t time;
+ enum libinput_switch sw;
+ enum libinput_switch_state state;
+};
+
LIBINPUT_ATTRIBUTE_PRINTF(3, 0)
static void
libinput_default_log_func(struct libinput *libinput,
@@ -365,6 +372,17 @@ libinput_event_get_device_notify_event(struct libinput_event *event)
return (struct libinput_event_device_notify *) event;
}
+LIBINPUT_EXPORT struct libinput_event_switch *
+libinput_event_get_switch_event(struct libinput_event *event)
+{
+ require_event_type(libinput_event_get_context(event),
+ event->type,
+ NULL,
+ LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ return (struct libinput_event_switch *) event;
+}
+
LIBINPUT_EXPORT uint32_t
libinput_event_keyboard_get_time(struct libinput_event_keyboard *event)
{
@@ -498,8 +516,7 @@ libinput_event_pointer_get_dy_unaccelerated(
LIBINPUT_EXPORT double
libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -512,8 +529,7 @@ libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event)
LIBINPUT_EXPORT double
libinput_event_pointer_get_absolute_y(struct libinput_event_pointer *event)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -528,8 +544,7 @@ libinput_event_pointer_get_absolute_x_transformed(
struct libinput_event_pointer *event,
uint32_t width)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -544,8 +559,7 @@ libinput_event_pointer_get_absolute_y_transformed(
struct libinput_event_pointer *event,
uint32_t height)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -734,8 +748,7 @@ libinput_event_touch_get_seat_slot(struct libinput_event_touch *event)
LIBINPUT_EXPORT double
libinput_event_touch_get_x(struct libinput_event_touch *event)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -750,8 +763,7 @@ LIBINPUT_EXPORT double
libinput_event_touch_get_x_transformed(struct libinput_event_touch *event,
uint32_t width)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -766,8 +778,7 @@ LIBINPUT_EXPORT double
libinput_event_touch_get_y_transformed(struct libinput_event_touch *event,
uint32_t height)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -781,8 +792,7 @@ libinput_event_touch_get_y_transformed(struct libinput_event_touch *event,
LIBINPUT_EXPORT double
libinput_event_touch_get_y(struct libinput_event_touch *event)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -1092,8 +1102,7 @@ libinput_event_tablet_tool_wheel_has_changed(
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_x(struct libinput_event_tablet_tool *event)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -1110,8 +1119,7 @@ libinput_event_tablet_tool_get_x(struct libinput_event_tablet_tool *event)
LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_y(struct libinput_event_tablet_tool *event)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -1259,8 +1267,7 @@ LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_x_transformed(struct libinput_event_tablet_tool *event,
uint32_t width)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -1279,8 +1286,7 @@ LIBINPUT_EXPORT double
libinput_event_tablet_tool_get_y_transformed(struct libinput_event_tablet_tool *event,
uint32_t height)
{
- struct evdev_device *device =
- (struct evdev_device *) event->base.device;
+ struct evdev_device *device = evdev_device(event->base.device);
require_event_type(libinput_event_get_context(&event->base),
event->base.type,
@@ -1508,6 +1514,61 @@ libinput_tablet_tool_unref(struct libinput_tablet_tool *tool)
return NULL;
}
+LIBINPUT_EXPORT struct libinput_event *
+libinput_event_switch_get_base_event(struct libinput_event_switch *event)
+{
+ require_event_type(libinput_event_get_context(&event->base),
+ event->base.type,
+ NULL,
+ LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ return &event->base;
+}
+
+LIBINPUT_EXPORT enum libinput_switch
+libinput_event_switch_get_switch(struct libinput_event_switch *event)
+{
+ require_event_type(libinput_event_get_context(&event->base),
+ event->base.type,
+ 0,
+ LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ return event->sw;
+}
+
+LIBINPUT_EXPORT enum libinput_switch_state
+libinput_event_switch_get_switch_state(struct libinput_event_switch *event)
+{
+ require_event_type(libinput_event_get_context(&event->base),
+ event->base.type,
+ 0,
+ LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ return event->state;
+}
+
+LIBINPUT_EXPORT uint32_t
+libinput_event_switch_get_time(struct libinput_event_switch *event)
+{
+ require_event_type(libinput_event_get_context(&event->base),
+ event->base.type,
+ 0,
+ LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ return us2ms(event->time);
+}
+
+LIBINPUT_EXPORT uint64_t
+libinput_event_switch_get_time_usec(struct libinput_event_switch *event)
+{
+ require_event_type(libinput_event_get_context(&event->base),
+ event->base.type,
+ 0,
+ LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ return event->time;
+}
+
struct libinput_source *
libinput_add_fd(struct libinput *libinput,
int fd,
@@ -1825,7 +1886,7 @@ static void
libinput_device_destroy(struct libinput_device *device)
{
assert(list_empty(&device->event_listeners));
- evdev_device_destroy((struct evdev_device *) device);
+ evdev_device_destroy(evdev_device(device));
}
LIBINPUT_EXPORT struct libinput_device *
@@ -1872,6 +1933,12 @@ libinput_dispatch(struct libinput *libinput)
}
void
+libinput_device_init_event_listener(struct libinput_event_listener *listener)
+{
+ list_init(&listener->link);
+}
+
+void
libinput_device_add_event_listener(struct libinput_device *device,
struct libinput_event_listener *listener,
void (*notify_func)(
@@ -2024,6 +2091,9 @@ device_has_cap(struct libinput_device *device,
case LIBINPUT_DEVICE_CAP_TABLET_PAD:
capability = "CAP_TABLET_PAD";
break;
+ case LIBINPUT_DEVICE_CAP_SWITCH:
+ capability = "CAP_SWITCH";
+ break;
}
log_bug_libinput(device->seat->libinput,
@@ -2619,6 +2689,7 @@ event_type_to_str(enum libinput_event_type type)
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_BEGIN);
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_UPDATE);
CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_PINCH_END);
+ CASE_RETURN_STRING(LIBINPUT_EVENT_SWITCH_TOGGLE);
case LIBINPUT_EVENT_NONE:
abort();
}
@@ -2626,6 +2697,32 @@ event_type_to_str(enum libinput_event_type type)
return NULL;
}
+void
+switch_notify_toggle(struct libinput_device *device,
+ uint64_t time,
+ enum libinput_switch sw,
+ enum libinput_switch_state state)
+{
+ struct libinput_event_switch *switch_event;
+
+ if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_SWITCH))
+ return;
+
+ switch_event = zalloc(sizeof *switch_event);
+ if (!switch_event)
+ return;
+
+ *switch_event = (struct libinput_event_switch) {
+ .time = time,
+ .sw = sw,
+ .state = state,
+ };
+
+ post_device_event(device, time,
+ LIBINPUT_EVENT_SWITCH_TOGGLE,
+ &switch_event->base);
+}
+
static void
libinput_post_event(struct libinput *libinput,
struct libinput_event *event)
diff --git a/src/libinput.h b/src/libinput.h
index fdbba3c..436923d 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -187,6 +187,7 @@ enum libinput_device_capability {
LIBINPUT_DEVICE_CAP_TABLET_TOOL = 3,
LIBINPUT_DEVICE_CAP_TABLET_PAD = 4,
LIBINPUT_DEVICE_CAP_GESTURE = 5,
+ LIBINPUT_DEVICE_CAP_SWITCH = 6,
};
/**
@@ -598,6 +599,42 @@ libinput_tablet_pad_mode_group_get_user_data(
struct libinput_tablet_pad_mode_group *group);
/**
+ * @ingroup device
+ *
+ * The state of a switch. The default state of a switch is @ref
+ * LIBINPUT_SWITCH_STATE_OFF and no event is sent to confirm a switch in the
+ * off position. If a switch is logically on during initialization, libinput
+ * sends an event of type @ref LIBINPUT_EVENT_SWITCH_TOGGLE with a state
+ * @ref LIBINPUT_SWITCH_STATE_ON.
+ */
+enum libinput_switch_state {
+ LIBINPUT_SWITCH_STATE_OFF = 0,
+ LIBINPUT_SWITCH_STATE_ON = 1,
+};
+
+/**
+ * @ingroup device
+ *
+ * The type of a switch.
+ */
+enum libinput_switch {
+ /**
+ * The laptop lid was closed when the switch state is @ref
+ * LIBINPUT_SWITCH_STATE_ON, or was opened when it is @ref
+ * LIBINPUT_SWITCH_STATE_OFF.
+ */
+ LIBINPUT_SWITCH_LID = 1,
+};
+
+/**
+ * @ingroup event_switch
+ * @struct libinput_event_switch
+ *
+ * A switch event representing a changed state in a switch.
+ */
+struct libinput_event_switch;
+
+/**
* @ingroup base
*
* Event type for events returned by libinput_get_event().
@@ -752,6 +789,8 @@ enum libinput_event_type {
LIBINPUT_EVENT_GESTURE_PINCH_BEGIN,
LIBINPUT_EVENT_GESTURE_PINCH_UPDATE,
LIBINPUT_EVENT_GESTURE_PINCH_END,
+
+ LIBINPUT_EVENT_SWITCH_TOGGLE = 900,
};
/**
@@ -891,6 +930,19 @@ libinput_event_get_tablet_pad_event(struct libinput_event *event);
/**
* @ingroup event
*
+ * Return the switch event that is this input event. If the event type does
+ * not match the switch event types, this function returns NULL.
+ *
+ * The inverse of this function is libinput_event_switch_get_base_event().
+ *
+ * @return A switch event, or NULL for other events
+ */
+struct libinput_event_switch *
+libinput_event_get_switch_event(struct libinput_event *event);
+
+/**
+ * @ingroup event
+ *
* Return the device event that is this input event. If the event type does
* not match the device event types, this function returns NULL.
*
@@ -2699,6 +2751,70 @@ uint64_t
libinput_event_tablet_pad_get_time_usec(struct libinput_event_tablet_pad *event);
/**
+ * @defgroup event_switch Switch events
+ *
+ * Events that come from switch devices.
+ */
+
+/**
+ * @ingroup event_switch
+ *
+ * Return the switch that triggered this event.
+ * For pointer events that are not of type @ref
+ * LIBINPUT_EVENT_SWITCH_TOGGLE, this function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_SWITCH_TOGGLE.
+ *
+ * @param event The libinput switch event
+ * @return The switch triggering this event
+ */
+enum libinput_switch
+libinput_event_switch_get_switch(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * Return the switch state that triggered this event.
+ * For switch events that are not of type @ref
+ * LIBINPUT_EVENT_SWITCH_TOGGLE, this function returns 0.
+ *
+ * @note It is an application bug to call this function for events other than
+ * @ref LIBINPUT_EVENT_SWITCH_TOGGLE.
+ *
+ * @param event The libinput switch event
+ * @return The switch state triggering this event
+ */
+enum libinput_switch_state
+libinput_event_switch_get_switch_state(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * @return The generic libinput_event of this event
+ */
+struct libinput_event *
+libinput_event_switch_get_base_event(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * @param event The libinput switch event
+ * @return The event time for this event
+ */
+uint32_t
+libinput_event_switch_get_time(struct libinput_event_switch *event);
+
+/**
+ * @ingroup event_switch
+ *
+ * @param event The libinput switch event
+ * @return The event time for this event in microseconds
+ */
+uint64_t
+libinput_event_switch_get_time_usec(struct libinput_event_switch *event);
+
+/**
* @defgroup base Initialization and manipulation of libinput contexts
*/
diff --git a/src/libinput.sym b/src/libinput.sym
index 97bb57f..f440521 100644
--- a/src/libinput.sym
+++ b/src/libinput.sym
@@ -280,3 +280,12 @@ LIBINPUT_1.5 {
libinput_device_config_tap_get_default_button_map;
libinput_device_config_tap_set_button_map;
} LIBINPUT_1.4;
+
+LIBINPUT_SWITCH {
+ libinput_event_get_switch_event;
+ libinput_event_switch_get_base_event;
+ libinput_event_switch_get_switch_state;
+ libinput_event_switch_get_switch;
+ libinput_event_switch_get_time;
+ libinput_event_switch_get_time_usec;
+} LIBINPUT_1.5;
diff --git a/src/path-seat.c b/src/path-seat.c
index d806bfb..e6289a2 100644
--- a/src/path-seat.c
+++ b/src/path-seat.c
@@ -244,11 +244,11 @@ path_device_change_seat(struct libinput_device *device,
const char *seat_name)
{
struct libinput *libinput = device->seat->libinput;
- struct evdev_device *evdev_device = (struct evdev_device *)device;
+ struct evdev_device *evdev = evdev_device(device);
struct udev_device *udev_device = NULL;
int rc = -1;
- udev_device = evdev_device->udev_device;
+ udev_device = evdev->udev_device;
udev_device_ref(udev_device);
libinput_path_remove_device(device);
@@ -361,7 +361,7 @@ libinput_path_remove_device(struct libinput_device *device)
struct libinput *libinput = device->seat->libinput;
struct path_input *input = (struct path_input*)libinput;
struct libinput_seat *seat;
- struct evdev_device *evdev = (struct evdev_device*)device;
+ struct evdev_device *evdev = evdev_device(device);
struct path_device *dev;
if (libinput->interface_backend != &interface_backend) {
diff --git a/src/udev-seat.c b/src/udev-seat.c
index d1eaed8..a19afb4 100644
--- a/src/udev-seat.c
+++ b/src/udev-seat.c
@@ -322,8 +322,8 @@ udev_device_change_seat(struct libinput_device *device,
{
struct libinput *libinput = device->seat->libinput;
struct udev_input *input = (struct udev_input *)libinput;
- struct evdev_device *evdev_device = (struct evdev_device *)device;
- struct udev_device *udev_device = evdev_device->udev_device;
+ struct evdev_device *evdev = evdev_device(device);
+ struct udev_device *udev_device = evdev->udev_device;
int rc;
udev_device_ref(udev_device);
diff --git a/test/Makefile.am b/test/Makefile.am
index 0d54dab..2e565de 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -32,6 +32,8 @@ liblitest_la_SOURCES = \
litest-device-keyboard.c \
litest-device-keyboard-all-codes.c \
litest-device-keyboard-razer-blackwidow.c \
+ litest-device-lid-switch.c \
+ litest-device-lid-switch-surface3.c \
litest-device-logitech-trackball.c \
litest-device-nexus4-touch-screen.c \
litest-device-magic-trackpad.c \
@@ -117,7 +119,8 @@ libinput_test_suite_runner_SOURCES = test-udev.c \
test-misc.c \
test-keyboard.c \
test-device.c \
- test-gestures.c
+ test-gestures.c \
+ test-lid.c
libinput_test_suite_runner_CFLAGS = $(AM_CFLAGS) -DLIBINPUT_LT_VERSION="\"$(LIBINPUT_LT_VERSION)\""
libinput_test_suite_runner_LDADD = $(TEST_LIBS)
diff --git a/test/litest-device-lid-switch-surface3.c b/test/litest-device-lid-switch-surface3.c
new file mode 100644
index 0000000..fde15c2
--- /dev/null
+++ b/test/litest-device-lid-switch-surface3.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright © 2017 James Ye <jye836@gmail.com>
+ * Copyright © 2017 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 "litest.h"
+#include "litest-int.h"
+
+static void
+litest_lid_switch_setup(void)
+{
+ struct litest_device *d = litest_create_device(LITEST_LID_SWITCH_SURFACE3);
+ litest_set_current_device(d);
+}
+
+static struct input_id input_id = {
+ .bustype = 0x19,
+ .vendor = 0x0,
+ .product = 0x5,
+};
+
+static int events[] = {
+ EV_SW, SW_LID,
+ -1, -1,
+};
+
+static const char udev_rule[] =
+"ACTION==\"remove\", GOTO=\"switch_end\"\n"
+"KERNEL!=\"event*\", GOTO=\"switch_end\"\n"
+"\n"
+"ATTRS{name}==\"litest Lid Switch Surface3*\",\\\n"
+" ENV{ID_INPUT_SWITCH}=\"1\",\\\n"
+" ENV{LIBINPUT_ATTR_LID_SWITCH_RELIABILITY}=\"write_open\"\n"
+"\n"
+"LABEL=\"switch_end\"";
+
+struct litest_test_device litest_lid_switch_surface3_device = {
+ .type = LITEST_LID_SWITCH_SURFACE3,
+ .features = LITEST_SWITCH,
+ .shortname = "lid-switch-surface3",
+ .setup = litest_lid_switch_setup,
+ .interface = NULL,
+
+ .name = "Lid Switch Surface3",
+ .id = &input_id,
+ .events = events,
+ .absinfo = NULL,
+
+ .udev_rule = udev_rule,
+};
diff --git a/test/litest-device-lid-switch.c b/test/litest-device-lid-switch.c
new file mode 100644
index 0000000..b96592d
--- /dev/null
+++ b/test/litest-device-lid-switch.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright © 2017 James Ye <jye836@gmail.com>
+ *
+ * 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 "litest.h"
+#include "litest-int.h"
+
+static void
+litest_lid_switch_setup(void)
+{
+ struct litest_device *d = litest_create_device(LITEST_LID_SWITCH);
+ litest_set_current_device(d);
+}
+
+static struct input_id input_id = {
+ .bustype = 0x19,
+ .vendor = 0x0,
+ .product = 0x5,
+};
+
+static int events[] = {
+ EV_SW, SW_LID,
+ -1, -1,
+};
+
+static const char udev_rule[] =
+"ACTION==\"remove\", GOTO=\"switch_end\"\n"
+"KERNEL!=\"event*\", GOTO=\"switch_end\"\n"
+"\n"
+"ATTRS{name}==\"litest Lid Switch*\",\\\n"
+" ENV{ID_INPUT_SWITCH}=\"1\",\\\n"
+" ENV{LIBINPUT_ATTR_LID_SWITCH_RELIABILITY}=\"reliable\"\n"
+"\n"
+"LABEL=\"switch_end\"";
+
+struct litest_test_device litest_lid_switch_device = {
+ .type = LITEST_LID_SWITCH,
+ .features = LITEST_SWITCH,
+ .shortname = "lid switch",
+ .setup = litest_lid_switch_setup,
+ .interface = NULL,
+
+ .name = "Lid Switch",
+ .id = &input_id,
+ .events = events,
+ .absinfo = NULL,
+
+ .udev_rule = udev_rule,
+};
diff --git a/test/litest.c b/test/litest.c
index b3e7ba3..1756940 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -408,6 +408,8 @@ extern struct litest_test_device litest_acer_hawaii_keyboard_device;
extern struct litest_test_device litest_acer_hawaii_touchpad_device;
extern struct litest_test_device litest_synaptics_rmi4_device;
extern struct litest_test_device litest_mouse_wheel_tilt_device;
+extern struct litest_test_device litest_lid_switch_device;
+extern struct litest_test_device litest_lid_switch_surface3_device;
struct litest_test_device* devices[] = {
&litest_synaptics_clickpad_device,
@@ -470,6 +472,8 @@ struct litest_test_device* devices[] = {
&litest_acer_hawaii_touchpad_device,
&litest_synaptics_rmi4_device,
&litest_mouse_wheel_tilt_device,
+ &litest_lid_switch_device,
+ &litest_lid_switch_surface3_device,
NULL,
};
@@ -1907,6 +1911,14 @@ litest_keyboard_key(struct litest_device *d, unsigned int key, bool is_press)
litest_button_click(d, key, is_press);
}
+void
+litest_lid_action(struct litest_device *dev,
+ enum libinput_switch_state state)
+{
+ litest_event(dev, EV_SW, SW_LID, state);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+}
+
static int
litest_scale_axis(const struct litest_device *d,
unsigned int axis,
@@ -2203,6 +2215,9 @@ litest_event_type_str(enum libinput_event_type type)
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
str = "TABLET PAD STRIP";
break;
+ case LIBINPUT_EVENT_SWITCH_TOGGLE:
+ str = "SWITCH TOGGLE";
+ break;
}
return str;
}
@@ -2816,6 +2831,25 @@ litest_is_pad_strip_event(struct libinput_event *event,
return p;
}
+struct libinput_event_switch *
+litest_is_switch_event(struct libinput_event *event,
+ enum libinput_switch sw,
+ enum libinput_switch_state state)
+{
+ struct libinput_event_switch *swev;
+ enum libinput_event_type type = LIBINPUT_EVENT_SWITCH_TOGGLE;
+
+ litest_assert_notnull(event);
+ litest_assert_event_type(event, type);
+ swev = libinput_event_get_switch_event(event);
+
+ litest_assert_int_eq(libinput_event_switch_get_switch(swev), sw);
+ litest_assert_int_eq(libinput_event_switch_get_switch_state(swev),
+ state);
+
+ return swev;
+}
+
void
litest_assert_pad_button_event(struct libinput *li,
unsigned int button,
@@ -3320,6 +3354,7 @@ main(int argc, char **argv)
litest_setup_tests_keyboard();
litest_setup_tests_device();
litest_setup_tests_gestures();
+ litest_setup_tests_lid();
if (mode == LITEST_MODE_LIST) {
litest_list_tests(&all_tests);
diff --git a/test/litest.h b/test/litest.h
index e6d35a9..d779f0f 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -49,6 +49,7 @@ extern void litest_setup_tests_misc(void);
extern void litest_setup_tests_keyboard(void);
extern void litest_setup_tests_device(void);
extern void litest_setup_tests_gestures(void);
+extern void litest_setup_tests_lid(void);
void
litest_fail_condition(const char *file,
@@ -228,6 +229,8 @@ enum litest_device_type {
LITEST_ACER_HAWAII_TOUCHPAD,
LITEST_SYNAPTICS_RMI4,
LITEST_MOUSE_WHEEL_TILT,
+ LITEST_LID_SWITCH,
+ LITEST_LID_SWITCH_SURFACE3,
};
enum litest_device_feature {
@@ -259,6 +262,7 @@ enum litest_device_feature {
LITEST_STRIP = 1 << 23,
LITEST_TRACKBALL = 1 << 24,
LITEST_LEDS = 1 << 25,
+ LITEST_SWITCH = 1 << 26,
};
struct litest_device {
@@ -526,6 +530,9 @@ litest_keyboard_key(struct litest_device *d,
unsigned int key,
bool is_press);
+void litest_lid_action(struct litest_device *d,
+ enum libinput_switch_state state);
+
void
litest_wait_for_event(struct libinput *li);
@@ -589,6 +596,11 @@ litest_is_pad_strip_event(struct libinput_event *event,
unsigned int number,
enum libinput_tablet_pad_strip_axis_source source);
+struct libinput_event_switch *
+litest_is_switch_event(struct libinput_event *event,
+ enum libinput_switch sw,
+ enum libinput_switch_state state);
+
void
litest_assert_button_event(struct libinput *li,
unsigned int button,
diff --git a/test/test-device.c b/test/test-device.c
index 3fa35d8..8f06f7e 100644
--- a/test/test-device.c
+++ b/test/test-device.c
@@ -1493,6 +1493,7 @@ START_TEST(device_capability_at_least_one)
LIBINPUT_DEVICE_CAP_TABLET_TOOL,
LIBINPUT_DEVICE_CAP_TABLET_PAD,
LIBINPUT_DEVICE_CAP_GESTURE,
+ LIBINPUT_DEVICE_CAP_SWITCH,
};
enum libinput_device_capability *cap;
int ncaps = 0;
@@ -1512,7 +1513,7 @@ START_TEST(device_capability_check_invalid)
struct libinput_device *device = dev->libinput_device;
ck_assert(!libinput_device_has_capability(device, -1));
- ck_assert(!libinput_device_has_capability(device, 6));
+ ck_assert(!libinput_device_has_capability(device, 7));
ck_assert(!libinput_device_has_capability(device, 0xffff));
}
diff --git a/test/test-lid.c b/test/test-lid.c
new file mode 100644
index 0000000..a5f439a
--- /dev/null
+++ b/test/test-lid.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright © 2017 James Ye <jye836@gmail.com>
+ *
+ * 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 <check.h>
+#include <libinput.h>
+
+#include "libinput-util.h"
+#include "litest.h"
+
+START_TEST(lid_switch)
+{
+ struct litest_device *sw = litest_current_device();
+ struct libinput *li = sw->libinput;
+ struct libinput_event *event;
+
+ litest_drain_events(li);
+
+ /* lid closed */
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_ON);
+ libinput_event_destroy(event);
+
+ /* lid opened */
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_OFF);
+ libinput_event_destroy(event);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(lid_switch_double)
+{
+ struct litest_device *sw = litest_current_device();
+ struct libinput *li = sw->libinput;
+ struct libinput_event *event;
+
+ litest_drain_events(li);
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_ON);
+ libinput_event_destroy(event);
+
+ /* This will be filtered by the kernel, so this test is a bit
+ * useless */
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ libinput_dispatch(li);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+static bool
+lid_switch_is_reliable(struct litest_device *dev)
+{
+ struct udev_device *udev_device;
+ const char *prop;
+ bool is_reliable = false;
+
+ udev_device = libinput_device_get_udev_device(dev->libinput_device);
+ prop = udev_device_get_property_value(udev_device,
+ "LIBINPUT_ATTR_LID_SWITCH_RELIABILITY");
+
+ is_reliable = prop && streq(prop, "reliable");
+ udev_device_unref(udev_device);
+
+ return is_reliable;
+}
+
+START_TEST(lid_switch_down_on_init)
+{
+ struct litest_device *sw = litest_current_device();
+ struct libinput *li;
+ struct libinput_event *event;
+
+ if (!lid_switch_is_reliable(sw))
+ return;
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+
+ /* need separate context to test */
+ li = litest_create_context();
+ libinput_path_add_device(li,
+ libevdev_uinput_get_devnode(sw->uinput));
+ libinput_dispatch(li);
+
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_SWITCH_TOGGLE, -1);
+ event = libinput_get_event(li);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_ON);
+ libinput_event_destroy(event);
+
+ while ((event = libinput_get_event(li))) {
+ ck_assert_int_ne(libinput_event_get_type(event),
+ LIBINPUT_EVENT_SWITCH_TOGGLE);
+ libinput_event_destroy(event);
+ }
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF);
+ libinput_dispatch(li);
+ event = libinput_get_event(li);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_OFF);
+ libinput_event_destroy(event);
+ litest_assert_empty_queue(li);
+
+ libinput_unref(li);
+
+}
+END_TEST
+
+START_TEST(lid_switch_not_down_on_init)
+{
+ struct litest_device *sw = litest_current_device();
+ struct libinput *li;
+ struct libinput_event *event;
+
+ if (lid_switch_is_reliable(sw))
+ return;
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+
+ /* need separate context to test */
+ li = litest_create_context();
+ libinput_path_add_device(li,
+ libevdev_uinput_get_devnode(sw->uinput));
+ libinput_dispatch(li);
+
+ while ((event = libinput_get_event(li)) != NULL) {
+ ck_assert_int_ne(libinput_event_get_type(event),
+ LIBINPUT_EVENT_SWITCH_TOGGLE);
+ libinput_event_destroy(event);
+ }
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF);
+ litest_assert_empty_queue(li);
+ libinput_unref(li);
+}
+END_TEST
+
+static inline struct litest_device *
+lid_init_paired_touchpad(struct libinput *li)
+{
+ enum litest_device_type which = LITEST_SYNAPTICS_I2C;
+
+ return litest_add_device(li, which);
+}
+
+START_TEST(lid_disable_touchpad)
+{
+ struct litest_device *sw = litest_current_device();
+ struct litest_device *touchpad;
+ struct libinput *li = sw->libinput;
+
+ touchpad = lid_init_paired_touchpad(li);
+ litest_disable_tap(touchpad->libinput_device);
+ litest_drain_events(li);
+
+ /* lid is down - no events */
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_empty_queue(li);
+
+ /* lid is up - motion events */
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+ litest_delete_device(touchpad);
+}
+END_TEST
+
+START_TEST(lid_disable_touchpad_during_touch)
+{
+ struct litest_device *sw = litest_current_device();
+ struct litest_device *touchpad;
+ struct libinput *li = sw->libinput;
+
+ touchpad = lid_init_paired_touchpad(li);
+ litest_disable_tap(touchpad->libinput_device);
+ litest_drain_events(li);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 5, 1);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ litest_touch_move_to(touchpad, 0, 70, 50, 50, 50, 5, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_empty_queue(li);
+
+ litest_delete_device(touchpad);
+}
+END_TEST
+
+START_TEST(lid_disable_touchpad_edge_scroll)
+{
+ struct litest_device *sw = litest_current_device();
+ struct litest_device *touchpad;
+ struct libinput *li = sw->libinput;
+
+ touchpad = lid_init_paired_touchpad(li);
+ litest_enable_edge_scroll(touchpad);
+
+ litest_drain_events(li);
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ litest_touch_down(touchpad, 0, 99, 20);
+ libinput_dispatch(li);
+ litest_timeout_edgescroll();
+ libinput_dispatch(li);
+ litest_assert_empty_queue(li);
+
+ litest_touch_move_to(touchpad, 0, 99, 20, 99, 80, 60, 10);
+ libinput_dispatch(li);
+ litest_assert_empty_queue(li);
+
+ litest_touch_move_to(touchpad, 0, 99, 80, 99, 20, 60, 10);
+ litest_touch_up(touchpad, 0);
+ libinput_dispatch(li);
+ litest_assert_empty_queue(li);
+
+ litest_delete_device(touchpad);
+}
+END_TEST
+
+START_TEST(lid_disable_touchpad_edge_scroll_interrupt)
+{
+ struct litest_device *sw = litest_current_device();
+ struct litest_device *touchpad;
+ struct libinput *li = sw->libinput;
+ struct libinput_event *event;
+
+ touchpad = lid_init_paired_touchpad(li);
+ litest_enable_edge_scroll(touchpad);
+
+ litest_drain_events(li);
+
+ litest_touch_down(touchpad, 0, 99, 20);
+ libinput_dispatch(li);
+ litest_timeout_edgescroll();
+ litest_touch_move_to(touchpad, 0, 99, 20, 99, 30, 10, 10);
+ libinput_dispatch(li);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ litest_is_axis_event(event,
+ LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
+ LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
+ libinput_event_destroy(event);
+
+ event = libinput_get_event(li);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_ON);
+ libinput_event_destroy(event);
+
+ litest_delete_device(touchpad);
+}
+END_TEST
+
+START_TEST(lid_disable_touchpad_already_open)
+{
+ struct litest_device *sw = litest_current_device();
+ struct litest_device *touchpad;
+ struct libinput *li = sw->libinput;
+
+ touchpad = lid_init_paired_touchpad(li);
+ litest_disable_tap(touchpad->libinput_device);
+ litest_drain_events(li);
+
+ /* default: lid is up - motion events */
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+ /* open lid - motion events */
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF);
+ litest_assert_empty_queue(li);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+ litest_delete_device(touchpad);
+}
+END_TEST
+
+START_TEST(lid_open_on_key)
+{
+ struct litest_device *sw = litest_current_device();
+ struct litest_device *keyboard;
+ struct libinput *li = sw->libinput;
+ struct libinput_event *event;
+
+ keyboard = litest_add_device(li, LITEST_KEYBOARD);
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ litest_drain_events(li);
+
+ litest_event(keyboard, EV_KEY, KEY_A, 1);
+ litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
+ litest_event(keyboard, EV_KEY, KEY_A, 0);
+ litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
+ libinput_dispatch(li);
+
+ litest_wait_for_event_of_type(li, LIBINPUT_EVENT_SWITCH_TOGGLE, -1);
+ event = libinput_get_event(li);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_OFF);
+
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF);
+ litest_assert_empty_queue(li);
+
+ libinput_event_destroy(event);
+ litest_delete_device(keyboard);
+}
+END_TEST
+
+START_TEST(lid_open_on_key_touchpad_enabled)
+{
+ struct litest_device *sw = litest_current_device();
+ struct litest_device *keyboard, *touchpad;
+ struct libinput *li = sw->libinput;
+
+ keyboard = litest_add_device(li, LITEST_KEYBOARD);
+ touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ litest_drain_events(li);
+
+ litest_event(keyboard, EV_KEY, KEY_A, 1);
+ litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
+ litest_event(keyboard, EV_KEY, KEY_A, 0);
+ litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
+ litest_drain_events(li);
+ litest_timeout_dwt_long();
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 70, 10, 1);
+ litest_touch_up(touchpad, 0);
+ libinput_dispatch(li);
+
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+ litest_delete_device(keyboard);
+ litest_delete_device(touchpad);
+}
+END_TEST
+
+START_TEST(lid_update_hw_on_key)
+{
+ struct litest_device *sw = litest_current_device();
+ struct libinput *li = sw->libinput;
+ struct libinput *li2;
+ struct litest_device *keyboard;
+ struct libinput_event *event;
+
+ sleep(5);
+ keyboard = litest_add_device(li, LITEST_KEYBOARD);
+
+ /* separate context to listen to the fake hw event */
+ li2 = litest_create_context();
+ libinput_path_add_device(li2,
+ libevdev_uinput_get_devnode(sw->uinput));
+ litest_drain_events(li2);
+
+ litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
+ litest_drain_events(li);
+
+ libinput_dispatch(li2);
+ event = libinput_get_event(li2);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_ON);
+ libinput_event_destroy(event);
+
+ litest_event(keyboard, EV_KEY, KEY_A, 1);
+ litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
+ litest_event(keyboard, EV_KEY, KEY_A, 0);
+ litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
+ litest_drain_events(li);
+
+ libinput_dispatch(li2);
+ event = libinput_get_event(li2);
+ litest_is_switch_event(event,
+ LIBINPUT_SWITCH_LID,
+ LIBINPUT_SWITCH_STATE_OFF);
+ libinput_event_destroy(event);
+ litest_assert_empty_queue(li);
+
+ libinput_unref(li2);
+ litest_delete_device(keyboard);
+}
+END_TEST
+
+void
+litest_setup_tests_lid(void)
+{
+ litest_add("lid:switch", lid_switch, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:switch", lid_switch_double, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:switch", lid_switch_down_on_init, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:switch", lid_switch_not_down_on_init, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:disable_touchpad", lid_disable_touchpad, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:disable_touchpad", lid_disable_touchpad_during_touch, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:disable_touchpad", lid_disable_touchpad_edge_scroll, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:disable_touchpad", lid_disable_touchpad_edge_scroll_interrupt, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:disable_touchpad", lid_disable_touchpad_already_open, LITEST_SWITCH, LITEST_ANY);
+
+ litest_add("lid:keyboard", lid_open_on_key, LITEST_SWITCH, LITEST_ANY);
+ litest_add("lid:keyboard", lid_open_on_key_touchpad_enabled, LITEST_SWITCH, LITEST_ANY);
+
+ litest_add_for_device("lid:buggy", lid_update_hw_on_key, LITEST_LID_SWITCH_SURFACE3);
+}
diff --git a/test/test-misc.c b/test/test-misc.c
index ed5471d..36cabdc 100644
--- a/test/test-misc.c
+++ b/test/test-misc.c
@@ -135,6 +135,7 @@ START_TEST(event_conversion_device_notify)
ck_assert(libinput_event_get_gesture_event(event) == NULL);
ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+ ck_assert(libinput_event_get_switch_event(event) == NULL);
litest_restore_log_handler(li);
}
@@ -192,6 +193,7 @@ START_TEST(event_conversion_pointer)
ck_assert(libinput_event_get_gesture_event(event) == NULL);
ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+ ck_assert(libinput_event_get_switch_event(event) == NULL);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@@ -243,6 +245,7 @@ START_TEST(event_conversion_pointer_abs)
ck_assert(libinput_event_get_gesture_event(event) == NULL);
ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+ ck_assert(libinput_event_get_switch_event(event) == NULL);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@@ -287,6 +290,7 @@ START_TEST(event_conversion_key)
ck_assert(libinput_event_get_gesture_event(event) == NULL);
ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+ ck_assert(libinput_event_get_switch_event(event) == NULL);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@@ -338,6 +342,7 @@ START_TEST(event_conversion_touch)
ck_assert(libinput_event_get_gesture_event(event) == NULL);
ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+ ck_assert(libinput_event_get_switch_event(event) == NULL);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@@ -387,6 +392,7 @@ START_TEST(event_conversion_gesture)
ck_assert(libinput_event_get_keyboard_event(event) == NULL);
ck_assert(libinput_event_get_touch_event(event) == NULL);
ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+ ck_assert(libinput_event_get_switch_event(event) == NULL);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@@ -434,6 +440,7 @@ START_TEST(event_conversion_tablet)
ck_assert(libinput_event_get_keyboard_event(event) == NULL);
ck_assert(libinput_event_get_touch_event(event) == NULL);
ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+ ck_assert(libinput_event_get_switch_event(event) == NULL);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@@ -477,6 +484,7 @@ START_TEST(event_conversion_tablet_pad)
ck_assert(libinput_event_get_keyboard_event(event) == NULL);
ck_assert(libinput_event_get_touch_event(event) == NULL);
ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
+ ck_assert(libinput_event_get_switch_event(event) == NULL);
litest_restore_log_handler(li);
}
libinput_event_destroy(event);
@@ -486,6 +494,47 @@ START_TEST(event_conversion_tablet_pad)
}
END_TEST
+START_TEST(event_conversion_switch)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+ int sw = 0;
+
+ litest_lid_action(dev, LIBINPUT_SWITCH_STATE_ON);
+ litest_lid_action(dev, LIBINPUT_SWITCH_STATE_OFF);
+ libinput_dispatch(li);
+
+ while ((event = libinput_get_event(li))) {
+ enum libinput_event_type type;
+ type = libinput_event_get_type(event);
+
+ if (type == LIBINPUT_EVENT_SWITCH_TOGGLE) {
+ struct libinput_event_switch *s;
+ struct libinput_event *base;
+ s = libinput_event_get_switch_event(event);
+ base = libinput_event_switch_get_base_event(s);
+ ck_assert(event == base);
+
+ sw++;
+
+ litest_disable_log_handler(li);
+ ck_assert(libinput_event_get_device_notify_event(event) == NULL);
+ ck_assert(libinput_event_get_keyboard_event(event) == NULL);
+ ck_assert(libinput_event_get_pointer_event(event) == NULL);
+ ck_assert(libinput_event_get_touch_event(event) == NULL);
+ ck_assert(libinput_event_get_gesture_event(event) == NULL);
+ ck_assert(libinput_event_get_tablet_tool_event(event) == NULL);
+ ck_assert(libinput_event_get_tablet_pad_event(event) == NULL);
+ litest_restore_log_handler(li);
+ }
+ libinput_event_destroy(event);
+ }
+
+ ck_assert_int_gt(sw, 0);
+}
+END_TEST
+
START_TEST(bitfield_helpers)
{
/* This value has a bit set on all of the word boundaries we want to
@@ -859,6 +908,45 @@ START_TEST(dimension_prop_parser)
}
END_TEST
+struct parser_test_reliability {
+ char *tag;
+ bool success;
+ enum switch_reliability reliability;
+};
+
+START_TEST(reliability_prop_parser)
+{
+ struct parser_test_reliability tests[] = {
+ { "reliable", true, RELIABILITY_RELIABLE },
+ { "unreliable", false, 0 },
+ { "", false, 0 },
+ { "0", false, 0 },
+ { "1", false, 0 },
+ { NULL, false, 0, }
+ };
+ enum switch_reliability r;
+ bool success;
+ int i;
+
+ for (i = 0; tests[i].tag != NULL; i++) {
+ r = 0xaf;
+ success = parse_switch_reliability_property(tests[i].tag, &r);
+ ck_assert(success == tests[i].success);
+ if (success)
+ ck_assert_int_eq(r, tests[i].reliability);
+ else
+ ck_assert_int_eq(r, 0xaf);
+ }
+
+ success = parse_switch_reliability_property(NULL, &r);
+ ck_assert(success == true);
+ ck_assert_int_eq(r, RELIABILITY_UNKNOWN);
+
+ success = parse_switch_reliability_property("foo", NULL);
+ ck_assert(success == false);
+}
+END_TEST
+
START_TEST(time_conversion)
{
ck_assert_int_eq(us(10), 10);
@@ -1118,6 +1206,7 @@ litest_setup_tests_misc(void)
litest_add_for_device("events:conversion", event_conversion_gesture, LITEST_BCM5974);
litest_add_for_device("events:conversion", event_conversion_tablet, LITEST_WACOM_CINTIQ);
litest_add_for_device("events:conversion", event_conversion_tablet_pad, LITEST_WACOM_INTUOS5_PAD);
+ litest_add_for_device("events:conversion", event_conversion_switch, LITEST_LID_SWITCH);
litest_add_no_device("misc:bitfield_helpers", bitfield_helpers);
litest_add_no_device("context:refcount", context_ref_counting);
@@ -1130,6 +1219,7 @@ litest_setup_tests_misc(void)
litest_add_no_device("misc:parser", wheel_click_count_parser);
litest_add_no_device("misc:parser", trackpoint_accel_parser);
litest_add_no_device("misc:parser", dimension_prop_parser);
+ litest_add_no_device("misc:parser", reliability_prop_parser);
litest_add_no_device("misc:parser", safe_atoi_test);
litest_add_no_device("misc:parser", safe_atod_test);
litest_add_no_device("misc:parser", strsplit_test);
diff --git a/tools/event-debug.c b/tools/event-debug.c
index a3e460a..779b54a 100644
--- a/tools/event-debug.c
+++ b/tools/event-debug.c
@@ -133,6 +133,9 @@ print_event_header(struct libinput_event *ev)
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
type = "TABLET_PAD_STRIP";
break;
+ case LIBINPUT_EVENT_SWITCH_TOGGLE:
+ type = "SWITCH_TOGGLE";
+ break;
}
prefix = (last_device != dev) ? '-' : ' ';
@@ -194,6 +197,9 @@ print_device_notify(struct libinput_event *ev)
if (libinput_device_has_capability(dev,
LIBINPUT_DEVICE_CAP_TABLET_PAD))
printf("P");
+ if (libinput_device_has_capability(dev,
+ LIBINPUT_DEVICE_CAP_SWITCH))
+ printf("S");
if (libinput_device_get_size(dev, &w, &h) == 0)
printf(" size %.0fx%.0fmm", w, h);
@@ -706,6 +712,28 @@ print_tablet_pad_strip_event(struct libinput_event *ev)
mode);
}
+static void
+print_switch_event(struct libinput_event *ev)
+{
+ struct libinput_event_switch *sw = libinput_event_get_switch_event(ev);
+ enum libinput_switch_state state;
+ const char *which;
+
+ print_event_time(libinput_event_switch_get_time(sw));
+
+ switch (libinput_event_switch_get_switch(sw)) {
+ case LIBINPUT_SWITCH_LID:
+ which = "lid";
+ break;
+ default:
+ abort();
+ }
+
+ state = libinput_event_switch_get_switch_state(sw);
+
+ printf("switch %s state %d\n", which, state);
+}
+
static int
handle_and_print_events(struct libinput *li)
{
@@ -794,6 +822,9 @@ handle_and_print_events(struct libinput *li)
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
print_tablet_pad_strip_event(ev);
break;
+ case LIBINPUT_EVENT_SWITCH_TOGGLE:
+ print_switch_event(ev);
+ break;
}
libinput_event_destroy(ev);
diff --git a/tools/event-gui.c b/tools/event-gui.c
index e819901..155cc95 100644
--- a/tools/event-gui.c
+++ b/tools/event-gui.c
@@ -845,6 +845,8 @@ handle_event_libinput(GIOChannel *source, GIOCondition condition, gpointer data)
case LIBINPUT_EVENT_TABLET_PAD_RING:
case LIBINPUT_EVENT_TABLET_PAD_STRIP:
break;
+ case LIBINPUT_EVENT_SWITCH_TOGGLE:
+ break;
}
libinput_event_destroy(ev);
diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb
index 04bdf9a..86eea0d 100644
--- a/udev/90-libinput-model-quirks.hwdb
+++ b/udev/90-libinput-model-quirks.hwdb
@@ -17,6 +17,15 @@
# Sort by brand, model
##########################################
+# Chassis types 9 (Laptop) and 10
+# (Notebook) are expected to have working
+# lid switches
+##########################################
+libinput:name:*Lid Switch*:dmi:*:ct10:*
+libinput:name:*Lid Switch*:dmi:*:ct9:*
+ LIBINPUT_ATTR_LID_SWITCH_RELIABILITY=reliable
+
+##########################################
# ALPS
##########################################
libinput:name:*AlpsPS/2 ALPS DualPoint TouchPad:dmi:*
@@ -151,6 +160,13 @@ libinput:name:*Logitech M570*:dmi:*
LIBINPUT_MODEL_TRACKBALL=1
##########################################
+# Microsoft
+##########################################
+# Surface3 needs us to write the open lid switch event
+libinput:name:*Lid Switch*:dmi:*svnMicrosoftCorporation:pnSurface3:*
+ LIBINPUT_ATTR_LID_SWITCH_RELIABILITY=write_open
+
+##########################################
# Synaptics
##########################################
libinput:touchpad:input:b0011v0002p0007*
@@ -187,3 +203,4 @@ libinput:touchpad:input:b0003v056Ap*
##########################################
libinput:name:*Trackball*:dmi:*
LIBINPUT_MODEL_TRACKBALL=1
+
diff --git a/udev/parse_hwdb.py b/udev/parse_hwdb.py
index d90c90f..d079be2 100755
--- a/udev/parse_hwdb.py
+++ b/udev/parse_hwdb.py
@@ -98,10 +98,16 @@ def property_grammar():
('LIBINPUT_ATTR_SIZE_HINT', Group(dimension('SETTINGS*'))),
('LIBINPUT_ATTR_RESOLUTION_HINT', Group(dimension('SETTINGS*'))),
)
+
size_props = [Literal(name)('NAME') - Suppress('=') - val('VALUE')
for name, val in sz_props]
- grammar = Or(model_props + size_props);
+ reliability_tags = Or(('reliable', 'write_open'))
+ reliability = [Literal('LIBINPUT_ATTR_LID_SWITCH_RELIABILITY')('NAME') -
+ Suppress('=') -
+ reliability_tags('VALUE')]
+
+ grammar = Or(model_props + size_props + reliability)
return grammar