Merge branch 'wip/switch-interface'

This commit is contained in:
Peter Hutterer 2017-02-01 13:56:32 +10:00
commit 45d7794de2
35 changed files with 1697 additions and 177 deletions

View file

@ -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 \

16
doc/switches.dox Normal file
View file

@ -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.
*/

View file

@ -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 \

302
src/evdev-lid.c Normal file
View file

@ -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;
}

View file

@ -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 :

View file

@ -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:

View file

@ -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);
}

View file

@ -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);
}
@ -1552,6 +1553,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;

View file

@ -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++)

View file

@ -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;

View file

@ -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)
{

View file

@ -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;

View file

@ -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)
{

View file

@ -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 },
@ -1082,13 +1084,20 @@ evdev_tag_keyboard(struct evdev_device *device,
device->tags |= EVDEV_TAG_KEYBOARD;
}
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;

View file

@ -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);
@ -353,6 +390,10 @@ evdev_init_calibration(struct evdev_device *device,
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);

View file

@ -466,6 +466,9 @@ void
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,
@ -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)

View file

@ -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.

View file

@ -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)
{

View file

@ -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 *
@ -1871,6 +1932,12 @@ libinput_dispatch(struct libinput *libinput)
return 0;
}
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,
@ -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)

View file

@ -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,
};
/**
@ -597,6 +598,42 @@ void *
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
*
@ -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,
};
/**
@ -888,6 +927,19 @@ libinput_event_get_tablet_tool_event(struct libinput_event *event);
struct libinput_event_tablet_pad *
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
*
@ -2698,6 +2750,70 @@ libinput_event_tablet_pad_get_time(struct libinput_event_tablet_pad *event);
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
*/

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -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)

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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);

View file

@ -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,

View file

@ -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));
}

473
test/test-lid.c Normal file
View file

@ -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);
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -16,6 +16,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
##########################################
@ -150,6 +159,13 @@ libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO:*:pvrThinkPadX1Carbon3rd
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
##########################################
@ -187,3 +203,4 @@ libinput:touchpad:input:b0003v056Ap*
##########################################
libinput:name:*Trackball*:dmi:*
LIBINPUT_MODEL_TRACKBALL=1

View file

@ -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