diff --git a/README.md b/README.md index e2333a62a..6215e5add 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -libinput +lib(open)input ======== libinput is a library that provides a full input stack for display servers @@ -11,6 +11,22 @@ provide the common set of functionality that users expect. Input event processing includes scaling touch coordinates, generating relative pointer events from touchpads, pointer acceleration, etc. +OpenBSD related changes +----------------------- +This repository fork from https://gitlab.freedesktop.org/libinput/libinput. +It is an attempt to extend libinput so that it works with wscons(4) and +kqueue(2) and thus on OpenBSD. + +``` +$ meson setup builddir -Dlibwacom=false -Ddocumentation=false +$ cd builddir && ninja +``` + +TODO: +[X] Build and Compile on OpenBSD +[ ] Port logic from https://github.com/mpieuchot/libinput + + User documentation ------------------ diff --git a/include/libevdev/libevdev.h b/include/libevdev/libevdev.h new file mode 100644 index 000000000..35c5b704a --- /dev/null +++ b/include/libevdev/libevdev.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2013 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. + * + */ + +#ifndef LIBEVDEV_H +#define LIBEVDEV_H + +#include + +extern int libevdev_event_code_from_name(unsigned int type, const char *name); +extern const char * libevdev_event_code_get_name(unsigned int type, unsigned int code); +#endif diff --git a/include/linux/input-event-codes.h b/include/linux/input-event-codes.h new file mode 100644 index 000000000..680d81234 --- /dev/null +++ b/include/linux/input-event-codes.h @@ -0,0 +1,5 @@ +#ifdef __linux__ +#include "linux/input-event-codes.h" +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) +#include "freebsd/input-event-codes.h" +#endif diff --git a/include/linux/input.h b/include/linux/input.h index 03c512efb..2b091d5d8 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -1,5 +1,5 @@ #ifdef __linux__ #include "linux/input.h" -#elif __FreeBSD__ +#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) #include "freebsd/input.h" #endif diff --git a/meson.build b/meson.build index dccc32c2a..4458c3a87 100644 --- a/meson.build +++ b/meson.build @@ -143,11 +143,17 @@ config_h.set10('HAVE_INSTALLED_TESTS', get_option('install-tests')) # Dependencies pkgconfig = import('pkgconfig') -dep_udev = dependency('libudev') -dep_mtdev = dependency('mtdev', version : '>= 1.1.0') -dep_libevdev = dependency('libevdev') -config_h.set10('HAVE_LIBEVDEV_DISABLE_PROPERTY', - dep_libevdev.version().version_compare('>= 1.9.902')) +if host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' + dep_udev = dependency('libudev') + dep_mtdev = [] + dep_libevdev = [] +else + dep_udev = dependency('libudev') + dep_mtdev = dependency('mtdev', version : '>= 1.1.0') + dep_libevdev = dependency('libevdev') + config_h.set10('HAVE_LIBEVDEV_DISABLE_PROPERTY', + dep_libevdev.version().version_compare('>= 1.9.902')) +endif dep_lm = cc.find_library('m', required : false) dep_rt = cc.find_library('rt', required : false) @@ -158,7 +164,11 @@ includes_src = include_directories('src') ############ libwacom configuration ############ +if host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' +have_libwacom = false +else have_libwacom = get_option('libwacom') +endif config_h.set10('HAVE_LIBWACOM', have_libwacom) if have_libwacom dep_libwacom = dependency('libwacom', version : '>= 0.27') @@ -167,7 +177,7 @@ else endif ############ udev bits ############ - +if host_machine.system() != 'openbsd' and host_machine.system() != 'netbsd' executable('libinput-device-group', 'udev/libinput-device-group.c', dependencies : [dep_udev, dep_libwacom], @@ -222,6 +232,7 @@ if get_option('tests') suite : ['all']) endif +endif ############ libepoll-shim (BSD) ############ if cc.has_header_symbol('sys/epoll.h', 'epoll_create1', prefix : prefix) @@ -251,7 +262,6 @@ else endif ############ libinput-util.a ############ - # Basic compilation test to make sure the headers include and define all the # necessary bits. util_headers = [ @@ -304,11 +314,14 @@ src_libfilter = [ 'src/filter-trackpoint.c', 'src/filter-trackpoint-flat.c', ] +if host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' + dep_libfilter = [] +else libfilter = static_library('filter', src_libfilter, dependencies : [dep_udev, dep_libwacom], include_directories : includes_include) dep_libfilter = declare_dependency(link_with : libfilter) - +endif ############ libquirks.a ############# libinput_data_path = dir_data libinput_data_override_path = dir_overrides / 'local-overrides.quirks' @@ -332,14 +345,25 @@ libquirks = static_library('quirks', src_libquirks, dep_libquirks = declare_dependency(link_with : libquirks) # Create /etc/libinput +if host_machine.system() != 'openbsd' and host_machine.system() != 'netbsd' if meson.version().version_compare('>= 0.60') install_emptydir(dir_etc / 'libinput') else install_subdir('libinput', install_dir : dir_etc) endif +endif ############ libinput.so ############ install_headers('src/libinput.h') +if host_machine.system() == 'openbsd' or host_machine.system() == 'netbsd' +src_libinput = src_libfilter + [ + 'src/libinput_openbsd.c', + 'src/libinput-private-config.c', + 'src/timer.c', + 'src/wskbdmap.c', + 'src/wscons.c' +] +else src_libinput = src_libfilter + [ 'src/libinput.c', 'src/libinput-private-config.c', @@ -362,6 +386,7 @@ src_libinput = src_libfilter + [ 'src/udev-seat.c', 'src/timer.c', ] +endif deps_libinput = [ dep_mtdev, @@ -391,13 +416,26 @@ mapfile = dir_src / 'libinput.sym' version_flag = '-Wl,--version-script,@0@'.format(mapfile) lib_libinput = shared_library('input', src_libinput, - include_directories : [include_directories('.'), includes_include], + include_directories : [include_directories('.'), + include_directories('include'), + include_directories('include/linux/freebsd'), + includes_include], dependencies : deps_libinput, version : libinput_so_version, link_args : version_flag, link_depends : mapfile, install : true ) +if host_machine.system() == 'openbsd' +install_headers('include/linux/freebsd/input-event-codes.h', subdir: 'linux/freebsd') +install_headers('include/linux/freebsd/input.h', subdir: 'linux/freebsd') + +install_headers('include/linux/linux/input-event-codes.h', subdir: 'linux/linux') +install_headers('include/linux/linux/input.h', subdir: 'linux/linux') + +install_headers('include/linux/input.h', subdir: 'linux') +install_headers('include/linux/input-event-codes.h', subdir: 'linux') +endif dep_libinput = declare_dependency( link_with : lib_libinput, @@ -432,6 +470,8 @@ endif subdir('completion/zsh') ############ tools ############ +if host_machine.system() != 'openbsd' and host_machine.system() != 'netbsd' + libinput_tool_path = dir_libexec config_h.set_quoted('LIBINPUT_TOOL_PATH', libinput_tool_path) tools_shared_sources = [ 'tools/shared.c' ] @@ -675,7 +715,9 @@ test('tools-builddir-lookup-installed', suite : ['all'], workdir : '/tmp') +endif ############ tests ############ +if host_machine.system() != 'openbsd' and host_machine.system() != 'netbsd' test('symbols-leak-test', find_program('test/symbols-leak-test'), @@ -729,8 +771,10 @@ if get_option('tests') config_h.set10('HAVE_GSTACK', gstack.found()) # for inhibit support during test run +if host_machine.system() != 'openbsd' and host_machine.system() != 'netbsd' dep_libsystemd = dependency('libsystemd', version : '>= 221', required : false) config_h.set10('HAVE_LIBSYSTEMD', dep_libsystemd.found()) +endif litest_sources = [ 'src/libinput-private-config.c', @@ -839,6 +883,7 @@ if get_option('tests') 'test/litest.c', ] +if host_machine.system() != 'openbsd' and host_machine.system() != 'netbsd' dep_dl = cc.find_library('dl') deps_litest = [ dep_libinput, @@ -850,6 +895,14 @@ if get_option('tests') dep_libsystemd, dep_libquirks, ] +else + deps_litest = [ + dep_libinput, + dep_check, + dep_lm, + dep_libquirks, + ] +endif litest_config_h = configuration_data() litest_config_h.set_quoted('LIBINPUT_DEVICE_GROUPS_RULES_FILE', @@ -973,6 +1026,7 @@ if get_option('tests') endif +endif ############ man pages ############ man_config = configuration_data() man_config.set('LIBINPUT_VERSION', meson.project_version()) @@ -1032,3 +1086,7 @@ configure_file(input : 'tools/libinput-quirks.man', ############ output files ############ configure_file(output : 'config.h', configuration : config_h) + +warning('*********************************************************************') +warning('This branch is no longer updated. Please switch to the "main" branch.') +warning('*********************************************************************') diff --git a/src/libinput-private.h b/src/libinput-private.h index dff0aaae6..dab68f2e3 100644 --- a/src/libinput-private.h +++ b/src/libinput-private.h @@ -420,6 +420,9 @@ struct libinput_device { void *user_data; int refcount; struct libinput_device_config config; + struct libinput_source *source; + char* devname; + int fd; }; enum libinput_tablet_tool_axis { @@ -1011,4 +1014,14 @@ static inline void *libinput_libwacom_ref(struct libinput *li) { return NULL; } static inline void libinput_libwacom_unref(struct libinput *li) {} #endif + +#if defined(__OpenBSD__) || defined(__NetBSD__) +void +axis_notify_event(struct libinput_device *device, + uint64_t time, + const struct normalized_coords *delta, + const struct device_float_coords *raw); +#endif + + #endif /* LIBINPUT_PRIVATE_H */ diff --git a/src/libinput-util.h b/src/libinput-util.h index 1f9863c64..a04052dc8 100644 --- a/src/libinput-util.h +++ b/src/libinput-util.h @@ -66,4 +66,9 @@ #define LIBINPUT_EXPORT __attribute__ ((visibility("default"))) #define LIBINPUT_UNUSED __attribute__ ((unused)) +#if defined(__OpenBSD__) || defined(__NetBSD__) +#define bit(x_) (1UL << (x_)) +#define NBITS(b) (b * 8) +#endif + #endif /* LIBINPUT_UTIL_H */ diff --git a/src/libinput_openbsd.c b/src/libinput_openbsd.c new file mode 100644 index 000000000..ae20cc3ae --- /dev/null +++ b/src/libinput_openbsd.c @@ -0,0 +1,4811 @@ +/* + * Copyright © 2013 Jonas Ådahl + * Copyright © 2013-2018 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libinput.h" +#include "libinput-private.h" +#include "timer.h" +#include "quirks.h" + +#include "wscons.h" + +#define require_event_type(li_, type_, retval_, ...) \ + if (type_ == LIBINPUT_EVENT_NONE) abort(); \ + if (!check_event_type(li_, __func__, type_, __VA_ARGS__, -1)) \ + return retval_; \ + +#define ASSERT_INT_SIZE(type_) \ + static_assert(sizeof(type_) == sizeof(unsigned int), \ + "sizeof(" #type_ ") must be sizeof(uint)") + +ASSERT_INT_SIZE(enum libinput_log_priority); +ASSERT_INT_SIZE(enum libinput_device_capability); +ASSERT_INT_SIZE(enum libinput_key_state); +ASSERT_INT_SIZE(enum libinput_led); +ASSERT_INT_SIZE(enum libinput_button_state); +ASSERT_INT_SIZE(enum libinput_pointer_axis); +ASSERT_INT_SIZE(enum libinput_pointer_axis_source); +ASSERT_INT_SIZE(enum libinput_tablet_pad_ring_axis_source); +ASSERT_INT_SIZE(enum libinput_tablet_pad_strip_axis_source); +ASSERT_INT_SIZE(enum libinput_tablet_tool_type); +ASSERT_INT_SIZE(enum libinput_tablet_tool_proximity_state); +ASSERT_INT_SIZE(enum libinput_tablet_tool_tip_state); +ASSERT_INT_SIZE(enum libinput_switch_state); +ASSERT_INT_SIZE(enum libinput_switch); +ASSERT_INT_SIZE(enum libinput_event_type); +ASSERT_INT_SIZE(enum libinput_config_status); +ASSERT_INT_SIZE(enum libinput_config_tap_state); +ASSERT_INT_SIZE(enum libinput_config_tap_button_map); +ASSERT_INT_SIZE(enum libinput_config_drag_state); +ASSERT_INT_SIZE(enum libinput_config_drag_lock_state); +ASSERT_INT_SIZE(enum libinput_config_send_events_mode); +ASSERT_INT_SIZE(enum libinput_config_accel_profile); +ASSERT_INT_SIZE(enum libinput_config_click_method); +ASSERT_INT_SIZE(enum libinput_config_clickfinger_button_map); +ASSERT_INT_SIZE(enum libinput_config_middle_emulation_state); +ASSERT_INT_SIZE(enum libinput_config_scroll_method); +ASSERT_INT_SIZE(enum libinput_config_dwt_state); +ASSERT_INT_SIZE(enum libinput_config_dwtp_state); + +static inline const char * +event_type_to_str(enum libinput_event_type type) +{ + switch(type) { + CASE_RETURN_STRING(LIBINPUT_EVENT_DEVICE_ADDED); + CASE_RETURN_STRING(LIBINPUT_EVENT_DEVICE_REMOVED); + CASE_RETURN_STRING(LIBINPUT_EVENT_KEYBOARD_KEY); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_MOTION); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_BUTTON); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_AXIS); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_SCROLL_WHEEL); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_SCROLL_FINGER); + CASE_RETURN_STRING(LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_DOWN); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_UP); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_MOTION); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_CANCEL); + CASE_RETURN_STRING(LIBINPUT_EVENT_TOUCH_FRAME); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_AXIS); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_TIP); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_TOOL_BUTTON); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_BUTTON); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_RING); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_STRIP); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_KEY); + CASE_RETURN_STRING(LIBINPUT_EVENT_TABLET_PAD_DIAL); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_SWIPE_END); + 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_GESTURE_HOLD_BEGIN); + CASE_RETURN_STRING(LIBINPUT_EVENT_GESTURE_HOLD_END); + CASE_RETURN_STRING(LIBINPUT_EVENT_SWITCH_TOGGLE); + case LIBINPUT_EVENT_NONE: + abort(); + } + + return NULL; +} + +static inline bool +check_event_type(struct libinput *libinput, + const char *function_name, + unsigned int type_in, + ...) +{ + bool rc = false; + va_list args; + unsigned int type_permitted; + + va_start(args, type_in); + type_permitted = va_arg(args, unsigned int); + + while (type_permitted != (unsigned int)-1) { + if (type_permitted == type_in) { + rc = true; + break; + } + type_permitted = va_arg(args, unsigned int); + } + + va_end(args); + + if (!rc) { + const char *name = event_type_to_str(type_in); + log_bug_client(libinput, + "Invalid event type %s (%d) passed to %s()\n", + name, type_in, function_name); + } + + return rc; +} + +struct libinput_source { + libinput_source_dispatch_t dispatch; + void *user_data; + int fd; + struct list link; +}; + +struct libinput_event_device_notify { + struct libinput_event base; +}; + +struct libinput_event_keyboard { + struct libinput_event base; + uint64_t time; + uint32_t key; + uint32_t seat_key_count; + enum libinput_key_state state; +}; + +struct libinput_event_pointer { + struct libinput_event base; + uint64_t time; + struct normalized_coords delta; + struct device_float_coords delta_raw; + struct device_coords absolute; + struct discrete_coords discrete; + struct wheel_v120 v120; + uint32_t button; + uint32_t seat_button_count; + enum libinput_button_state state; + enum libinput_pointer_axis_source source; + uint32_t axes; +}; + +struct libinput_event_touch { + struct libinput_event base; + uint64_t time; + int32_t slot; + int32_t seat_slot; + struct device_coords point; +}; + +struct libinput_event_gesture { + struct libinput_event base; + uint64_t time; + int finger_count; + int cancelled; + struct normalized_coords delta; + struct normalized_coords delta_unaccel; + double scale; + double angle; +}; + +struct libinput_event_tablet_tool { + struct libinput_event base; + uint32_t button; + enum libinput_button_state state; + uint32_t seat_button_count; + uint64_t time; + struct tablet_axes axes; + unsigned char changed_axes[NCHARS(LIBINPUT_TABLET_TOOL_AXIS_MAX + 1)]; + struct libinput_tablet_tool *tool; + enum libinput_tablet_tool_proximity_state proximity_state; + enum libinput_tablet_tool_tip_state tip_state; +}; + +struct libinput_event_tablet_pad { + struct libinput_event base; + unsigned int mode; + struct libinput_tablet_pad_mode_group *mode_group; + uint64_t time; + struct { + uint32_t number; + enum libinput_button_state state; + } button; + struct { + uint32_t code; + enum libinput_key_state state; + } key; + struct { + enum libinput_tablet_pad_ring_axis_source source; + double position; + int number; + } ring; + struct { + enum libinput_tablet_pad_strip_axis_source source; + double position; + int number; + } 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, + enum libinput_log_priority priority, + const char *format, va_list args) +{ + const char *prefix; + + switch(priority) { + case LIBINPUT_LOG_PRIORITY_DEBUG: prefix = "debug"; break; + case LIBINPUT_LOG_PRIORITY_INFO: prefix = "info"; break; + case LIBINPUT_LOG_PRIORITY_ERROR: prefix = "error"; break; + default: prefix=""; break; + } + + fprintf(stderr, "libinput %s: ", prefix); + vfprintf(stderr, format, args); +} + +void +log_msg_va(struct libinput *libinput, + enum libinput_log_priority priority, + const char *format, + va_list args) +{ + if (is_logged(libinput, priority)) + libinput->log_handler(libinput, priority, format, args); +} + +void +log_msg(struct libinput *libinput, + enum libinput_log_priority priority, + const char *format, ...) +{ + va_list args; + + va_start(args, format); + log_msg_va(libinput, priority, format, args); + va_end(args); +} + +void +log_msg_ratelimit(struct libinput *libinput, + struct ratelimit *ratelimit, + enum libinput_log_priority priority, + const char *format, ...) +{ + va_list args; + enum ratelimit_state state; + + state = ratelimit_test(ratelimit); + if (state == RATELIMIT_EXCEEDED) + return; + + va_start(args, format); + log_msg_va(libinput, priority, format, args); + va_end(args); + + if (state == RATELIMIT_THRESHOLD) + log_msg(libinput, + priority, + "WARNING: log rate limit exceeded (%d msgs per %dms). Discarding future messages.\n", + ratelimit->burst, + us2ms(ratelimit->interval)); +} + +LIBINPUT_EXPORT void +libinput_log_set_priority(struct libinput *libinput, + enum libinput_log_priority priority) +{ + libinput->log_priority = priority; +} + +LIBINPUT_EXPORT enum libinput_log_priority +libinput_log_get_priority(const struct libinput *libinput) +{ + return libinput->log_priority; +} + +LIBINPUT_EXPORT void +libinput_log_set_handler(struct libinput *libinput, + libinput_log_handler log_handler) +{ + libinput->log_handler = log_handler; +} + +static void +libinput_device_group_destroy(struct libinput_device_group *group); + +static void +libinput_post_event(struct libinput *libinput, + struct libinput_event *event); + +LIBINPUT_EXPORT enum libinput_event_type +libinput_event_get_type(struct libinput_event *event) +{ + return event->type; +} + +LIBINPUT_EXPORT struct libinput * +libinput_event_get_context(struct libinput_event *event) +{ + return event->device->seat->libinput; +} + +LIBINPUT_EXPORT struct libinput_device * +libinput_event_get_device(struct libinput_event *event) +{ + return event->device; +} + +LIBINPUT_EXPORT struct libinput_event_pointer * +libinput_event_get_pointer_event(struct libinput_event *event) +{ + require_event_type(libinput_event_get_context(event), + event->type, + NULL, + LIBINPUT_EVENT_POINTER_MOTION, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, + LIBINPUT_EVENT_POINTER_BUTTON, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + LIBINPUT_EVENT_POINTER_SCROLL_FINGER, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_EVENT_POINTER_AXIS); + + return (struct libinput_event_pointer *) event; +} + +LIBINPUT_EXPORT struct libinput_event_keyboard * +libinput_event_get_keyboard_event(struct libinput_event *event) +{ + require_event_type(libinput_event_get_context(event), + event->type, + NULL, + LIBINPUT_EVENT_KEYBOARD_KEY); + + return (struct libinput_event_keyboard *) event; +} + +LIBINPUT_EXPORT struct libinput_event_touch * +libinput_event_get_touch_event(struct libinput_event *event) +{ + require_event_type(libinput_event_get_context(event), + event->type, + NULL, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_UP, + LIBINPUT_EVENT_TOUCH_MOTION, + LIBINPUT_EVENT_TOUCH_CANCEL, + LIBINPUT_EVENT_TOUCH_FRAME); + return (struct libinput_event_touch *) event; +} + +LIBINPUT_EXPORT struct libinput_event_gesture * +libinput_event_get_gesture_event(struct libinput_event *event) +{ + require_event_type(libinput_event_get_context(event), + event->type, + NULL, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_HOLD_BEGIN, + LIBINPUT_EVENT_GESTURE_HOLD_END); + + return (struct libinput_event_gesture *) event; +} + +LIBINPUT_EXPORT struct libinput_event_tablet_tool * +libinput_event_get_tablet_tool_event(struct libinput_event *event) +{ + require_event_type(libinput_event_get_context(event), + event->type, + NULL, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON); + + return (struct libinput_event_tablet_tool *) event; +} + +LIBINPUT_EXPORT struct libinput_event_tablet_pad * +libinput_event_get_tablet_pad_event(struct libinput_event *event) +{ + require_event_type(libinput_event_get_context(event), + event->type, + NULL, + LIBINPUT_EVENT_TABLET_PAD_RING, + LIBINPUT_EVENT_TABLET_PAD_STRIP, + LIBINPUT_EVENT_TABLET_PAD_BUTTON, + LIBINPUT_EVENT_TABLET_PAD_KEY); + + return (struct libinput_event_tablet_pad *) event; +} + +LIBINPUT_EXPORT struct libinput_event_device_notify * +libinput_event_get_device_notify_event(struct libinput_event *event) +{ + require_event_type(libinput_event_get_context(event), + event->type, + NULL, + LIBINPUT_EVENT_DEVICE_ADDED, + LIBINPUT_EVENT_DEVICE_REMOVED); + + 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) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_KEYBOARD_KEY); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_keyboard_get_time_usec(struct libinput_event_keyboard *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_KEYBOARD_KEY); + + return event->time; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_keyboard_get_key(struct libinput_event_keyboard *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_KEYBOARD_KEY); + + return event->key; +} + +LIBINPUT_EXPORT enum libinput_key_state +libinput_event_keyboard_get_key_state(struct libinput_event_keyboard *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_KEYBOARD_KEY); + + return event->state; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_keyboard_get_seat_key_count( + struct libinput_event_keyboard *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_KEYBOARD_KEY); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->seat_key_count; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_pointer_get_time(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, + LIBINPUT_EVENT_POINTER_BUTTON, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + LIBINPUT_EVENT_POINTER_SCROLL_FINGER, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_EVENT_POINTER_AXIS); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_pointer_get_time_usec(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, + LIBINPUT_EVENT_POINTER_BUTTON, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + LIBINPUT_EVENT_POINTER_SCROLL_FINGER, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_EVENT_POINTER_AXIS); + + return event->time; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_dx(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION); + + return event->delta.x; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_dy(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION); + + return event->delta.y; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_dx_unaccelerated( + struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION); + + // fprintf(stderr, "%s: partial stub\n", __func__); + return event->delta_raw.x; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_dy_unaccelerated( + struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION); + + // fprintf(stderr, "%s: partial stub\n", __func__); + return event->delta_raw.y; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_absolute_x(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); + + fprintf(stderr, "%s: stub\n", __func__); + return (double)(-1); +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_absolute_y(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); + + fprintf(stderr, "%s: stub\n", __func__); + return (double)(-1); +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_absolute_x_transformed( + struct libinput_event_pointer *event, + uint32_t width) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); + + fprintf(stderr, "%s: stub\n", __func__); + return (double)(-1); +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_absolute_y_transformed( + struct libinput_event_pointer *event, + uint32_t height) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE); + + fprintf(stderr, "%s: stub\n", __func__); + return (double)(-1); +} + +LIBINPUT_EXPORT uint32_t +libinput_event_pointer_get_button(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_BUTTON); + + return event->button; +} + +LIBINPUT_EXPORT enum libinput_button_state +libinput_event_pointer_get_button_state(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_BUTTON); + + return event->state; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_pointer_get_seat_button_count( + struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_BUTTON); + + // fprintf(stderr, "%s: partial stub\n", __func__); + return event->seat_button_count; +} + +LIBINPUT_EXPORT int +libinput_event_pointer_has_axis(struct libinput_event_pointer *event, + enum libinput_pointer_axis axis) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + LIBINPUT_EVENT_POINTER_SCROLL_FINGER, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_EVENT_POINTER_AXIS); + + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + return !!(event->axes & bit(axis)); + } + + return 0; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_axis_value(struct libinput_event_pointer *event, + enum libinput_pointer_axis axis) +{ + // XXX differnt + struct libinput *libinput = event->base.device->seat->libinput; + double value = 0; + + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_POINTER_AXIS); + + if (!libinput_event_pointer_has_axis(event, axis)) { + log_bug_client(libinput, "value requested for unset axis\n"); + } else { + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + value = event->delta.x; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + value = event->delta.y; + break; + } + } + + return value; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_axis_value_discrete(struct libinput_event_pointer *event, + enum libinput_pointer_axis axis) +{ + // XXX differnt + struct libinput *libinput = event->base.device->seat->libinput; + double value = 0; + + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_POINTER_AXIS); + + if (!libinput_event_pointer_has_axis(event, axis)) { + log_bug_client(libinput, "value requested for unset axis\n"); + } else { + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + value = event->discrete.x; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + value = event->discrete.y; + break; + } + } + return value; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_scroll_value(struct libinput_event_pointer *event, + enum libinput_pointer_axis axis) +{ + struct libinput *libinput = event->base.device->seat->libinput; + double value = 0; + + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + LIBINPUT_EVENT_POINTER_SCROLL_FINGER, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS); + + if (!libinput_event_pointer_has_axis(event, axis)) { + log_bug_client(libinput, "value requested for unset axis\n"); + } else { + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + value = event->delta.x; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + value = event->delta.y; + break; + } + } + return value; +} + +LIBINPUT_EXPORT double +libinput_event_pointer_get_scroll_value_v120(struct libinput_event_pointer *event, + enum libinput_pointer_axis axis) +{ + struct libinput *libinput = event->base.device->seat->libinput; + double value = 0; + + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL); + + if (!libinput_event_pointer_has_axis(event, axis)) { + log_bug_client(libinput, "value requested for unset axis\n"); + } else { + switch (axis) { + case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: + value = event->v120.x; + break; + case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: + value = event->v120.y; + break; + } + } + return value; +} + +LIBINPUT_EXPORT enum libinput_pointer_axis_source +libinput_event_pointer_get_axis_source(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_POINTER_AXIS); + + // return event->source; + /* XXX impossible to return an error, so pick a source type. */ + return LIBINPUT_POINTER_AXIS_SOURCE_WHEEL; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_touch_get_time(struct libinput_event_touch *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_UP, + LIBINPUT_EVENT_TOUCH_MOTION, + LIBINPUT_EVENT_TOUCH_CANCEL, + LIBINPUT_EVENT_TOUCH_FRAME); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_touch_get_time_usec(struct libinput_event_touch *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_UP, + LIBINPUT_EVENT_TOUCH_MOTION, + LIBINPUT_EVENT_TOUCH_CANCEL, + LIBINPUT_EVENT_TOUCH_FRAME); + + return event->time; +} + +LIBINPUT_EXPORT int32_t +libinput_event_touch_get_slot(struct libinput_event_touch *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_UP, + LIBINPUT_EVENT_TOUCH_MOTION, + LIBINPUT_EVENT_TOUCH_CANCEL); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->slot; +} + +LIBINPUT_EXPORT int32_t +libinput_event_touch_get_seat_slot(struct libinput_event_touch *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_UP, + LIBINPUT_EVENT_TOUCH_MOTION, + LIBINPUT_EVENT_TOUCH_CANCEL); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->seat_slot; +} + +LIBINPUT_EXPORT double +libinput_event_touch_get_x(struct libinput_event_touch *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_MOTION); + + fprintf(stderr, "%s: stub\n", __func__); + return (double)(-1); +} + +LIBINPUT_EXPORT double +libinput_event_touch_get_x_transformed(struct libinput_event_touch *event, + uint32_t width) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_MOTION); + + fprintf(stderr, "%s: stub\n", __func__); + return (double)(-1); +} + +LIBINPUT_EXPORT double +libinput_event_touch_get_y_transformed(struct libinput_event_touch *event, + uint32_t height) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_MOTION); + + fprintf(stderr, "%s: stub\n", __func__); + return (double)(-1); +} + +LIBINPUT_EXPORT double +libinput_event_touch_get_y(struct libinput_event_touch *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_MOTION); + + fprintf(stderr, "%s: stub\n", __func__); + return (double)(-1); +} + +LIBINPUT_EXPORT uint32_t +libinput_event_gesture_get_time(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + LIBINPUT_EVENT_GESTURE_HOLD_BEGIN, + LIBINPUT_EVENT_GESTURE_HOLD_END); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_gesture_get_time_usec(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + LIBINPUT_EVENT_GESTURE_HOLD_BEGIN, + LIBINPUT_EVENT_GESTURE_HOLD_END); + + return event->time; +} + +LIBINPUT_EXPORT int +libinput_event_gesture_get_finger_count(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + LIBINPUT_EVENT_GESTURE_HOLD_BEGIN, + LIBINPUT_EVENT_GESTURE_HOLD_END); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->finger_count; +} + +LIBINPUT_EXPORT int +libinput_event_gesture_get_cancelled(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + LIBINPUT_EVENT_GESTURE_HOLD_END); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->cancelled; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_dx(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->delta.x; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_dy(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->delta.y; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_dx_unaccelerated( + struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->delta_unaccel.x; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_dy_unaccelerated( + struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->delta_unaccel.y; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_scale(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->scale; +} + +LIBINPUT_EXPORT double +libinput_event_gesture_get_angle_delta(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END); + + fprintf(stderr, "%s: partial stub\n", __func__); + return event->angle; +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_x_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_X); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_y_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_Y); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_pressure_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_PRESSURE); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_distance_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_DISTANCE); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_tilt_x_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_TILT_X); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_tilt_y_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_TILT_Y); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_rotation_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_slider_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_SLIDER); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_size_major_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_size_minor_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_SIZE_MINOR); +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_wheel_has_changed( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return bit_is_set(event->changed_axes, + LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL); +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_x(struct libinput_event_tablet_tool *event) +{ + return 0xdeadbeef; // TODO +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_y(struct libinput_event_tablet_tool *event) +{ + return 0xdeadbeef; // TODO +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_dx(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.delta.x; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_dy(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.delta.y; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_pressure(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.pressure; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_distance(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.distance; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_tilt_x(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.tilt.x; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_tilt_y(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.tilt.y; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_rotation(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.rotation; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_slider_position(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.slider; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_size_major(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.size.major; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_size_minor(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.size.minor; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_wheel_delta(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.wheel; +} + +LIBINPUT_EXPORT int +libinput_event_tablet_tool_get_wheel_delta_discrete( + struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->axes.wheel_discrete; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_x_transformed(struct libinput_event_tablet_tool *event, + uint32_t width) +{ + return 0xdeadbeef; // TODO +} + +LIBINPUT_EXPORT double +libinput_event_tablet_tool_get_y_transformed(struct libinput_event_tablet_tool *event, + uint32_t height) +{ + return 0xdeadbeef; // TODO +} + +LIBINPUT_EXPORT struct libinput_tablet_tool * +libinput_event_tablet_tool_get_tool(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->tool; +} + +LIBINPUT_EXPORT enum libinput_tablet_tool_proximity_state +libinput_event_tablet_tool_get_proximity_state(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->proximity_state; +} + +LIBINPUT_EXPORT enum libinput_tablet_tool_tip_state +libinput_event_tablet_tool_get_tip_state(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->tip_state; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_tablet_tool_get_time(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_tablet_tool_get_time_usec(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY); + + return event->time; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_tablet_tool_get_button(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON); + + return event->button; +} + +LIBINPUT_EXPORT enum libinput_button_state +libinput_event_tablet_tool_get_button_state(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON); + + return event->state; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_tablet_tool_get_seat_button_count(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON); + + return event->seat_button_count; +} + +LIBINPUT_EXPORT enum libinput_tablet_tool_type +libinput_tablet_tool_get_type(struct libinput_tablet_tool *tool) +{ + return tool->type; +} + +LIBINPUT_EXPORT uint64_t +libinput_tablet_tool_get_tool_id(struct libinput_tablet_tool *tool) +{ + return tool->tool_id; +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_is_unique(struct libinput_tablet_tool *tool) +{ + return tool->serial != 0; +} + +LIBINPUT_EXPORT uint64_t +libinput_tablet_tool_get_serial(struct libinput_tablet_tool *tool) +{ + return tool->serial; +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_has_pressure(struct libinput_tablet_tool *tool) +{ + return bit_is_set(tool->axis_caps, + LIBINPUT_TABLET_TOOL_AXIS_PRESSURE); +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_has_distance(struct libinput_tablet_tool *tool) +{ + return bit_is_set(tool->axis_caps, + LIBINPUT_TABLET_TOOL_AXIS_DISTANCE); +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_has_tilt(struct libinput_tablet_tool *tool) +{ + return bit_is_set(tool->axis_caps, + LIBINPUT_TABLET_TOOL_AXIS_TILT_X); +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_has_rotation(struct libinput_tablet_tool *tool) +{ + return bit_is_set(tool->axis_caps, + LIBINPUT_TABLET_TOOL_AXIS_ROTATION_Z); +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_has_slider(struct libinput_tablet_tool *tool) +{ + return bit_is_set(tool->axis_caps, + LIBINPUT_TABLET_TOOL_AXIS_SLIDER); +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_has_wheel(struct libinput_tablet_tool *tool) +{ + return bit_is_set(tool->axis_caps, + LIBINPUT_TABLET_TOOL_AXIS_REL_WHEEL); +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_has_size(struct libinput_tablet_tool *tool) +{ + return bit_is_set(tool->axis_caps, + LIBINPUT_TABLET_TOOL_AXIS_SIZE_MAJOR); +} + +LIBINPUT_EXPORT int +libinput_tablet_tool_has_button(struct libinput_tablet_tool *tool, + uint32_t code) +{ + if (NCHARS(code) > sizeof(tool->buttons)) + return 0; + + return bit_is_set(tool->buttons, code); +} + +LIBINPUT_EXPORT void +libinput_tablet_tool_set_user_data(struct libinput_tablet_tool *tool, + void *user_data) +{ + tool->user_data = user_data; +} + +LIBINPUT_EXPORT void * +libinput_tablet_tool_get_user_data(struct libinput_tablet_tool *tool) +{ + return tool->user_data; +} + +LIBINPUT_EXPORT struct libinput_tablet_tool * +libinput_tablet_tool_ref(struct libinput_tablet_tool *tool) +{ + tool->refcount++; + return tool; +} + +LIBINPUT_EXPORT struct libinput_tablet_tool * +libinput_tablet_tool_unref(struct libinput_tablet_tool *tool) +{ + assert(tool->refcount > 0); + + tool->refcount--; + if (tool->refcount > 0) + return tool; + + list_remove(&tool->link); + free(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, + libinput_source_dispatch_t dispatch, + void *user_data) +{ + struct libinput_source *source; + struct epoll_event ep; + + source = zalloc(sizeof *source); + source->dispatch = dispatch; + source->user_data = user_data; + source->fd = fd; + + memset(&ep, 0, sizeof ep); + ep.events = EPOLLIN; + ep.data.ptr = source; + + if (epoll_ctl(libinput->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) { + free(source); + return NULL; + } + + return source; +} + +void +libinput_remove_source(struct libinput *libinput, + struct libinput_source *source) +{ + epoll_ctl(libinput->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL); + source->fd = -1; + list_insert(&libinput->source_destroy_list, &source->link); +} + +int +libinput_init(struct libinput *libinput, + const struct libinput_interface *interface, + const struct libinput_interface_backend *interface_backend, + void *user_data) +{ + assert(interface->open_restricted != NULL); + assert(interface->close_restricted != NULL); + + libinput->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + if (libinput->epoll_fd < 0) + return -1; + + libinput->events_len = 4; + libinput->events = zalloc(libinput->events_len * sizeof(*libinput->events)); + libinput->log_handler = libinput_default_log_func; + libinput->log_priority = LIBINPUT_LOG_PRIORITY_ERROR; + libinput->interface = interface; + libinput->interface_backend = interface_backend; + libinput->user_data = user_data; + libinput->refcount = 1; + list_init(&libinput->source_destroy_list); + list_init(&libinput->seat_list); + list_init(&libinput->device_group_list); + list_init(&libinput->tool_list); + + if (libinput_timer_subsys_init(libinput) != 0) { + free(libinput->events); + close(libinput->epoll_fd); + return -1; + } + + return 0; +} + +void +libinput_init_quirks(struct libinput *libinput) +{ + const char *data_path, + *override_file = NULL; + struct quirks_context *quirks; + + if (libinput->quirks_initialized) + return; + + /* If we fail, we'll fail next time too */ + libinput->quirks_initialized = true; + + data_path = getenv("LIBINPUT_QUIRKS_DIR"); + if (!data_path) { + data_path = LIBINPUT_QUIRKS_DIR; + override_file = LIBINPUT_QUIRKS_OVERRIDE_FILE; + } + + quirks = quirks_init_subsystem(data_path, + override_file, + log_msg_va, + libinput, + QLOG_LIBINPUT_LOGGING); + if (!quirks) { + log_error(libinput, + "Failed to load the device quirks from %s%s%s. " + "This will negatively affect device behavior. " + "See %s/device-quirks.html for details.\n", + data_path, + override_file ? " and " : "", + override_file ? override_file : "", + HTTP_DOC_LINK + ); + return; + } + + libinput->quirks = quirks; +} + +static void +libinput_device_destroy(struct libinput_device *device); + +static void +libinput_seat_destroy(struct libinput_seat *seat); + +static void +libinput_drop_destroyed_sources(struct libinput *libinput) +{ + struct libinput_source *source; + + list_for_each_safe(source, &libinput->source_destroy_list, link) + free(source); + list_init(&libinput->source_destroy_list); +} + +LIBINPUT_EXPORT struct libinput * +libinput_ref(struct libinput *libinput) +{ + libinput->refcount++; + return libinput; +} + +LIBINPUT_EXPORT struct libinput * +libinput_unref(struct libinput *libinput) +{ + struct libinput_event *event; + struct libinput_device *device; + struct libinput_seat *seat; + struct libinput_tablet_tool *tool; + struct libinput_device_group *group; + + if (libinput == NULL) + return NULL; + + assert(libinput->refcount > 0); + libinput->refcount--; + if (libinput->refcount > 0) + return libinput; + + libinput_suspend(libinput); + + libinput->interface_backend->destroy(libinput); + + while ((event = libinput_get_event(libinput))) + libinput_event_destroy(event); + + free(libinput->events); + + list_for_each_safe(seat, &libinput->seat_list, link) { + list_for_each_safe(device, + &seat->devices_list, + link) + libinput_device_destroy(device); + + libinput_seat_destroy(seat); + } + + list_for_each_safe(group, + &libinput->device_group_list, + link) { + libinput_device_group_destroy(group); + } + + list_for_each_safe(tool, &libinput->tool_list, link) { + libinput_tablet_tool_unref(tool); + } + + libinput_timer_subsys_destroy(libinput); + libinput_drop_destroyed_sources(libinput); + quirks_context_unref(libinput->quirks); + close(libinput->epoll_fd); + free(libinput); + + return NULL; +} + +static void +libinput_event_tablet_tool_destroy(struct libinput_event_tablet_tool *event) +{ + libinput_tablet_tool_unref(event->tool); +} + +static void +libinput_event_tablet_pad_destroy(struct libinput_event_tablet_pad *event) +{ + if (event->base.type != LIBINPUT_EVENT_TABLET_PAD_KEY) + libinput_tablet_pad_mode_group_unref(event->mode_group); +} + +LIBINPUT_EXPORT void +libinput_event_destroy(struct libinput_event *event) +{ + if (event == NULL) + return; + + switch(event->type) { + case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: + case LIBINPUT_EVENT_TABLET_TOOL_AXIS: + case LIBINPUT_EVENT_TABLET_TOOL_TIP: + case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: + libinput_event_tablet_tool_destroy( + libinput_event_get_tablet_tool_event(event)); + break; + case LIBINPUT_EVENT_TABLET_PAD_RING: + case LIBINPUT_EVENT_TABLET_PAD_STRIP: + case LIBINPUT_EVENT_TABLET_PAD_BUTTON: + case LIBINPUT_EVENT_TABLET_PAD_KEY: + libinput_event_tablet_pad_destroy( + libinput_event_get_tablet_pad_event(event)); + break; + default: + break; + } + + if (event->device) + libinput_device_unref(event->device); + + free(event); +} + +int +open_restricted(struct libinput *libinput, + const char *path, int flags) +{ + return libinput->interface->open_restricted(path, + flags, + libinput->user_data); +} + +void +close_restricted(struct libinput *libinput, int fd) +{ + libinput->interface->close_restricted(fd, libinput->user_data); +} + +bool +ignore_litest_test_suite_device(struct udev_device *device) +{ + if (!getenv("LIBINPUT_RUNNING_TEST_SUITE") && + udev_device_get_property_value(device, "LIBINPUT_TEST_DEVICE")) + return true; + + return false; +} + +void +libinput_seat_init(struct libinput_seat *seat, + struct libinput *libinput, + const char *physical_name, + const char *logical_name, + libinput_seat_destroy_func destroy) +{ + seat->refcount = 1; + seat->libinput = libinput; + seat->physical_name = safe_strdup(physical_name); + seat->logical_name = safe_strdup(logical_name); + seat->destroy = destroy; + list_init(&seat->devices_list); + list_insert(&libinput->seat_list, &seat->link); +} + +LIBINPUT_EXPORT struct libinput_seat * +libinput_seat_ref(struct libinput_seat *seat) +{ + seat->refcount++; + return seat; +} + +static void +libinput_seat_destroy(struct libinput_seat *seat) +{ + list_remove(&seat->link); + free(seat->logical_name); + free(seat->physical_name); + seat->destroy(seat); +} + +LIBINPUT_EXPORT struct libinput_seat * +libinput_seat_unref(struct libinput_seat *seat) +{ + assert(seat->refcount > 0); + seat->refcount--; + if (seat->refcount == 0) { + libinput_seat_destroy(seat); + return NULL; + } + + return seat; +} + +LIBINPUT_EXPORT void +libinput_seat_set_user_data(struct libinput_seat *seat, void *user_data) +{ + seat->user_data = user_data; +} + +LIBINPUT_EXPORT void * +libinput_seat_get_user_data(struct libinput_seat *seat) +{ + return seat->user_data; +} + +LIBINPUT_EXPORT struct libinput * +libinput_seat_get_context(struct libinput_seat *seat) +{ + return seat->libinput; +} + +LIBINPUT_EXPORT const char * +libinput_seat_get_physical_name(struct libinput_seat *seat) +{ + return seat->physical_name; +} + +LIBINPUT_EXPORT const char * +libinput_seat_get_logical_name(struct libinput_seat *seat) +{ + return seat->logical_name; +} + +void +libinput_device_init(struct libinput_device *device, + struct libinput_seat *seat) +{ + device->seat = seat; + device->refcount = 1; + list_init(&device->event_listeners); +} + +LIBINPUT_EXPORT struct libinput_device * +libinput_device_ref(struct libinput_device *device) +{ + device->refcount++; + return device; +} + +static void +libinput_device_destroy(struct libinput_device *device) +{ + // TODO + assert(list_empty(&device->event_listeners)); + //wscons_device_destroy(evdev_device(device)); +} + +LIBINPUT_EXPORT struct libinput_device * +libinput_device_unref(struct libinput_device *device) +{ + assert(device->refcount > 0); + device->refcount--; + if (device->refcount == 0) { + libinput_device_destroy(device); + return NULL; + } + + return device; +} + +LIBINPUT_EXPORT int +libinput_get_fd(struct libinput *libinput) +{ + return libinput->epoll_fd; +} + +LIBINPUT_EXPORT int +libinput_dispatch(struct libinput *libinput) +{ + static uint8_t take_time_snapshot; + struct libinput_source *source; + struct epoll_event ep[32]; + int i, count; + + /* Every 10 calls to libinput_dispatch() we take the current time so + * we can check the delay between our current time and the event + * timestamps */ + if ((++take_time_snapshot % 10) == 0) + libinput->dispatch_time = libinput_now(libinput); + else if (libinput->dispatch_time) + libinput->dispatch_time = 0; + + count = epoll_wait(libinput->epoll_fd, ep, ARRAY_LENGTH(ep), 0); + if (count < 0) + return -errno; + + for (i = 0; i < count; ++i) { + source = ep[i].data.ptr; + if (source->fd == -1) + continue; + + source->dispatch(source->user_data); + } + + libinput_drop_destroyed_sources(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, + void (*notify_func)( + uint64_t time, + struct libinput_event *event, + void *notify_func_data), + void *notify_func_data) +{ + listener->notify_func = notify_func; + listener->notify_func_data = notify_func_data; + list_insert(&device->event_listeners, &listener->link); +} + +void +libinput_device_remove_event_listener(struct libinput_event_listener *listener) +{ + list_remove(&listener->link); +} + +static uint32_t +update_seat_key_count(struct libinput_seat *seat, + int32_t key, + enum libinput_key_state state) +{ + assert(key >= 0 && key <= KEY_MAX); + + switch (state) { + case LIBINPUT_KEY_STATE_PRESSED: + return ++seat->button_count[key]; + case LIBINPUT_KEY_STATE_RELEASED: + /* We might not have received the first PRESSED event. */ + if (seat->button_count[key] == 0) + return 0; + + return --seat->button_count[key]; + } + + return 0; +} + +static uint32_t +update_seat_button_count(struct libinput_seat *seat, + int32_t button, + enum libinput_button_state state) +{ + assert(button >= 0 && button <= KEY_MAX); + + switch (state) { + case LIBINPUT_BUTTON_STATE_PRESSED: + return ++seat->button_count[button]; + case LIBINPUT_BUTTON_STATE_RELEASED: + /* We might not have received the first PRESSED event. */ + if (seat->button_count[button] == 0) + return 0; + + return --seat->button_count[button]; + } + + return 0; +} + +static void +init_event_base(struct libinput_event *event, + struct libinput_device *device, + enum libinput_event_type type) +{ + event->type = type; + event->device = device; +} + +static void +post_base_event(struct libinput_device *device, + enum libinput_event_type type, + struct libinput_event *event) +{ + struct libinput *libinput = device->seat->libinput; + init_event_base(event, device, type); + libinput_post_event(libinput, event); +} + +void +post_device_event(struct libinput_device *device, + uint64_t time, + enum libinput_event_type type, + struct libinput_event *event) +{ + struct libinput_event_listener *listener; +#if 0 + struct libinput *libinput = device->seat->libinput; + + if (libinput->last_event_time > time) { + log_bug_libinput(device->seat->libinput, + "out-of-order timestamps for %s time %" PRIu64 "\n", + event_type_to_str(type), + time); + } + libinput->last_event_time = time; +#endif + + init_event_base(event, device, type); + + list_for_each_safe(listener, &device->event_listeners, link) + listener->notify_func(time, event, listener->notify_func_data); + + libinput_post_event(device->seat->libinput, event); +} + +void +notify_added_device(struct libinput_device *device) +{ + struct libinput_event_device_notify *added_device_event; + + added_device_event = zalloc(sizeof *added_device_event); + + post_base_event(device, + LIBINPUT_EVENT_DEVICE_ADDED, + &added_device_event->base); + +#ifdef __clang_analyzer__ + /* clang doesn't realize we're not leaking the event here, so + * pretend to free it */ + free(added_device_event); +#endif +} + +void +notify_removed_device(struct libinput_device *device) +{ + struct libinput_event_device_notify *removed_device_event; + + removed_device_event = zalloc(sizeof *removed_device_event); + + post_base_event(device, + LIBINPUT_EVENT_DEVICE_REMOVED, + &removed_device_event->base); + +#ifdef __clang_analyzer__ + /* clang doesn't realize we're not leaking the event here, so + * pretend to free it */ + free(removed_device_event); +#endif +} + +static inline bool +device_has_cap(struct libinput_device *device, + enum libinput_device_capability cap) +{ + const char *capability; + + if (libinput_device_has_capability(device, cap)) + return true; + + switch (cap) { + case LIBINPUT_DEVICE_CAP_POINTER: + capability = "CAP_POINTER"; + break; + case LIBINPUT_DEVICE_CAP_KEYBOARD: + capability = "CAP_KEYBOARD"; + break; + case LIBINPUT_DEVICE_CAP_TOUCH: + capability = "CAP_TOUCH"; + break; + case LIBINPUT_DEVICE_CAP_GESTURE: + capability = "CAP_GESTURE"; + break; + case LIBINPUT_DEVICE_CAP_TABLET_TOOL: + capability = "CAP_TABLET_TOOL"; + break; + 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, + "Event for missing capability %s on device \"%s\"\n", + capability, + libinput_device_get_name(device)); + + return false; +} + +void +keyboard_notify_key(struct libinput_device *device, + uint64_t time, + uint32_t key, + enum libinput_key_state state) +{ + struct libinput_event_keyboard *key_event; + uint32_t seat_key_count; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_KEYBOARD)) + return; + + key_event = zalloc(sizeof *key_event); + + seat_key_count = update_seat_key_count(device->seat, key, state); + + *key_event = (struct libinput_event_keyboard) { + .time = time, + .key = key, + .state = state, + .seat_key_count = seat_key_count, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_KEYBOARD_KEY, + &key_event->base); +} + +void +axis_notify_event(struct libinput_device *device, + uint64_t time, + const struct normalized_coords *delta, + const struct device_float_coords *raw) +{ + struct libinput_event_pointer *axis_event; + uint32_t axes; + + axis_event = zalloc(sizeof *axis_event); + if (!axis_event) + return; + if (delta->x) + axes = bit(LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL); + else + axes = bit(LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL); + + *axis_event = (struct libinput_event_pointer) { + .time = time, + .delta = *delta, + .delta_raw = *raw, + .source = LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, + .axes = axes, + }; + + post_device_event(device, time, LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + &axis_event->base); +} + +void +pointer_notify_motion(struct libinput_device *device, + uint64_t time, + const struct normalized_coords *delta, + const struct device_float_coords *raw) +{ + struct libinput_event_pointer *motion_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_POINTER)) + return; + + motion_event = zalloc(sizeof *motion_event); + + *motion_event = (struct libinput_event_pointer) { + .time = time, + .delta = *delta, + .delta_raw = *raw, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_MOTION, + &motion_event->base); +} + +void +pointer_notify_motion_absolute(struct libinput_device *device, + uint64_t time, + const struct device_coords *point) +{ + struct libinput_event_pointer *motion_absolute_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_POINTER)) + return; + + motion_absolute_event = zalloc(sizeof *motion_absolute_event); + + *motion_absolute_event = (struct libinput_event_pointer) { + .time = time, + .absolute = *point, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, + &motion_absolute_event->base); +} + +void +pointer_notify_button(struct libinput_device *device, + uint64_t time, + int32_t button, + enum libinput_button_state state) +{ + struct libinput_event_pointer *button_event; + int32_t seat_button_count; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_POINTER)) + return; + + button_event = zalloc(sizeof *button_event); + + seat_button_count = update_seat_button_count(device->seat, + button, + state); + + *button_event = (struct libinput_event_pointer) { + .time = time, + .button = button, + .state = state, + .seat_button_count = seat_button_count, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_BUTTON, + &button_event->base); +} + +void +pointer_notify_axis_finger(struct libinput_device *device, + uint64_t time, + uint32_t axes, + const struct normalized_coords *delta) +{ + struct libinput_event_pointer *axis_event, *axis_event_legacy; + const struct discrete_coords zero_discrete = {0}; + const struct wheel_v120 zero_v120 = {0}; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_POINTER)) + return; + + axis_event = zalloc(sizeof *axis_event); + axis_event_legacy = zalloc(sizeof *axis_event_legacy); + + *axis_event = (struct libinput_event_pointer) { + .time = time, + .delta = *delta, + .source = LIBINPUT_POINTER_AXIS_SOURCE_FINGER, + .axes = axes, + .discrete = zero_discrete, + .v120 = zero_v120, + }; + *axis_event_legacy = *axis_event; + + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_SCROLL_FINGER, + &axis_event->base); + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_AXIS, + &axis_event_legacy->base); +} + +void +pointer_notify_axis_continuous(struct libinput_device *device, + uint64_t time, + uint32_t axes, + const struct normalized_coords *delta) +{ + struct libinput_event_pointer *axis_event, *axis_event_legacy; + const struct discrete_coords zero_discrete = {0}; + const struct wheel_v120 zero_v120 = {0}; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_POINTER)) + return; + + axis_event = zalloc(sizeof *axis_event); + axis_event_legacy = zalloc(sizeof *axis_event_legacy); + + *axis_event = (struct libinput_event_pointer) { + .time = time, + .delta = *delta, + .source = LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS, + .axes = axes, + .discrete = zero_discrete, + .v120 = zero_v120, + }; + *axis_event_legacy = *axis_event; + + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + &axis_event->base); + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_AXIS, + &axis_event_legacy->base); +} + +void +pointer_notify_axis_legacy_wheel(struct libinput_device *device, + uint64_t time, + uint32_t axes, + const struct normalized_coords *delta, + const struct discrete_coords *discrete) +{ + struct libinput_event_pointer *axis_event; + const struct wheel_v120 zero_v120 = {0}; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_POINTER)) + return; + + axis_event = zalloc(sizeof *axis_event); + + *axis_event = (struct libinput_event_pointer) { + .time = time, + .delta = *delta, + .source = LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, + .axes = axes, + .discrete = *discrete, + .v120 = zero_v120, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_AXIS, + &axis_event->base); +} + +void +pointer_notify_axis_wheel(struct libinput_device *device, + uint64_t time, + uint32_t axes, + const struct normalized_coords *delta, + const struct wheel_v120 *v120) +{ + struct libinput_event_pointer *axis_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_POINTER)) + return; + + axis_event = zalloc(sizeof *axis_event); + + *axis_event = (struct libinput_event_pointer) { + .time = time, + .delta = *delta, + .source = LIBINPUT_POINTER_AXIS_SOURCE_WHEEL, + .axes = axes, + .discrete.x = 0, + .discrete.y = 0, + .v120 = *v120, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + &axis_event->base); + + /* legacy wheel events are sent separately */ +} + +void +touch_notify_touch_down(struct libinput_device *device, + uint64_t time, + int32_t slot, + int32_t seat_slot, + const struct device_coords *point) +{ + struct libinput_event_touch *touch_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_TOUCH)) + return; + + touch_event = zalloc(sizeof *touch_event); + + *touch_event = (struct libinput_event_touch) { + .time = time, + .slot = slot, + .seat_slot = seat_slot, + .point = *point, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_TOUCH_DOWN, + &touch_event->base); +} + +void +touch_notify_touch_motion(struct libinput_device *device, + uint64_t time, + int32_t slot, + int32_t seat_slot, + const struct device_coords *point) +{ + struct libinput_event_touch *touch_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_TOUCH)) + return; + + touch_event = zalloc(sizeof *touch_event); + + *touch_event = (struct libinput_event_touch) { + .time = time, + .slot = slot, + .seat_slot = seat_slot, + .point = *point, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_TOUCH_MOTION, + &touch_event->base); +} + +void +touch_notify_touch_up(struct libinput_device *device, + uint64_t time, + int32_t slot, + int32_t seat_slot) +{ + struct libinput_event_touch *touch_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_TOUCH)) + return; + + touch_event = zalloc(sizeof *touch_event); + + *touch_event = (struct libinput_event_touch) { + .time = time, + .slot = slot, + .seat_slot = seat_slot, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_TOUCH_UP, + &touch_event->base); +} + +void +touch_notify_touch_cancel(struct libinput_device *device, + uint64_t time, + int32_t slot, + int32_t seat_slot) +{ + struct libinput_event_touch *touch_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_TOUCH)) + return; + + touch_event = zalloc(sizeof *touch_event); + + *touch_event = (struct libinput_event_touch) { + .time = time, + .slot = slot, + .seat_slot = seat_slot, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_TOUCH_CANCEL, + &touch_event->base); +} + +void +touch_notify_frame(struct libinput_device *device, + uint64_t time) +{ + struct libinput_event_touch *touch_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_TOUCH)) + return; + + touch_event = zalloc(sizeof *touch_event); + + *touch_event = (struct libinput_event_touch) { + .time = time, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_TOUCH_FRAME, + &touch_event->base); +} + +void +tablet_notify_axis(struct libinput_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + enum libinput_tablet_tool_tip_state tip_state, + unsigned char *changed_axes, + const struct tablet_axes *axes) +{ + struct libinput_event_tablet_tool *axis_event; + + axis_event = zalloc(sizeof *axis_event); + + *axis_event = (struct libinput_event_tablet_tool) { + .time = time, + .tool = libinput_tablet_tool_ref(tool), + .proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN, + .tip_state = tip_state, + .axes = *axes, + }; + + memcpy(axis_event->changed_axes, + changed_axes, + sizeof(axis_event->changed_axes)); + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + &axis_event->base); +} + +void +tablet_notify_proximity(struct libinput_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + enum libinput_tablet_tool_proximity_state proximity_state, + unsigned char *changed_axes, + const struct tablet_axes *axes) +{ + struct libinput_event_tablet_tool *proximity_event; + + proximity_event = zalloc(sizeof *proximity_event); + + *proximity_event = (struct libinput_event_tablet_tool) { + .time = time, + .tool = libinput_tablet_tool_ref(tool), + .tip_state = LIBINPUT_TABLET_TOOL_TIP_UP, + .proximity_state = proximity_state, + .axes = *axes, + }; + memcpy(proximity_event->changed_axes, + changed_axes, + sizeof(proximity_event->changed_axes)); + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, + &proximity_event->base); +} + +void +tablet_notify_tip(struct libinput_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + enum libinput_tablet_tool_tip_state tip_state, + unsigned char *changed_axes, + const struct tablet_axes *axes) +{ + struct libinput_event_tablet_tool *tip_event; + + tip_event = zalloc(sizeof *tip_event); + + *tip_event = (struct libinput_event_tablet_tool) { + .time = time, + .tool = libinput_tablet_tool_ref(tool), + .tip_state = tip_state, + .proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN, + .axes = *axes, + }; + memcpy(tip_event->changed_axes, + changed_axes, + sizeof(tip_event->changed_axes)); + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + &tip_event->base); +} + +void +tablet_notify_button(struct libinput_device *device, + uint64_t time, + struct libinput_tablet_tool *tool, + enum libinput_tablet_tool_tip_state tip_state, + const struct tablet_axes *axes, + int32_t button, + enum libinput_button_state state) +{ + struct libinput_event_tablet_tool *button_event; + int32_t seat_button_count; + + button_event = zalloc(sizeof *button_event); + + seat_button_count = update_seat_button_count(device->seat, + button, + state); + + *button_event = (struct libinput_event_tablet_tool) { + .time = time, + .tool = libinput_tablet_tool_ref(tool), + .button = button, + .state = state, + .seat_button_count = seat_button_count, + .proximity_state = LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN, + .tip_state = tip_state, + .axes = *axes, + }; + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON, + &button_event->base); +} + +void +tablet_pad_notify_button(struct libinput_device *device, + uint64_t time, + int32_t button, + enum libinput_button_state state, + struct libinput_tablet_pad_mode_group *group) +{ + struct libinput_event_tablet_pad *button_event; + unsigned int mode; + + button_event = zalloc(sizeof *button_event); + + mode = libinput_tablet_pad_mode_group_get_mode(group); + + *button_event = (struct libinput_event_tablet_pad) { + .time = time, + .button.number = button, + .button.state = state, + .mode_group = libinput_tablet_pad_mode_group_ref(group), + .mode = mode, + }; + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_PAD_BUTTON, + &button_event->base); +} + +void +tablet_pad_notify_ring(struct libinput_device *device, + uint64_t time, + unsigned int number, + double value, + enum libinput_tablet_pad_ring_axis_source source, + struct libinput_tablet_pad_mode_group *group) +{ + struct libinput_event_tablet_pad *ring_event; + unsigned int mode; + + ring_event = zalloc(sizeof *ring_event); + + mode = libinput_tablet_pad_mode_group_get_mode(group); + + *ring_event = (struct libinput_event_tablet_pad) { + .time = time, + .ring.number = number, + .ring.position = value, + .ring.source = source, + .mode_group = libinput_tablet_pad_mode_group_ref(group), + .mode = mode, + }; + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_PAD_RING, + &ring_event->base); +} + +void +tablet_pad_notify_strip(struct libinput_device *device, + uint64_t time, + unsigned int number, + double value, + enum libinput_tablet_pad_strip_axis_source source, + struct libinput_tablet_pad_mode_group *group) +{ + struct libinput_event_tablet_pad *strip_event; + unsigned int mode; + + strip_event = zalloc(sizeof *strip_event); + + mode = libinput_tablet_pad_mode_group_get_mode(group); + + *strip_event = (struct libinput_event_tablet_pad) { + .time = time, + .strip.number = number, + .strip.position = value, + .strip.source = source, + .mode_group = libinput_tablet_pad_mode_group_ref(group), + .mode = mode, + }; + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_PAD_STRIP, + &strip_event->base); +} + +void +tablet_pad_notify_key(struct libinput_device *device, + uint64_t time, + int32_t key, + enum libinput_key_state state) +{ + struct libinput_event_tablet_pad *key_event; + + key_event = zalloc(sizeof *key_event); + + *key_event = (struct libinput_event_tablet_pad) { + .time = time, + .key.code = key, + .key.state = state, + }; + + post_device_event(device, + time, + LIBINPUT_EVENT_TABLET_PAD_KEY, + &key_event->base); +} + +static void +gesture_notify(struct libinput_device *device, + uint64_t time, + enum libinput_event_type type, + int finger_count, + bool cancelled, + const struct normalized_coords *delta, + const struct normalized_coords *unaccel, + double scale, + double angle) +{ + struct libinput_event_gesture *gesture_event; + + if (!device_has_cap(device, LIBINPUT_DEVICE_CAP_GESTURE)) + return; + + gesture_event = zalloc(sizeof *gesture_event); + + *gesture_event = (struct libinput_event_gesture) { + .time = time, + .finger_count = finger_count, + .cancelled = cancelled, + .delta = *delta, + .delta_unaccel = *unaccel, + .scale = scale, + .angle = angle, + }; + + post_device_event(device, time, type, + &gesture_event->base); +} + +void +gesture_notify_swipe(struct libinput_device *device, + uint64_t time, + enum libinput_event_type type, + int finger_count, + const struct normalized_coords *delta, + const struct normalized_coords *unaccel) +{ + gesture_notify(device, time, type, finger_count, 0, delta, unaccel, + 0.0, 0.0); +} + +void +gesture_notify_swipe_end(struct libinput_device *device, + uint64_t time, + int finger_count, + bool cancelled) +{ + const struct normalized_coords zero = { 0.0, 0.0 }; + + gesture_notify(device, time, LIBINPUT_EVENT_GESTURE_SWIPE_END, + finger_count, cancelled, &zero, &zero, 0.0, 0.0); +} + +void +gesture_notify_pinch(struct libinput_device *device, + uint64_t time, + enum libinput_event_type type, + int finger_count, + const struct normalized_coords *delta, + const struct normalized_coords *unaccel, + double scale, + double angle) +{ + gesture_notify(device, time, type, finger_count, 0, + delta, unaccel, scale, angle); +} + +void +gesture_notify_pinch_end(struct libinput_device *device, + uint64_t time, + int finger_count, + double scale, + bool cancelled) +{ + const struct normalized_coords zero = { 0.0, 0.0 }; + + gesture_notify(device, time, LIBINPUT_EVENT_GESTURE_PINCH_END, + finger_count, cancelled, &zero, &zero, scale, 0.0); +} + +void +gesture_notify_hold(struct libinput_device *device, + uint64_t time, + int finger_count) +{ + const struct normalized_coords zero = { 0.0, 0.0 }; + + gesture_notify(device, time, LIBINPUT_EVENT_GESTURE_HOLD_BEGIN, + finger_count, 0, &zero, &zero, 0.0, 0.0); +} + +void +gesture_notify_hold_end(struct libinput_device *device, + uint64_t time, + int finger_count, + bool cancelled) +{ + const struct normalized_coords zero = { 0.0, 0.0 }; + + gesture_notify(device, time, LIBINPUT_EVENT_GESTURE_HOLD_END, + finger_count, cancelled, &zero, &zero, 0, 0.0); +} + +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); + + *switch_event = (struct libinput_event_switch) { + .time = time, + .sw = sw, + .state = state, + }; + + post_device_event(device, time, + LIBINPUT_EVENT_SWITCH_TOGGLE, + &switch_event->base); + +#ifdef __clang_analyzer__ + /* clang doesn't realize we're not leaking the event here, so + * pretend to free it */ + free(switch_event); +#endif +} + +static void +libinput_post_event(struct libinput *libinput, + struct libinput_event *event) +{ + struct libinput_event **events = libinput->events; + size_t events_len = libinput->events_len; + size_t events_count = libinput->events_count; + size_t move_len; + size_t new_out; + +#if 0 + log_debug(libinput, "Queuing %s\n", event_type_to_str(event->type)); +#endif + + events_count++; + if (events_count > events_len) { + void *tmp; + + events_len *= 2; + tmp = realloc(events, events_len * sizeof *events); + if (!tmp) { + log_error(libinput, + "Failed to reallocate event ring buffer. " + "Events may be discarded\n"); + return; + } + + events = tmp; + + if (libinput->events_count > 0 && libinput->events_in == 0) { + libinput->events_in = libinput->events_len; + } else if (libinput->events_count > 0 && + libinput->events_out >= libinput->events_in) { + move_len = libinput->events_len - libinput->events_out; + new_out = events_len - move_len; + memmove(events + new_out, + events + libinput->events_out, + move_len * sizeof *events); + libinput->events_out = new_out; + } + + libinput->events = events; + libinput->events_len = events_len; + } + + if (event->device) + libinput_device_ref(event->device); + + libinput->events_count = events_count; + events[libinput->events_in] = event; + libinput->events_in = (libinput->events_in + 1) % libinput->events_len; +} + +LIBINPUT_EXPORT struct libinput_event * +libinput_get_event(struct libinput *libinput) +{ + struct libinput_event *event; + + if (libinput->events_count == 0) + return NULL; + + event = libinput->events[libinput->events_out]; + libinput->events_out = + (libinput->events_out + 1) % libinput->events_len; + libinput->events_count--; + + return event; +} + +LIBINPUT_EXPORT enum libinput_event_type +libinput_next_event_type(struct libinput *libinput) +{ + struct libinput_event *event; + + if (libinput->events_count == 0) + return LIBINPUT_EVENT_NONE; + + event = libinput->events[libinput->events_out]; + return event->type; +} + +LIBINPUT_EXPORT void +libinput_set_user_data(struct libinput *libinput, + void *user_data) +{ + libinput->user_data = user_data; +} + +LIBINPUT_EXPORT void * +libinput_get_user_data(struct libinput *libinput) +{ + return libinput->user_data; +} + +LIBINPUT_EXPORT int +libinput_resume(struct libinput *libinput) +{ + return libinput->interface_backend->resume(libinput); +} + +LIBINPUT_EXPORT void +libinput_suspend(struct libinput *libinput) +{ + libinput->interface_backend->suspend(libinput); +} + +LIBINPUT_EXPORT void +libinput_device_set_user_data(struct libinput_device *device, void *user_data) +{ + device->user_data = user_data; +} + +LIBINPUT_EXPORT void * +libinput_device_get_user_data(struct libinput_device *device) +{ + return device->user_data; +} + +LIBINPUT_EXPORT struct libinput * +libinput_device_get_context(struct libinput_device *device) +{ + return libinput_seat_get_context(device->seat); +} + +LIBINPUT_EXPORT struct libinput_device_group * +libinput_device_get_device_group(struct libinput_device *device) +{ + return device->group; +} + +LIBINPUT_EXPORT const char * +libinput_device_get_sysname(struct libinput_device *device) +{ + return device->devname; +} + +LIBINPUT_EXPORT const char * +libinput_device_get_name(struct libinput_device *device) +{ + if (strncmp(device->devname, "/dev/", 5) == 0) + return device->devname + 5; /* skip /dev/ */ + else + return device->devname; /* XXX */ +} + +LIBINPUT_EXPORT unsigned int +libinput_device_get_id_product(struct libinput_device *device) +{ + return 0; // TODO +} + +LIBINPUT_EXPORT unsigned int +libinput_device_get_id_vendor(struct libinput_device *device) +{ + return 0; // TODO +} + +LIBINPUT_EXPORT const char * +libinput_device_get_output_name(struct libinput_device *device) +{ + return "unsupported"; +} + +LIBINPUT_EXPORT struct libinput_seat * +libinput_device_get_seat(struct libinput_device *device) +{ + return device->seat; +} + +LIBINPUT_EXPORT int +libinput_device_set_seat_logical_name(struct libinput_device *device, + const char *name) +{ + struct libinput *libinput = device->seat->libinput; + + if (name == NULL) + return -1; + + return libinput->interface_backend->device_change_seat(device, + name); +} + +LIBINPUT_EXPORT struct udev_device * +libinput_device_get_udev_device(struct libinput_device *device) +{ + return NULL; // TODO +} + +LIBINPUT_EXPORT void +libinput_device_led_update(struct libinput_device *device, + enum libinput_led leds) +{ + // TODO +} + +LIBINPUT_EXPORT int +libinput_device_has_capability(struct libinput_device *device, + enum libinput_device_capability capability) +{ + return (wscons_device(device)->capability == capability); +} + +LIBINPUT_EXPORT int +libinput_device_get_size(struct libinput_device *device, + double *width, + double *height) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_pointer_has_button(struct libinput_device *device, uint32_t code) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_keyboard_has_key(struct libinput_device *device, uint32_t code) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_touch_get_touch_count(struct libinput_device *device) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_switch_has_switch(struct libinput_device *device, + enum libinput_switch sw) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_tablet_pad_has_key(struct libinput_device *device, uint32_t code) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_tablet_pad_get_num_buttons(struct libinput_device *device) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_tablet_pad_get_num_rings(struct libinput_device *device) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_tablet_pad_get_num_strips(struct libinput_device *device) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT int +libinput_device_tablet_pad_get_num_mode_groups(struct libinput_device *device) +{ + fprintf(stderr, "%s: stub\n", __func__); + return (-1); +} + +LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group* +libinput_device_tablet_pad_get_mode_group(struct libinput_device *device, + unsigned int index) +{ + fprintf(stderr, "%s: stub\n", __func__); + return NULL; +} + +LIBINPUT_EXPORT unsigned int +libinput_tablet_pad_mode_group_get_num_modes( + struct libinput_tablet_pad_mode_group *group) +{ + return group->num_modes; +} + +LIBINPUT_EXPORT unsigned int +libinput_tablet_pad_mode_group_get_mode(struct libinput_tablet_pad_mode_group *group) +{ + return group->current_mode; +} + +LIBINPUT_EXPORT unsigned int +libinput_tablet_pad_mode_group_get_index(struct libinput_tablet_pad_mode_group *group) +{ + return group->index; +} + +LIBINPUT_EXPORT int +libinput_tablet_pad_mode_group_has_button(struct libinput_tablet_pad_mode_group *group, + unsigned int button) +{ + if ((int)button >= + libinput_device_tablet_pad_get_num_buttons(group->device)) + return 0; + + return !!(group->button_mask & bit(button)); +} + +LIBINPUT_EXPORT int +libinput_tablet_pad_mode_group_has_ring(struct libinput_tablet_pad_mode_group *group, + unsigned int ring) +{ + if ((int)ring >= + libinput_device_tablet_pad_get_num_rings(group->device)) + return 0; + + return !!(group->ring_mask & bit(ring)); +} + +LIBINPUT_EXPORT int +libinput_tablet_pad_mode_group_has_strip(struct libinput_tablet_pad_mode_group *group, + unsigned int strip) +{ + if ((int)strip >= + libinput_device_tablet_pad_get_num_strips(group->device)) + return 0; + + return !!(group->strip_mask & bit(strip)); +} + +LIBINPUT_EXPORT int +libinput_tablet_pad_mode_group_button_is_toggle(struct libinput_tablet_pad_mode_group *group, + unsigned int button) +{ + if ((int)button >= + libinput_device_tablet_pad_get_num_buttons(group->device)) + return 0; + + return !!(group->toggle_button_mask & bit(button)); +} + +LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group * +libinput_tablet_pad_mode_group_ref( + struct libinput_tablet_pad_mode_group *group) +{ + group->refcount++; + return group; +} + +LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group * +libinput_tablet_pad_mode_group_unref( + struct libinput_tablet_pad_mode_group *group) +{ + assert(group->refcount > 0); + + group->refcount--; + if (group->refcount > 0) + return group; + + list_remove(&group->link); + group->destroy(group); + return NULL; +} + +LIBINPUT_EXPORT void +libinput_tablet_pad_mode_group_set_user_data( + struct libinput_tablet_pad_mode_group *group, + void *user_data) +{ + group->user_data = user_data; +} + +LIBINPUT_EXPORT void * +libinput_tablet_pad_mode_group_get_user_data( + struct libinput_tablet_pad_mode_group *group) +{ + return group->user_data; +} + +LIBINPUT_EXPORT struct libinput_event * +libinput_event_device_notify_get_base_event(struct libinput_event_device_notify *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + NULL, + LIBINPUT_EVENT_DEVICE_ADDED, + LIBINPUT_EVENT_DEVICE_REMOVED); + + return &event->base; +} + +LIBINPUT_EXPORT struct libinput_event * +libinput_event_keyboard_get_base_event(struct libinput_event_keyboard *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + NULL, + LIBINPUT_EVENT_KEYBOARD_KEY); + + return &event->base; +} + +LIBINPUT_EXPORT struct libinput_event * +libinput_event_pointer_get_base_event(struct libinput_event_pointer *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + NULL, + LIBINPUT_EVENT_POINTER_MOTION, + LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE, + LIBINPUT_EVENT_POINTER_BUTTON, + LIBINPUT_EVENT_POINTER_SCROLL_WHEEL, + LIBINPUT_EVENT_POINTER_SCROLL_FINGER, + LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS, + LIBINPUT_EVENT_POINTER_AXIS); + + return &event->base; +} + +LIBINPUT_EXPORT struct libinput_event * +libinput_event_touch_get_base_event(struct libinput_event_touch *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + NULL, + LIBINPUT_EVENT_TOUCH_DOWN, + LIBINPUT_EVENT_TOUCH_UP, + LIBINPUT_EVENT_TOUCH_MOTION, + LIBINPUT_EVENT_TOUCH_CANCEL, + LIBINPUT_EVENT_TOUCH_FRAME); + + return &event->base; +} + +LIBINPUT_EXPORT struct libinput_event * +libinput_event_gesture_get_base_event(struct libinput_event_gesture *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + NULL, + LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN, + LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE, + LIBINPUT_EVENT_GESTURE_SWIPE_END, + LIBINPUT_EVENT_GESTURE_PINCH_BEGIN, + LIBINPUT_EVENT_GESTURE_PINCH_UPDATE, + LIBINPUT_EVENT_GESTURE_PINCH_END, + LIBINPUT_EVENT_GESTURE_HOLD_BEGIN, + LIBINPUT_EVENT_GESTURE_HOLD_END); + + return &event->base; +} + +LIBINPUT_EXPORT struct libinput_event * +libinput_event_tablet_tool_get_base_event(struct libinput_event_tablet_tool *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + NULL, + LIBINPUT_EVENT_TABLET_TOOL_AXIS, + LIBINPUT_EVENT_TABLET_TOOL_TIP, + LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY, + LIBINPUT_EVENT_TABLET_TOOL_BUTTON); + + return &event->base; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_pad_get_ring_position(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_TABLET_PAD_RING); + + return event->ring.position; +} + +LIBINPUT_EXPORT unsigned int +libinput_event_tablet_pad_get_ring_number(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_PAD_RING); + + return event->ring.number; +} + +LIBINPUT_EXPORT enum libinput_tablet_pad_ring_axis_source +libinput_event_tablet_pad_get_ring_source(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN, + LIBINPUT_EVENT_TABLET_PAD_RING); + + return event->ring.source; +} + +LIBINPUT_EXPORT double +libinput_event_tablet_pad_get_strip_position(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0.0, + LIBINPUT_EVENT_TABLET_PAD_STRIP); + + return event->strip.position; +} + +LIBINPUT_EXPORT unsigned int +libinput_event_tablet_pad_get_strip_number(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_PAD_STRIP); + + return event->strip.number; +} + +LIBINPUT_EXPORT enum libinput_tablet_pad_strip_axis_source +libinput_event_tablet_pad_get_strip_source(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN, + LIBINPUT_EVENT_TABLET_PAD_STRIP); + + return event->strip.source; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_tablet_pad_get_button_number(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_PAD_BUTTON); + + return event->button.number; +} + +LIBINPUT_EXPORT enum libinput_button_state +libinput_event_tablet_pad_get_button_state(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + LIBINPUT_BUTTON_STATE_RELEASED, + LIBINPUT_EVENT_TABLET_PAD_BUTTON); + + return event->button.state; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_tablet_pad_get_key(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_PAD_KEY); + + return event->key.code; +} + +LIBINPUT_EXPORT enum libinput_key_state +libinput_event_tablet_pad_get_key_state(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + LIBINPUT_KEY_STATE_RELEASED, + LIBINPUT_EVENT_TABLET_PAD_KEY); + + return event->key.state; +} + +LIBINPUT_EXPORT unsigned int +libinput_event_tablet_pad_get_mode(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_PAD_RING, + LIBINPUT_EVENT_TABLET_PAD_STRIP, + LIBINPUT_EVENT_TABLET_PAD_BUTTON); + + return event->mode; +} + +LIBINPUT_EXPORT struct libinput_tablet_pad_mode_group * +libinput_event_tablet_pad_get_mode_group(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + NULL, + LIBINPUT_EVENT_TABLET_PAD_RING, + LIBINPUT_EVENT_TABLET_PAD_STRIP, + LIBINPUT_EVENT_TABLET_PAD_BUTTON); + + return event->mode_group; +} + +LIBINPUT_EXPORT uint32_t +libinput_event_tablet_pad_get_time(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_PAD_RING, + LIBINPUT_EVENT_TABLET_PAD_STRIP, + LIBINPUT_EVENT_TABLET_PAD_BUTTON, + LIBINPUT_EVENT_TABLET_PAD_KEY); + + return us2ms(event->time); +} + +LIBINPUT_EXPORT uint64_t +libinput_event_tablet_pad_get_time_usec(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + 0, + LIBINPUT_EVENT_TABLET_PAD_RING, + LIBINPUT_EVENT_TABLET_PAD_STRIP, + LIBINPUT_EVENT_TABLET_PAD_BUTTON, + LIBINPUT_EVENT_TABLET_PAD_KEY); + + return event->time; +} + +LIBINPUT_EXPORT struct libinput_event * +libinput_event_tablet_pad_get_base_event(struct libinput_event_tablet_pad *event) +{ + require_event_type(libinput_event_get_context(&event->base), + event->base.type, + NULL, + LIBINPUT_EVENT_TABLET_PAD_RING, + LIBINPUT_EVENT_TABLET_PAD_STRIP, + LIBINPUT_EVENT_TABLET_PAD_BUTTON, + LIBINPUT_EVENT_TABLET_PAD_KEY); + + return &event->base; +} + +LIBINPUT_EXPORT struct libinput_device_group * +libinput_device_group_ref(struct libinput_device_group *group) +{ + group->refcount++; + return group; +} + +struct libinput_device_group * +libinput_device_group_create(struct libinput *libinput, + const char *identifier) +{ + struct libinput_device_group *group; + + group = zalloc(sizeof *group); + group->refcount = 1; + group->identifier = safe_strdup(identifier); + + list_init(&group->link); + list_insert(&libinput->device_group_list, &group->link); + + return group; +} + +struct libinput_device_group * +libinput_device_group_find_group(struct libinput *libinput, + const char *identifier) +{ + struct libinput_device_group *g = NULL; + + list_for_each(g, &libinput->device_group_list, link) { + if (identifier && g->identifier && + streq(g->identifier, identifier)) { + return g; + } + } + + return NULL; +} + +void +libinput_device_set_device_group(struct libinput_device *device, + struct libinput_device_group *group) +{ + device->group = group; + libinput_device_group_ref(group); +} + +static void +libinput_device_group_destroy(struct libinput_device_group *group) +{ + list_remove(&group->link); + free(group->identifier); + free(group); +} + +LIBINPUT_EXPORT struct libinput_device_group * +libinput_device_group_unref(struct libinput_device_group *group) +{ + assert(group->refcount > 0); + group->refcount--; + if (group->refcount == 0) { + libinput_device_group_destroy(group); + return NULL; + } + + return group; +} + +LIBINPUT_EXPORT void +libinput_device_group_set_user_data(struct libinput_device_group *group, + void *user_data) +{ + group->user_data = user_data; +} + +LIBINPUT_EXPORT void * +libinput_device_group_get_user_data(struct libinput_device_group *group) +{ + return group->user_data; +} + +LIBINPUT_EXPORT const char * +libinput_config_status_to_str(enum libinput_config_status status) +{ + const char *str = NULL; + + switch(status) { + case LIBINPUT_CONFIG_STATUS_SUCCESS: + str = "Success"; + break; + case LIBINPUT_CONFIG_STATUS_UNSUPPORTED: + str = "Unsupported configuration option"; + break; + case LIBINPUT_CONFIG_STATUS_INVALID: + str = "Invalid argument range"; + break; + } + + return str; +} + +LIBINPUT_EXPORT int +libinput_device_config_tap_get_finger_count(struct libinput_device *device) +{ + return device->config.tap ? device->config.tap->count(device) : 0; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_tap_set_enabled(struct libinput_device *device, + enum libinput_config_tap_state enable) +{ + if (enable != LIBINPUT_CONFIG_TAP_ENABLED && + enable != LIBINPUT_CONFIG_TAP_DISABLED) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (libinput_device_config_tap_get_finger_count(device) == 0) + return enable ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : + LIBINPUT_CONFIG_STATUS_SUCCESS; + + return device->config.tap->set_enabled(device, enable); + +} + +LIBINPUT_EXPORT enum libinput_config_tap_state +libinput_device_config_tap_get_enabled(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_TAP_DISABLED; + + return device->config.tap->get_enabled(device); +} + +LIBINPUT_EXPORT enum libinput_config_tap_state +libinput_device_config_tap_get_default_enabled(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_TAP_DISABLED; + + return device->config.tap->get_default(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_tap_set_button_map(struct libinput_device *device, + enum libinput_config_tap_button_map map) +{ + switch (map) { + case LIBINPUT_CONFIG_TAP_MAP_LRM: + case LIBINPUT_CONFIG_TAP_MAP_LMR: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.tap->set_map(device, map); +} + +LIBINPUT_EXPORT enum libinput_config_tap_button_map +libinput_device_config_tap_get_button_map(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_TAP_MAP_LRM; + + return device->config.tap->get_map(device); +} + +LIBINPUT_EXPORT enum libinput_config_tap_button_map +libinput_device_config_tap_get_default_button_map(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_TAP_MAP_LRM; + + return device->config.tap->get_default_map(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_tap_set_drag_enabled(struct libinput_device *device, + enum libinput_config_drag_state enable) +{ + if (enable != LIBINPUT_CONFIG_DRAG_ENABLED && + enable != LIBINPUT_CONFIG_DRAG_DISABLED) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (libinput_device_config_tap_get_finger_count(device) == 0) + return enable ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : + LIBINPUT_CONFIG_STATUS_SUCCESS; + + return device->config.tap->set_drag_enabled(device, enable); +} + +LIBINPUT_EXPORT enum libinput_config_drag_state +libinput_device_config_tap_get_drag_enabled(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_DRAG_DISABLED; + + return device->config.tap->get_drag_enabled(device); +} + +LIBINPUT_EXPORT enum libinput_config_drag_state +libinput_device_config_tap_get_default_drag_enabled(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_DRAG_DISABLED; + + return device->config.tap->get_default_drag_enabled(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_tap_set_drag_lock_enabled(struct libinput_device *device, + enum libinput_config_drag_lock_state enable) +{ + if (enable != LIBINPUT_CONFIG_DRAG_LOCK_ENABLED && + enable != LIBINPUT_CONFIG_DRAG_LOCK_DISABLED) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (libinput_device_config_tap_get_finger_count(device) == 0) + return enable ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : + LIBINPUT_CONFIG_STATUS_SUCCESS; + + return device->config.tap->set_draglock_enabled(device, enable); +} + +LIBINPUT_EXPORT enum libinput_config_drag_lock_state +libinput_device_config_tap_get_drag_lock_enabled(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; + + return device->config.tap->get_draglock_enabled(device); +} + +LIBINPUT_EXPORT enum libinput_config_drag_lock_state +libinput_device_config_tap_get_default_drag_lock_enabled(struct libinput_device *device) +{ + if (libinput_device_config_tap_get_finger_count(device) == 0) + return LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; + + return device->config.tap->get_default_draglock_enabled(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_calibration_has_matrix(struct libinput_device *device) +{ + return device->config.calibration ? + device->config.calibration->has_matrix(device) : 0; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_calibration_set_matrix(struct libinput_device *device, + const float matrix[6]) +{ + if (!libinput_device_config_calibration_has_matrix(device)) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.calibration->set_matrix(device, matrix); +} + +LIBINPUT_EXPORT int +libinput_device_config_calibration_get_matrix(struct libinput_device *device, + float matrix[6]) +{ + if (!libinput_device_config_calibration_has_matrix(device)) + return 0; + + return device->config.calibration->get_matrix(device, matrix); +} + +LIBINPUT_EXPORT int +libinput_device_config_calibration_get_default_matrix(struct libinput_device *device, + float matrix[6]) +{ + if (!libinput_device_config_calibration_has_matrix(device)) + return 0; + + return device->config.calibration->get_default_matrix(device, matrix); +} + +LIBINPUT_EXPORT uint32_t +libinput_device_config_send_events_get_modes(struct libinput_device *device) +{ + uint32_t modes = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; + + if (device->config.sendevents) + modes |= device->config.sendevents->get_modes(device); + + return modes; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_send_events_set_mode(struct libinput_device *device, + uint32_t mode) +{ + if ((libinput_device_config_send_events_get_modes(device) & mode) != mode) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + if (device->config.sendevents) + return device->config.sendevents->set_mode(device, mode); + + /* mode must be _ENABLED to get here */ + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +LIBINPUT_EXPORT uint32_t +libinput_device_config_send_events_get_mode(struct libinput_device *device) +{ + if (device->config.sendevents) + return device->config.sendevents->get_mode(device); + + return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; +} + +LIBINPUT_EXPORT uint32_t +libinput_device_config_send_events_get_default_mode(struct libinput_device *device) +{ + return LIBINPUT_CONFIG_SEND_EVENTS_ENABLED; +} + +LIBINPUT_EXPORT int +libinput_device_config_accel_is_available(struct libinput_device *device) +{ + return device->config.accel ? + device->config.accel->available(device) : 0; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_accel_set_speed(struct libinput_device *device, + double speed) +{ + /* Need the negation in case speed is NaN */ + if (!(speed >= -1.0 && speed <= 1.0)) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (!libinput_device_config_accel_is_available(device)) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.accel->set_speed(device, speed); +} +LIBINPUT_EXPORT double +libinput_device_config_accel_get_speed(struct libinput_device *device) +{ + if (!libinput_device_config_accel_is_available(device)) + return 0; + + return device->config.accel->get_speed(device); +} + +LIBINPUT_EXPORT double +libinput_device_config_accel_get_default_speed(struct libinput_device *device) +{ + if (!libinput_device_config_accel_is_available(device)) + return 0; + + return device->config.accel->get_default_speed(device); +} + +LIBINPUT_EXPORT uint32_t +libinput_device_config_accel_get_profiles(struct libinput_device *device) +{ + if (!libinput_device_config_accel_is_available(device)) + return 0; + + return device->config.accel->get_profiles(device); +} + +LIBINPUT_EXPORT enum libinput_config_accel_profile +libinput_device_config_accel_get_profile(struct libinput_device *device) +{ + if (!libinput_device_config_accel_is_available(device)) + return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; + + return device->config.accel->get_profile(device); +} + +LIBINPUT_EXPORT enum libinput_config_accel_profile +libinput_device_config_accel_get_default_profile(struct libinput_device *device) +{ + if (!libinput_device_config_accel_is_available(device)) + return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; + + return device->config.accel->get_default_profile(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_accel_set_profile(struct libinput_device *device, + enum libinput_config_accel_profile profile) +{ + switch (profile) { + case LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT: + case LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE: + case LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + if (!libinput_device_config_accel_is_available(device) || + (libinput_device_config_accel_get_profiles(device) & profile) == 0) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.accel->set_profile(device, profile); +} + +static inline struct libinput_config_accel_custom_func * +libinput_config_accel_custom_func_create(void) +{ + struct libinput_config_accel_custom_func *func = zalloc(sizeof(*func)); + + func->step = 1.0; + func->npoints = 2; + func->points[0] = 0.0; /* default to a flat unaccelerated function */ + func->points[1] = 1.0; + + return func; +} + +static inline void +libinput_config_accel_custom_func_destroy(struct libinput_config_accel_custom_func * func) +{ + free(func); +} + +LIBINPUT_EXPORT struct libinput_config_accel * +libinput_config_accel_create(enum libinput_config_accel_profile profile) +{ + struct libinput_config_accel *config = zalloc(sizeof(*config)); + + config->profile = profile; + + switch (profile) { + case LIBINPUT_CONFIG_ACCEL_PROFILE_NONE: + break; + case LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT: + case LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE: + return config; + case LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM: + config->custom.fallback = libinput_config_accel_custom_func_create(); + return config; + } + + free(config); + return NULL; +} + +LIBINPUT_EXPORT void +libinput_config_accel_destroy(struct libinput_config_accel *accel_config) +{ + libinput_config_accel_custom_func_destroy(accel_config->custom.fallback); + libinput_config_accel_custom_func_destroy(accel_config->custom.motion); + libinput_config_accel_custom_func_destroy(accel_config->custom.scroll); + free(accel_config); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_accel_apply(struct libinput_device *device, + struct libinput_config_accel *accel_config) +{ + enum libinput_config_status status; + status = libinput_device_config_accel_set_profile(device, accel_config->profile); + if (status != LIBINPUT_CONFIG_STATUS_SUCCESS) + return status; + + switch (accel_config->profile) { + case LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT: + case LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE: + { + double speed = libinput_device_config_accel_get_default_speed(device); + return libinput_device_config_accel_set_speed(device, speed); + } + case LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM: + return device->config.accel->set_accel_config(device, accel_config); + + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_config_accel_set_points(struct libinput_config_accel *config, + enum libinput_config_accel_type accel_type, + double step, size_t npoints, double *points) +{ + if (config->profile != LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM) + return LIBINPUT_CONFIG_STATUS_INVALID; + + switch (accel_type) { + case LIBINPUT_ACCEL_TYPE_FALLBACK: + case LIBINPUT_ACCEL_TYPE_MOTION: + case LIBINPUT_ACCEL_TYPE_SCROLL: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + if (step <= 0 || step > LIBINPUT_ACCEL_STEP_MAX) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (npoints < LIBINPUT_ACCEL_NPOINTS_MIN || npoints > LIBINPUT_ACCEL_NPOINTS_MAX) + return LIBINPUT_CONFIG_STATUS_INVALID; + + for (size_t idx = 0; idx < npoints; idx++) { + if (points[idx] < LIBINPUT_ACCEL_POINT_MIN_VALUE || + points[idx] > LIBINPUT_ACCEL_POINT_MAX_VALUE) + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + struct libinput_config_accel_custom_func *func = libinput_config_accel_custom_func_create(); + + func->step = step; + func->npoints = npoints; + memcpy(func->points, points, sizeof(*points) * npoints); + + switch (accel_type) { + case LIBINPUT_ACCEL_TYPE_FALLBACK: + libinput_config_accel_custom_func_destroy(config->custom.fallback); + config->custom.fallback = func; + break; + case LIBINPUT_ACCEL_TYPE_MOTION: + libinput_config_accel_custom_func_destroy(config->custom.motion); + config->custom.motion = func; + break; + case LIBINPUT_ACCEL_TYPE_SCROLL: + libinput_config_accel_custom_func_destroy(config->custom.scroll); + config->custom.scroll = func; + break; + } + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +LIBINPUT_EXPORT int +libinput_device_config_scroll_has_natural_scroll(struct libinput_device *device) +{ + if (!device->config.natural_scroll) + return 0; + + return device->config.natural_scroll->has(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_scroll_set_natural_scroll_enabled(struct libinput_device *device, + int enabled) +{ + if (!libinput_device_config_scroll_has_natural_scroll(device)) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.natural_scroll->set_enabled(device, enabled); +} + +LIBINPUT_EXPORT int +libinput_device_config_scroll_get_natural_scroll_enabled(struct libinput_device *device) +{ + if (!device->config.natural_scroll) + return 0; + + return device->config.natural_scroll->get_enabled(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_scroll_get_default_natural_scroll_enabled(struct libinput_device *device) +{ + if (!device->config.natural_scroll) + return 0; + + return device->config.natural_scroll->get_default_enabled(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_left_handed_is_available(struct libinput_device *device) +{ + if (!device->config.left_handed) + return 0; + + return device->config.left_handed->has(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_left_handed_set(struct libinput_device *device, + int left_handed) +{ + if (!libinput_device_config_left_handed_is_available(device)) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.left_handed->set(device, left_handed); +} + +LIBINPUT_EXPORT int +libinput_device_config_left_handed_get(struct libinput_device *device) +{ + if (!libinput_device_config_left_handed_is_available(device)) + return 0; + + return device->config.left_handed->get(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_left_handed_get_default(struct libinput_device *device) +{ + if (!libinput_device_config_left_handed_is_available(device)) + return 0; + + return device->config.left_handed->get_default(device); +} + +LIBINPUT_EXPORT uint32_t +libinput_device_config_click_get_methods(struct libinput_device *device) +{ + if (device->config.click_method) + return device->config.click_method->get_methods(device); + + return 0; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_click_set_method(struct libinput_device *device, + enum libinput_config_click_method method) +{ + /* Check method is a single valid method */ + switch (method) { + case LIBINPUT_CONFIG_CLICK_METHOD_NONE: + case LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS: + case LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + if ((libinput_device_config_click_get_methods(device) & method) != method) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + if (device->config.click_method) + return device->config.click_method->set_method(device, method); + + /* method must be _NONE to get here */ + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +LIBINPUT_EXPORT enum libinput_config_click_method +libinput_device_config_click_get_method(struct libinput_device *device) +{ + if (device->config.click_method) + return device->config.click_method->get_method(device); + + return LIBINPUT_CONFIG_CLICK_METHOD_NONE; +} + +LIBINPUT_EXPORT enum libinput_config_click_method +libinput_device_config_click_get_default_method(struct libinput_device *device) +{ + if (device->config.click_method) + return device->config.click_method->get_default_method(device); + + return LIBINPUT_CONFIG_CLICK_METHOD_NONE; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_click_set_clickfinger_button_map(struct libinput_device *device, + enum libinput_config_clickfinger_button_map map) +{ + switch (map) { + case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM: + case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + if ((libinput_device_config_click_get_methods(device) & + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) != LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + return device->config.click_method->set_clickfinger_map(device, map); +} + +LIBINPUT_EXPORT enum libinput_config_clickfinger_button_map +libinput_device_config_click_get_clickfinger_button_map(struct libinput_device *device) +{ + if ((libinput_device_config_click_get_methods(device) & + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) != LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) + return LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM; + + return device->config.click_method->get_clickfinger_map(device); +} + +LIBINPUT_EXPORT enum libinput_config_clickfinger_button_map +libinput_device_config_click_get_default_clickfinger_button_map(struct libinput_device *device) +{ + if ((libinput_device_config_click_get_methods(device) & + LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) != LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER) + return LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM; + + return device->config.click_method->get_default_clickfinger_map(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_middle_emulation_is_available( + struct libinput_device *device) +{ + if (device->config.middle_emulation) + return device->config.middle_emulation->available(device); + + return LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_middle_emulation_set_enabled( + struct libinput_device *device, + enum libinput_config_middle_emulation_state enable) +{ + int available = + libinput_device_config_middle_emulation_is_available(device); + + switch (enable) { + case LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED: + if (!available) + return LIBINPUT_CONFIG_STATUS_SUCCESS; + break; + case LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED: + if (!available) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + return device->config.middle_emulation->set(device, enable); +} + +LIBINPUT_EXPORT enum libinput_config_middle_emulation_state +libinput_device_config_middle_emulation_get_enabled( + struct libinput_device *device) +{ + if (!libinput_device_config_middle_emulation_is_available(device)) + return LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; + + return device->config.middle_emulation->get(device); +} + +LIBINPUT_EXPORT enum libinput_config_middle_emulation_state +libinput_device_config_middle_emulation_get_default_enabled( + struct libinput_device *device) +{ + if (!libinput_device_config_middle_emulation_is_available(device)) + return LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; + + return device->config.middle_emulation->get_default(device); +} + +LIBINPUT_EXPORT uint32_t +libinput_device_config_scroll_get_methods(struct libinput_device *device) +{ + if (device->config.scroll_method) + return device->config.scroll_method->get_methods(device); + + return 0; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_scroll_set_method(struct libinput_device *device, + enum libinput_config_scroll_method method) +{ + /* Check method is a single valid method */ + switch (method) { + case LIBINPUT_CONFIG_SCROLL_NO_SCROLL: + case LIBINPUT_CONFIG_SCROLL_2FG: + case LIBINPUT_CONFIG_SCROLL_EDGE: + case LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + if ((libinput_device_config_scroll_get_methods(device) & method) != method) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + if (device->config.scroll_method) + return device->config.scroll_method->set_method(device, method); + + /* method must be _NO_SCROLL to get here */ + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +LIBINPUT_EXPORT enum libinput_config_scroll_method +libinput_device_config_scroll_get_method(struct libinput_device *device) +{ + if (device->config.scroll_method) + return device->config.scroll_method->get_method(device); + + return LIBINPUT_CONFIG_SCROLL_NO_SCROLL; +} + +LIBINPUT_EXPORT enum libinput_config_scroll_method +libinput_device_config_scroll_get_default_method(struct libinput_device *device) +{ + if (device->config.scroll_method) + return device->config.scroll_method->get_default_method(device); + + return LIBINPUT_CONFIG_SCROLL_NO_SCROLL; +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_scroll_set_button(struct libinput_device *device, + uint32_t button) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + if (button && !libinput_device_pointer_has_button(device, button)) + return LIBINPUT_CONFIG_STATUS_INVALID; + + return device->config.scroll_method->set_button(device, button); +} + +LIBINPUT_EXPORT uint32_t +libinput_device_config_scroll_get_button(struct libinput_device *device) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return 0; + + return device->config.scroll_method->get_button(device); +} + +LIBINPUT_EXPORT uint32_t +libinput_device_config_scroll_get_default_button(struct libinput_device *device) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return 0; + + return device->config.scroll_method->get_default_button(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_scroll_set_button_lock(struct libinput_device *device, + enum libinput_config_scroll_button_lock_state state) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + + switch (state) { + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED: + case LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED: + break; + default: + return LIBINPUT_CONFIG_STATUS_INVALID; + } + + return device->config.scroll_method->set_button_lock(device, state); +} + +LIBINPUT_EXPORT enum libinput_config_scroll_button_lock_state +libinput_device_config_scroll_get_button_lock(struct libinput_device *device) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; + + return device->config.scroll_method->get_button_lock(device); +} + +LIBINPUT_EXPORT enum libinput_config_scroll_button_lock_state +libinput_device_config_scroll_get_default_button_lock(struct libinput_device *device) +{ + if ((libinput_device_config_scroll_get_methods(device) & + LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) == 0) + return LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED; + + return device->config.scroll_method->get_default_button_lock(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_dwt_is_available(struct libinput_device *device) +{ + if (!device->config.dwt) + return 0; + + return device->config.dwt->is_available(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_dwt_set_enabled(struct libinput_device *device, + enum libinput_config_dwt_state enable) +{ + if (enable != LIBINPUT_CONFIG_DWT_ENABLED && + enable != LIBINPUT_CONFIG_DWT_DISABLED) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (!libinput_device_config_dwt_is_available(device)) + return enable ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : + LIBINPUT_CONFIG_STATUS_SUCCESS; + + return device->config.dwt->set_enabled(device, enable); +} + +LIBINPUT_EXPORT enum libinput_config_dwt_state +libinput_device_config_dwt_get_enabled(struct libinput_device *device) +{ + if (!libinput_device_config_dwt_is_available(device)) + return LIBINPUT_CONFIG_DWT_DISABLED; + + return device->config.dwt->get_enabled(device); +} + +LIBINPUT_EXPORT enum libinput_config_dwt_state +libinput_device_config_dwt_get_default_enabled(struct libinput_device *device) +{ + if (!libinput_device_config_dwt_is_available(device)) + return LIBINPUT_CONFIG_DWT_DISABLED; + + return device->config.dwt->get_default_enabled(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_dwtp_is_available(struct libinput_device *device) +{ + if (!device->config.dwtp) + return 0; + + return device->config.dwtp->is_available(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_dwtp_set_enabled(struct libinput_device *device, + enum libinput_config_dwtp_state enable) +{ + if (enable != LIBINPUT_CONFIG_DWTP_ENABLED && + enable != LIBINPUT_CONFIG_DWTP_DISABLED) + return LIBINPUT_CONFIG_STATUS_INVALID; + + if (!libinput_device_config_dwtp_is_available(device)) + return enable ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : + LIBINPUT_CONFIG_STATUS_SUCCESS; + + return device->config.dwtp->set_enabled(device, enable); +} + +LIBINPUT_EXPORT enum libinput_config_dwtp_state +libinput_device_config_dwtp_get_enabled(struct libinput_device *device) +{ + if (!libinput_device_config_dwtp_is_available(device)) + return LIBINPUT_CONFIG_DWTP_DISABLED; + + return device->config.dwtp->get_enabled(device); +} + +LIBINPUT_EXPORT enum libinput_config_dwtp_state +libinput_device_config_dwtp_get_default_enabled(struct libinput_device *device) +{ + if (!libinput_device_config_dwtp_is_available(device)) + return LIBINPUT_CONFIG_DWTP_DISABLED; + + return device->config.dwtp->get_default_enabled(device); +} + +LIBINPUT_EXPORT int +libinput_device_config_rotation_is_available(struct libinput_device *device) +{ + if (!device->config.rotation) + return 0; + + return device->config.rotation->is_available(device); +} + +LIBINPUT_EXPORT enum libinput_config_status +libinput_device_config_rotation_set_angle(struct libinput_device *device, + unsigned int degrees_cw) +{ + if (!libinput_device_config_rotation_is_available(device)) + return degrees_cw ? LIBINPUT_CONFIG_STATUS_UNSUPPORTED : + LIBINPUT_CONFIG_STATUS_SUCCESS; + + if (degrees_cw >= 360) + return LIBINPUT_CONFIG_STATUS_INVALID; + + return device->config.rotation->set_angle(device, degrees_cw); +} + +LIBINPUT_EXPORT unsigned int +libinput_device_config_rotation_get_angle(struct libinput_device *device) +{ + if (!libinput_device_config_rotation_is_available(device)) + return 0; + + return device->config.rotation->get_angle(device); +} + +LIBINPUT_EXPORT unsigned int +libinput_device_config_rotation_get_default_angle(struct libinput_device *device) +{ + if (!libinput_device_config_rotation_is_available(device)) + return 0; + + return device->config.rotation->get_default_angle(device); +} + +#if HAVE_LIBWACOM +WacomDeviceDatabase * +libinput_libwacom_ref(struct libinput *li) +{ + WacomDeviceDatabase *db = NULL; + if (!li->libwacom.db) { + db = libwacom_database_new(); + if (!db) { + log_error(li, + "Failed to initialize libwacom context\n"); + return NULL; + } + + li->libwacom.db = db; + li->libwacom.refcount = 0; + } + + li->libwacom.refcount++; + db = li->libwacom.db; + return db; +} + +void +libinput_libwacom_unref(struct libinput *li) +{ + if (!li->libwacom.db) + return; + + assert(li->libwacom.refcount >= 1); + + if (--li->libwacom.refcount == 0) { + libwacom_database_destroy(li->libwacom.db); + li->libwacom.db = NULL; + } +} +#endif diff --git a/src/util-strings.h b/src/util-strings.h index b09168152..184080c6a 100644 --- a/src/util-strings.h +++ b/src/util-strings.h @@ -242,7 +242,11 @@ safe_atod(const char *str, double *val) return false; errno = 0; +#if !defined(__OpenBSD__) && !defined(__NetBSD__) v = strtod_l(str, &endptr, c_locale); +#else + v = strtod(str, &endptr); +#endif freelocale(c_locale); #else /* No locale support in provided libc, assume it already uses '.' */ diff --git a/src/wscons.c b/src/wscons.c new file mode 100644 index 000000000..2120f0738 --- /dev/null +++ b/src/wscons.c @@ -0,0 +1,597 @@ +/* + * Copyright © 2015 Martin Pieuchot + * + * 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 +#include +#include +#include +#include + +#include "libinput.h" +#include "filter.h" +#include "wscons.h" +#include "input-event-codes.h" +#include "libinput-util.h" +#include "libinput-private.h" + +static const char default_seat[] = "seat0"; +static const char default_seat_name[] = "default"; + +static struct libinput_seat* wscons_seat_get(struct libinput *, const char *, + const char *); +static void wscons_device_dispatch(void *); + +static void +wscons_device_init_pointer_acceleration(struct wscons_device *device, + struct motion_filter *filter); + +static int old_value = -1; + +static int +udev_input_enable(struct libinput *libinput) +{ + struct libinput_seat *seat; + struct libinput_device *device; + + seat = wscons_seat_get(libinput, default_seat, default_seat_name); + list_for_each(device, &seat->devices_list, link) { + device->fd = open_restricted(libinput, device->devname, O_RDWR); + device->source = + libinput_add_fd(libinput, device->fd, + wscons_device_dispatch, device); + if (!device->source) { + return -ENOMEM; + } + } + return 0; +} + +static void +udev_input_disable(struct libinput *libinput) +{ + struct libinput_seat *seat; + struct libinput_device *device; + + seat = wscons_seat_get(libinput, default_seat, default_seat_name); + list_for_each(device, &seat->devices_list, link) { + if (device->source) { + libinput_remove_source(libinput, device->source); + device->source = NULL; + } + close_restricted(libinput, device->fd); + } +} + +static void +udev_input_destroy(struct libinput *libinput) +{ + struct libinput_seat *seat; + struct libinput_device *device; + + fprintf(stderr, "%s", __func__); + seat = wscons_seat_get(libinput, default_seat, default_seat_name); + list_for_each(device, &seat->devices_list, link) { + close_restricted(libinput, device->fd); + } +} + +static int +udev_device_change_seat(struct libinput_device *device, + const char *seat_name) +{ + return 0; +} + +static const struct libinput_interface_backend interface_backend = { + .resume = udev_input_enable, + .suspend = udev_input_disable, + .destroy = udev_input_destroy, + .device_change_seat = udev_device_change_seat, +}; + +static void +wscons_process(struct libinput_device *device, struct wscons_event *wsevent) +{ + enum libinput_button_state bstate; + enum libinput_key_state kstate; + struct normalized_coords accel; + struct device_float_coords raw; + struct wscons_device *dev = wscons_device(device); + uint64_t time; + int button, key; + + time = s2us(wsevent->time.tv_sec) + ns2us(wsevent->time.tv_nsec); + + switch (wsevent->type) { + case WSCONS_EVENT_KEY_UP: + case WSCONS_EVENT_KEY_DOWN: + key = wsevent->value; + if (wsevent->type == WSCONS_EVENT_KEY_UP) { + kstate = LIBINPUT_KEY_STATE_RELEASED; + old_value = -1; + } else { + kstate = LIBINPUT_KEY_STATE_PRESSED; + /* ignore auto-repeat */ + if (key == old_value) + return; + old_value = key; + } + keyboard_notify_key(device, time, + wskey_transcode(wscons_device(device)->scanCodeMap, key), kstate); + break; + + case WSCONS_EVENT_MOUSE_UP: + case WSCONS_EVENT_MOUSE_DOWN: + /* button to Linux events */ + switch (wsevent->value) { + case 1: + button = BTN_MIDDLE; + break; + case 2: + button = BTN_RIGHT; + break; + default: + button = wsevent->value + BTN_LEFT; + break; + } + if (wsevent->type == WSCONS_EVENT_MOUSE_UP) + bstate = LIBINPUT_BUTTON_STATE_RELEASED; + else + bstate = LIBINPUT_BUTTON_STATE_PRESSED; + pointer_notify_button(device, time, button, bstate); + break; + + case WSCONS_EVENT_MOUSE_DELTA_X: + case WSCONS_EVENT_MOUSE_DELTA_Y: + memset(&raw, 0, sizeof(raw)); + memset(&accel, 0, sizeof(accel)); + + if (wsevent->type == WSCONS_EVENT_MOUSE_DELTA_X) + raw.x = wsevent->value; + else + raw.y = -wsevent->value; + + if (dev->pointer.filter) { + accel = filter_dispatch(dev->pointer.filter, + &raw, + device, + time); + } else { + accel.x = raw.x; + accel.y = raw.y; + } + + pointer_notify_motion(device, time, &accel, &raw); + break; + + case WSCONS_EVENT_MOUSE_DELTA_Z: + memset(&raw, 0, sizeof(raw)); + accel.x = 0; + accel.y = wsevent->value * 32; + axis_notify_event(device, time, &accel, &raw); + break; + + case WSCONS_EVENT_MOUSE_ABSOLUTE_X: + case WSCONS_EVENT_MOUSE_ABSOLUTE_Y: + //return LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE; + break; + + case WSCONS_EVENT_HSCROLL: + memset(&raw, 0, sizeof(raw)); + accel.x = wsevent->value/8; + accel.y = 0; + axis_notify_event(device, time, &accel, &raw); + break; + case WSCONS_EVENT_VSCROLL: + memset(&raw, 0, sizeof(raw)); + accel.x = 0; + accel.y = wsevent->value/8; + axis_notify_event(device, time, &accel, &raw); + break; + +#ifdef WSCONS_EVENT_SYNC + case WSCONS_EVENT_SYNC: + break; +#endif + + case WSCONS_EVENT_MOUSE_ABSOLUTE_Z: + case WSCONS_EVENT_MOUSE_ABSOLUTE_W: +#ifdef WSCONS_EVENT_TOUCH_WIDTH + case WSCONS_EVENT_TOUCH_WIDTH: +#endif +#ifdef WSCONS_EVENT_TOUCH_RESET + case WSCONS_EVENT_TOUCH_RESET: +#endif + /* ignore those */ + break; + default: + fprintf(stderr, "unkown event: %x\n" , wsevent->type); + /* assert(1 == 0); */ + break; + } +} + +static void +wscons_device_dispatch(void *data) +{ + struct libinput_device *device = data; + struct wscons_event wsevents[32]; + ssize_t len; + int count, i; + + len = read(device->fd, wsevents, sizeof(struct wscons_event)); + if (len <= 0 || (len % sizeof(struct wscons_event)) != 0) + return; + + count = len / sizeof(struct wscons_event); + for (i = 0; i < count; i++) { + wscons_process(device, &wsevents[i]); + } +} + +static void +udev_seat_destroy(struct libinput_seat *seat) +{ + struct udev_seat *useat = (struct udev_seat*)seat; + free(useat); +} + +static struct libinput_seat* +wscons_seat_get(struct libinput *libinput, const char *seat_name_physical, + const char *seat_name_logical) +{ + struct libinput_seat *seat; + + list_for_each(seat, &libinput->seat_list, link) { + if (streq(seat->physical_name, seat_name_physical) && + streq(seat->logical_name, seat_name_logical)) { + libinput_seat_ref(seat); + return seat; + } + } + + seat = calloc(1, sizeof(*seat)); + if (seat == NULL) + return NULL; + + libinput_seat_init(seat, libinput, seat_name_physical, + seat_name_logical, udev_seat_destroy); + + return seat; +} + +LIBINPUT_EXPORT struct libinput * +libinput_udev_create_context(const struct libinput_interface *interface, + void *user_data, + struct udev *udev) +{ + struct libinput *libinput; + + libinput = calloc(1, sizeof(*libinput)); + if (libinput == NULL) + return NULL; + + if (libinput_init(libinput, interface, &interface_backend, user_data) != 0) { + free(libinput); + return NULL; + } + return libinput; +} + +LIBINPUT_EXPORT int +libinput_udev_assign_seat(struct libinput *libinput, const char *seat_id) +{ + + struct libinput_seat *seat; + struct libinput_device *device; + uint64_t time; + struct timespec ts; + struct libinput_event *event; + + /* Add standard devices */ + for (int i = 0; i < 10; i++) { + char name[32]; + int fd; + snprintf(name, sizeof(name), "/dev/wskbd%d", i); + if ((fd = open_restricted(libinput, name, O_RDWR|O_NONBLOCK)) >= 0) { + close_restricted(libinput, fd); + libinput_path_add_device(libinput, name); + } + snprintf(name, sizeof(name), "/dev/wsmouse%d", i); + if ((fd = open_restricted(libinput, name, O_RDWR|O_NONBLOCK)) >= 0) { + close_restricted(libinput, fd); + libinput_path_add_device(libinput, name); + } + } + + seat = wscons_seat_get(libinput, default_seat, default_seat_name); + list_for_each(device, &seat->devices_list, link) { + clock_gettime(CLOCK_REALTIME, &ts); + time = s2us(ts.tv_sec) + ns2us(ts.tv_nsec); + event = calloc(1, sizeof(*event)); + post_device_event(device, time, LIBINPUT_EVENT_DEVICE_ADDED, + event); + } + return 0; +} + +LIBINPUT_EXPORT struct libinput * +libinput_path_create_context(const struct libinput_interface *interface, + void *user_data) +{ + struct libinput *libinput; + + libinput = calloc(1, sizeof(*libinput)); + if (libinput == NULL) + return NULL; + + if (libinput_init(libinput, interface, &interface_backend, user_data) != 0) { + free(libinput); + return NULL; + } + + return libinput; +} + +static double +wscons_accel_config_get_speed(struct libinput_device *device) +{ + struct wscons_device *dev = wscons_device(device); + + return filter_get_speed(dev->pointer.filter); +} + +static enum libinput_config_status +wscons_accel_config_set_speed(struct libinput_device *device, double speed) +{ + struct wscons_device *dev = wscons_device(device); + + if (!filter_set_speed(dev->pointer.filter, speed)) + return LIBINPUT_CONFIG_STATUS_INVALID; + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static double +wscons_accel_config_get_default_speed(struct libinput_device *device) +{ + return 0.0; +} + +static int +wscons_accel_config_available(struct libinput_device *device) +{ + /* this function is only called if we set up ptraccel, so we can + reply with a resounding "Yes" */ + return 1; +} + +static enum libinput_config_accel_profile +wscons_accel_config_get_profile(struct libinput_device *libinput_device) +{ + struct wscons_device *device = wscons_device(libinput_device); + + return filter_get_type(device->pointer.filter); +} + +static inline bool +wscons_init_accel(struct wscons_device *device, + enum libinput_config_accel_profile which) +{ + struct motion_filter *filter = NULL; + + if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM) { + filter = create_custom_accelerator_filter(); + } else { + if (which == LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT) + filter = create_pointer_accelerator_filter_flat(DEFAULT_MOUSE_DPI); + else + filter = create_pointer_accelerator_filter_linear_low_dpi(DEFAULT_MOUSE_DPI, + true); + } + + if (!filter) + filter = create_pointer_accelerator_filter_linear(DEFAULT_MOUSE_DPI, + true); + + if (!filter) + return false; + + wscons_device_init_pointer_acceleration(device, filter); + + return true; +} + +static enum libinput_config_status +wscons_accel_config_set_profile(struct libinput_device *libinput_device, + enum libinput_config_accel_profile profile) +{ + struct wscons_device *device = wscons_device(libinput_device); + struct motion_filter *filter; + double speed; + + filter = device->pointer.filter; + if (filter_get_type(filter) == profile) + return LIBINPUT_CONFIG_STATUS_SUCCESS; + + speed = filter_get_speed(filter); + device->pointer.filter = NULL; + + if (wscons_init_accel(device, profile)) { + wscons_accel_config_set_speed(libinput_device, speed); + filter_destroy(filter); + } else { + device->pointer.filter = filter; + return LIBINPUT_CONFIG_STATUS_UNSUPPORTED; + } + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static uint32_t +wscons_accel_config_get_profiles(struct libinput_device *libinput_device) +{ + struct wscons_device *device = wscons_device(libinput_device); + + if (!device->pointer.filter) + return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; + + return LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE | + LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT | + LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM; +} + +static enum libinput_config_accel_profile +wscons_accel_config_get_default_profile(struct libinput_device *libinput_device) +{ + struct wscons_device *device = wscons_device(libinput_device); + + if (!device->pointer.filter) + return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE; + + /* No device has a flat profile as default */ + return LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE; +} + +static enum libinput_config_status +wscons_set_accel_config(struct libinput_device *libinput_device, + struct libinput_config_accel *accel_config) +{ + assert(wscons_accel_config_get_profile(libinput_device) == accel_config->profile); + + struct wscons_device *dev = wscons_device(libinput_device); + + if (!filter_set_accel_config(dev->pointer.filter, accel_config)) + return LIBINPUT_CONFIG_STATUS_INVALID; + + return LIBINPUT_CONFIG_STATUS_SUCCESS; +} + +static void +wscons_device_init_pointer_acceleration(struct wscons_device *device, + struct motion_filter *filter) +{ + device->pointer.filter = filter; + + if (device->base.config.accel == NULL) { + double default_speed; + + device->pointer.config.available = wscons_accel_config_available; + device->pointer.config.set_speed = wscons_accel_config_set_speed; + device->pointer.config.get_speed = wscons_accel_config_get_speed; + device->pointer.config.get_default_speed = wscons_accel_config_get_default_speed; + device->pointer.config.get_profiles = wscons_accel_config_get_profiles; + device->pointer.config.set_profile = wscons_accel_config_set_profile; + device->pointer.config.get_profile = wscons_accel_config_get_profile; + device->pointer.config.get_default_profile = wscons_accel_config_get_default_profile; + device->pointer.config.set_accel_config = wscons_set_accel_config; + device->base.config.accel = &device->pointer.config; + + default_speed = wscons_accel_config_get_default_speed(&device->base); + wscons_accel_config_set_speed(&device->base, default_speed); + } +} + +static int +wscons_device_init(struct wscons_device *wscons_device) +{ + struct libinput_device *device = &wscons_device->base; + + if (strncmp(device->devname, "/dev/wsmouse", 12) == 0) { + /* XXX handle tablets and touchpanel */ + wscons_device->capability = LIBINPUT_DEVICE_CAP_POINTER; + wscons_init_accel(wscons_device, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE); + } else if (strncmp(device->devname, "/dev/wskbd", 10) == 0) { + wscons_device->capability = LIBINPUT_DEVICE_CAP_KEYBOARD; + if (wscons_keyboard_init(wscons_device) == -1) + return -1; + } + return 0; +} + +LIBINPUT_EXPORT struct libinput_device * +libinput_path_add_device(struct libinput *libinput, + const char *path) +{ + struct libinput_seat *seat = NULL; + struct libinput_device *device = NULL; + struct wscons_device *wscons_device; + int fd; + + fd = open_restricted(libinput, path, + O_RDWR | O_NONBLOCK | O_CLOEXEC); + if (fd < 0) { + log_info(libinput, + "opening input device '%s' failed (%s).\n", + path, strerror(-fd)); + return NULL; + } + + wscons_device = calloc(1, sizeof(*wscons_device)); + if (wscons_device == NULL) + return NULL; + + /* Only one (default) seat is supported. */ + seat = wscons_seat_get(libinput, default_seat, default_seat_name); + if (seat == NULL) + goto err; + + device = &wscons_device->base; + libinput_device_init(device, seat); + + device->fd = fd; + device->devname = strdup(path); + if (device->devname == NULL) + goto err; + + device->source = + libinput_add_fd(libinput, fd, wscons_device_dispatch, device); + if (!device->source) + goto err; + + if (wscons_device_init(wscons_device) == -1) + goto err; + list_insert(&seat->devices_list, &device->link); + + return device; + +err: + if (device != NULL) + close_restricted(libinput, device->fd); + free(wscons_device); + return NULL; +} + +LIBINPUT_EXPORT void +libinput_path_remove_device(struct libinput_device *device) +{ + struct libinput *libinput = device->seat->libinput; + + libinput_remove_source(libinput, device->source); + device->source = NULL; + + close_restricted(libinput, device->fd); + device->fd = -1; + + libinput_device_unref(device); +} diff --git a/src/wscons.h b/src/wscons.h new file mode 100644 index 000000000..636e74879 --- /dev/null +++ b/src/wscons.h @@ -0,0 +1,38 @@ +#ifndef _LIBINPUT_WSCONS_H +#define _LIBINPUT_WSCONS_H + +#include + +#include "libinput-private.h" + +#define WSCONS_TYPE_POINTER 1 +#define WSCONS_TYPE_KEYBOARD 2 + +struct TransMapRec { + int begin; + int end; + uint32_t *map; +}; + +struct wscons_device { + struct libinput_device base; + enum libinput_device_capability capability; + struct TransMapRec *scanCodeMap; + struct { + struct libinput_device_config_accel config; + struct motion_filter *filter; + } pointer; +}; + + +static inline struct wscons_device * +wscons_device(struct libinput_device *device) +{ + return container_of(device, struct wscons_device, base); +} +extern int wscons_keyboard_init(struct wscons_device *); +extern uint32_t wskey_transcode(struct TransMapRec *, int); +extern void post_device_event(struct libinput_device *, uint64_t , + enum libinput_event_type , struct libinput_event *); + +#endif diff --git a/src/wskbdmap.c b/src/wskbdmap.c new file mode 100644 index 000000000..d030ab6d1 --- /dev/null +++ b/src/wskbdmap.c @@ -0,0 +1,547 @@ +#include +#include +#include +#include "wscons.h" +#include "input-event-codes.h" + +static uint32_t wsUsbMap[] = { + /* 0 */ KEY_RESERVED, + /* 1 */ KEY_RESERVED, + /* 2 */ KEY_RESERVED, + /* 3 */ KEY_RESERVED, + /* 4 */ KEY_A, + /* 5 */ KEY_B, + /* 6 */ KEY_C, + /* 7 */ KEY_D, + /* 8 */ KEY_E, + /* 9 */ KEY_F, + /* 10 */ KEY_G, + /* 11 */ KEY_H, + /* 12 */ KEY_I, + /* 13 */ KEY_J, + /* 14 */ KEY_K, + /* 15 */ KEY_L, + /* 16 */ KEY_M, + /* 17 */ KEY_N, + /* 18 */ KEY_O, + /* 19 */ KEY_P, + /* 20 */ KEY_Q, + /* 21 */ KEY_R, + /* 22 */ KEY_S, + /* 23 */ KEY_T, + /* 24 */ KEY_U, + /* 25 */ KEY_V, + /* 26 */ KEY_W, + /* 27 */ KEY_X, + /* 28 */ KEY_Y, + /* 29 */ KEY_Z, + /* 30 */ KEY_1, /* 1 !*/ + /* 31 */ KEY_2, /* 2 @ */ + /* 32 */ KEY_3, /* 3 # */ + /* 33 */ KEY_4, /* 4 $ */ + /* 34 */ KEY_5, /* 5 % */ + /* 35 */ KEY_6, /* 6 ^ */ + /* 36 */ KEY_7, /* 7 & */ + /* 37 */ KEY_8, /* 8 * */ + /* 38 */ KEY_9, /* 9 ( */ + /* 39 */ KEY_0, /* 0 ) */ + /* 40 */ KEY_ENTER, /* Return */ + /* 41 */ KEY_ESC, /* Escape */ + /* 42 */ KEY_BACKSPACE, /* Backspace Delete */ + /* 43 */ KEY_TAB, /* Tab */ + /* 44 */ KEY_SPACE, /* Space */ + /* 45 */ KEY_MINUS, /* - _ */ + /* 46 */ KEY_EQUAL, /* = + */ + /* 47 */ KEY_LEFTBRACE, /* [ { */ + /* 48 */ KEY_RIGHTBRACE, /* ] } */ + /* 49 */ KEY_BACKSLASH, /* \ | */ + /* 50 */ KEY_BACKSLASH, /* \ _ # ~ on some keyboards */ + /* 51 */ KEY_SEMICOLON, /* ; : */ + /* 52 */ KEY_APOSTROPHE, /* ' " */ + /* 53 */ KEY_GRAVE, /* ` ~ */ + /* 54 */ KEY_COMMA, /* , < */ + /* 55 */ KEY_DOT, /* . > */ + /* 56 */ KEY_SLASH, /* / ? */ + /* 57 */ KEY_CAPSLOCK, /* Caps Lock */ + /* 58 */ KEY_F1, /* F1 */ + /* 59 */ KEY_F2, /* F2 */ + /* 60 */ KEY_F3, /* F3 */ + /* 61 */ KEY_F4, /* F4 */ + /* 62 */ KEY_F5, /* F5 */ + /* 63 */ KEY_F6, /* F6 */ + /* 64 */ KEY_F7, /* F7 */ + /* 65 */ KEY_F8, /* F8 */ + /* 66 */ KEY_F9, /* F9 */ + /* 67 */ KEY_F10, /* F10 */ + /* 68 */ KEY_F11, /* F11 */ + /* 69 */ KEY_F12, /* F12 */ + /* 70 */ KEY_PRINT, /* PrintScrn SysReq */ + /* 71 */ KEY_SCROLLLOCK, /* Scroll Lock */ + /* 72 */ KEY_PAUSE, /* Pause Break */ + /* 73 */ KEY_INSERT, /* Insert XXX Help on some Mac Keyboards */ + /* 74 */ KEY_HOME, /* Home */ + /* 75 */ KEY_PAGEUP, /* Page Up */ + /* 76 */ KEY_DELETE, /* Delete */ + /* 77 */ KEY_END, /* End */ + /* 78 */ KEY_PAGEDOWN, /* Page Down */ + /* 79 */ KEY_RIGHT, /* Right Arrow */ + /* 80 */ KEY_LEFT, /* Left Arrow */ + /* 81 */ KEY_DOWN, /* Down Arrow */ + /* 82 */ KEY_UP, /* Up Arrow */ + /* 83 */ KEY_NUMLOCK, /* Num Lock */ + /* 84 */ KEY_KPSLASH, /* Keypad / */ + /* 85 */ KEY_KPASTERISK, /* Keypad * */ + /* 86 */ KEY_KPMINUS, /* Keypad - */ + /* 87 */ KEY_KPPLUS, /* Keypad + */ + /* 88 */ KEY_KPENTER, /* Keypad Enter */ + /* 89 */ KEY_KP1, /* Keypad 1 End */ + /* 90 */ KEY_KP2, /* Keypad 2 Down */ + /* 91 */ KEY_KP3, /* Keypad 3 Pg Down */ + /* 92 */ KEY_KP4, /* Keypad 4 Left */ + /* 93 */ KEY_KP5, /* Keypad 5 */ + /* 94 */ KEY_KP6, /* Keypad 6 */ + /* 95 */ KEY_KP7, /* Keypad 7 Home */ + /* 96 */ KEY_KP8, /* Keypad 8 Up */ + /* 97 */ KEY_KP9, /* KEypad 9 Pg Up */ + /* 98 */ KEY_KP0, /* Keypad 0 Ins */ + /* 99 */ KEY_KPDOT, /* Keypad . Del */ + /* 100 */ KEY_102ND, /* < > on some keyboards */ + /* 101 */ KEY_MENU, /* Menu */ + /* 102 */ KEY_POWER, /* sleep key on Sun USB */ + /* 103 */ KEY_KPEQUAL, /* Keypad = on Mac keyboards */ + /* 104 */ KEY_F13, + /* 105 */ KEY_F14, + /* 106 */ KEY_F15, + /* 107 */ KEY_F16, + /* 108 */ KEY_RESERVED, + /* 109 */ KEY_POWER, + /* 110 */ KEY_RESERVED, + /* 111 */ KEY_RESERVED, + /* 112 */ KEY_RESERVED, + /* 113 */ KEY_RESERVED, + /* 114 */ KEY_RESERVED, + /* 115 */ KEY_RESERVED, + /* 116 */ KEY_OPEN, /* L7 */ + /* 117 */ KEY_HELP, + /* 118 */ KEY_PROPS, /* L3 */ + /* 119 */ KEY_FRONT, /* L5 */ + /* 120 */ KEY_STOP, /* L1 */ + /* 121 */ KEY_AGAIN, /* L2 */ + /* 122 */ KEY_UNDO, /* L4 */ + /* 123 */ KEY_CUT, /* L10 */ + /* 124 */ KEY_COPY, /* L6 */ + /* 125 */ KEY_PASTE, /* L8 */ + /* 126 */ KEY_FIND, /* L9 */ + /* 127 */ KEY_MUTE, + /* 128 */ KEY_VOLUMEUP, + /* 129 */ KEY_VOLUMEDOWN, + /* 130 */ KEY_RESERVED, + /* 131 */ KEY_RESERVED, + /* 132 */ KEY_RESERVED, + /* 133 */ KEY_RESERVED, + /* 134 */ KEY_RESERVED, + /* 135 */ KEY_RESERVED, /* Japanese 106 kbd: '\_' */ + /* 136 */ KEY_RESERVED, /* Japanese 106 kbd: Hiragana Katakana toggle */ + /* 137 */ KEY_YEN, /* Japanese 106 kbd: '\|' */ + /* 138 */ KEY_RESERVED, /* Japanese 106 kbd: Henkan */ + /* 139 */ KEY_RESERVED, /* Japanese 106 kbd: Muhenkan */ + /* 140 */ KEY_RESERVED, + /* 141 */ KEY_RESERVED, + /* 142 */ KEY_RESERVED, + /* 143 */ KEY_RESERVED, + /* 144 */ KEY_RESERVED, /* Korean 106 kbd: Hangul */ + /* 145 */ KEY_RESERVED, /* Korean 106 kbd: Hangul Hanja */ + /* 146 */ KEY_RESERVED, + /* 147 */ KEY_RESERVED, + /* 148 */ KEY_RESERVED, + /* 149 */ KEY_RESERVED, + /* 150 */ KEY_RESERVED, + /* 151 */ KEY_RESERVED, + /* 152 */ KEY_RESERVED, + /* 153 */ KEY_RESERVED, + /* 154 */ KEY_RESERVED, + /* 155 */ KEY_RESERVED, + /* 156 */ KEY_RESERVED, + /* 157 */ KEY_RESERVED, + /* 158 */ KEY_RESERVED, + /* 159 */ KEY_RESERVED, + /* 160 */ KEY_RESERVED, + /* 161 */ KEY_RESERVED, + /* 162 */ KEY_RESERVED, + /* 163 */ KEY_RESERVED, + /* 164 */ KEY_RESERVED, + /* 165 */ KEY_RESERVED, + /* 166 */ KEY_RESERVED, + /* 167 */ KEY_RESERVED, + /* 168 */ KEY_RESERVED, + /* 169 */ KEY_RESERVED, + /* 170 */ KEY_RESERVED, + /* 171 */ KEY_RESERVED, + /* 172 */ KEY_RESERVED, + /* 173 */ KEY_RESERVED, + /* 174 */ KEY_RESERVED, + /* 175 */ KEY_RESERVED, + /* 176 */ KEY_RESERVED, + /* 177 */ KEY_RESERVED, + /* 178 */ KEY_RESERVED, + /* 179 */ KEY_RESERVED, + /* 180 */ KEY_RESERVED, + /* 181 */ KEY_RESERVED, + /* 182 */ KEY_RESERVED, + /* 183 */ KEY_RESERVED, + /* 184 */ KEY_RESERVED, + /* 185 */ KEY_RESERVED, + /* 186 */ KEY_RESERVED, + /* 187 */ KEY_RESERVED, + /* 188 */ KEY_RESERVED, + /* 189 */ KEY_RESERVED, + /* 190 */ KEY_RESERVED, + /* 191 */ KEY_RESERVED, + /* 192 */ KEY_RESERVED, + /* 193 */ KEY_RESERVED, + /* 194 */ KEY_RESERVED, + /* 195 */ KEY_RESERVED, + /* 196 */ KEY_RESERVED, + /* 197 */ KEY_RESERVED, + /* 198 */ KEY_RESERVED, + /* 199 */ KEY_RESERVED, + /* 200 */ KEY_RESERVED, + /* 201 */ KEY_RESERVED, + /* 202 */ KEY_RESERVED, + /* 203 */ KEY_RESERVED, + /* 204 */ KEY_RESERVED, + /* 205 */ KEY_RESERVED, + /* 206 */ KEY_RESERVED, + /* 207 */ KEY_RESERVED, + /* 208 */ KEY_RESERVED, + /* 209 */ KEY_RESERVED, + /* 210 */ KEY_RESERVED, + /* 211 */ KEY_RESERVED, + /* 212 */ KEY_RESERVED, + /* 213 */ KEY_RESERVED, + /* 214 */ KEY_RESERVED, + /* 215 */ KEY_RESERVED, + /* 216 */ KEY_RESERVED, + /* 217 */ KEY_RESERVED, + /* 218 */ KEY_RESERVED, + /* 219 */ KEY_RESERVED, + /* 220 */ KEY_RESERVED, + /* 221 */ KEY_RESERVED, + /* 222 */ KEY_RESERVED, + /* 223 */ KEY_RESERVED, + /* 224 */ KEY_LEFTCTRL, /* Left Control */ + /* 225 */ KEY_LEFTSHIFT, /* Left Shift */ + /* 226 */ KEY_LEFTALT, /* Left Alt */ + /* 227 */ KEY_LEFTMETA, /* Left Meta */ + /* 228 */ KEY_RIGHTCTRL, /* Right Control */ + /* 229 */ KEY_RIGHTSHIFT, /* Right Shift */ + /* 230 */ KEY_RIGHTALT, /* Right Alt, AKA AltGr */ + /* 231 */ KEY_RIGHTMETA, /* Right Meta */ +}; +#define WS_USB_MAP_SIZE (sizeof(wsUsbMap)/sizeof(*wsUsbMap)) +static +struct TransMapRec wsUsb = { + 0, + WS_USB_MAP_SIZE, + wsUsbMap +}; + +static uint32_t wsXtMap[] = { + /* 0 */ KEY_RESERVED, + /* 1 */ KEY_ESC, + /* 2 */ KEY_1, + /* 3 */ KEY_2, + /* 4 */ KEY_3, + /* 5 */ KEY_4, + /* 6 */ KEY_5, + /* 7 */ KEY_6, + /* 8 */ KEY_7, + /* 9 */ KEY_8, + /* 10 */ KEY_9, + /* 11 */ KEY_0, + /* 12 */ KEY_MINUS, + /* 13 */ KEY_EQUAL, + /* 14 */ KEY_BACKSPACE, + /* 15 */ KEY_TAB, + /* 16 */ KEY_Q, + /* 17 */ KEY_W, + /* 18 */ KEY_E, + /* 19 */ KEY_R, + /* 20 */ KEY_T, + /* 21 */ KEY_Y, + /* 22 */ KEY_U, + /* 23 */ KEY_I, + /* 24 */ KEY_O, + /* 25 */ KEY_P, + /* 26 */ KEY_LEFTBRACE, + /* 27 */ KEY_RIGHTBRACE, + /* 28 */ KEY_ENTER, + /* 29 */ KEY_LEFTCTRL, + /* 30 */ KEY_A, + /* 31 */ KEY_S, + /* 32 */ KEY_D, + /* 33 */ KEY_F, + /* 34 */ KEY_G, + /* 35 */ KEY_H, + /* 36 */ KEY_J, + /* 37 */ KEY_K, + /* 38 */ KEY_L, + /* 39 */ KEY_SEMICOLON, + /* 40 */ KEY_APOSTROPHE, + /* 41 */ KEY_GRAVE, + /* 42 */ KEY_LEFTSHIFT, + /* 43 */ KEY_BACKSLASH, + /* 44 */ KEY_Z, + /* 45 */ KEY_X, + /* 46 */ KEY_C, + /* 47 */ KEY_V, + /* 48 */ KEY_B, + /* 49 */ KEY_N, + /* 50 */ KEY_M, + /* 51 */ KEY_COMMA, + /* 52 */ KEY_DOT, + /* 53 */ KEY_SLASH, + /* 54 */ KEY_RIGHTSHIFT, + /* 55 */ KEY_KPASTERISK, + /* 56 */ KEY_LEFTALT, + /* 57 */ KEY_SPACE, + /* 58 */ KEY_CAPSLOCK, + /* 59 */ KEY_F1, + /* 60 */ KEY_F2, + /* 61 */ KEY_F3, + /* 62 */ KEY_F4, + /* 63 */ KEY_F5, + /* 64 */ KEY_F6, + /* 65 */ KEY_F7, + /* 66 */ KEY_F8, + /* 67 */ KEY_F9, + /* 68 */ KEY_F10, + /* 69 */ KEY_NUMLOCK, + /* 70 */ KEY_SCROLLLOCK, + /* 71 */ KEY_KP7, + /* 72 */ KEY_KP8, + /* 73 */ KEY_KP9, + /* 74 */ KEY_KPMINUS, + /* 75 */ KEY_KP4, + /* 76 */ KEY_KP5, + /* 77 */ KEY_KP6, + /* 78 */ KEY_KPPLUS, + /* 79 */ KEY_KP1, + /* 80 */ KEY_KP2, + /* 81 */ KEY_KP3, + /* 82 */ KEY_KP0, + /* 83 */ KEY_KPDOT, + /* 84 */ KEY_RESERVED, + + /* 85 */ KEY_ZENKAKUHANKAKU, + /* 86 */ KEY_102ND, /* backslash on uk, < on german */ + /* 87 */ KEY_F11, + /* 88 */ KEY_F12, + /* 89 */ KEY_RESERVED, + /* 90 */ KEY_RESERVED, + /* 91 */ KEY_RESERVED, + /* 92 */ KEY_RESERVED, + /* 93 */ KEY_RESERVED, + /* 94 */ KEY_RESERVED, + /* 95 */ KEY_RESERVED, + /* 96 */ KEY_RESERVED, + /* 97 */ KEY_RESERVED, + /* 98 */ KEY_RESERVED, + /* 99 */ KEY_RESERVED, + /* 100 */ KEY_RESERVED, + /* 101 */ KEY_RESERVED, + /* 102 */ KEY_RESERVED, + /* 103 */ KEY_RESERVED, + /* 104 */ KEY_RESERVED, + /* 105 */ KEY_RESERVED, + /* 106 */ KEY_RESERVED, + /* 107 */ KEY_RESERVED, + /* 108 */ KEY_RESERVED, + /* 109 */ KEY_RESERVED, + /* 110 */ KEY_RESERVED, + /* 111 */ KEY_BRIGHTNESSUP, + /* 112 */ KEY_BRIGHTNESSDOWN, + /* 113 */ KEY_RESERVED, + /* 114 */ KEY_RESERVED, + /* 115 */ KEY_RESERVED, + /* 116 */ KEY_RESERVED, + /* 117 */ KEY_RESERVED, + /* 118 */ KEY_RESERVED, + /* 119 */ KEY_RESERVED, + /* 120 */ KEY_RESERVED, + /* 121 */ KEY_RESERVED, + /* 122 */ KEY_RESERVED, + /* 123 */ KEY_RESERVED, + /* 124 */ KEY_RESERVED, + /* 125 */ KEY_RESERVED, + /* 126 */ KEY_RESERVED, + /* 127 */ KEY_PAUSE, + /* 128 */ KEY_RESERVED, + /* 129 */ KEY_RESERVED, + /* 130 */ KEY_RESERVED, + /* 131 */ KEY_RESERVED, + /* 132 */ KEY_RESERVED, + /* 133 */ KEY_RESERVED, + /* 134 */ KEY_RESERVED, + /* 135 */ KEY_RESERVED, + /* 136 */ KEY_RESERVED, + /* 137 */ KEY_RESERVED, + /* 138 */ KEY_RESERVED, + /* 139 */ KEY_RESERVED, + /* 140 */ KEY_RESERVED, + /* 141 */ KEY_RESERVED, + /* 142 */ KEY_RESERVED, + /* 143 */ KEY_RESERVED, + /* 144 */ KEY_PREVIOUSSONG, + /* 145 */ KEY_RESERVED, + /* 146 */ KEY_RESERVED, + /* 147 */ KEY_RESERVED, + /* 148 */ KEY_RESERVED, + /* 149 */ KEY_RESERVED, + /* 150 */ KEY_RESERVED, + /* 151 */ KEY_RESERVED, + /* 152 */ KEY_RESERVED, + /* 153 */ KEY_NEXTSONG, + /* 154 */ KEY_RESERVED, + /* 155 */ KEY_RESERVED, + /* 156 */ KEY_KPENTER, + /* 157 */ KEY_RIGHTCTRL, + /* 158 */ KEY_RESERVED, + /* 159 */ KEY_RESERVED, + /* 160 */ KEY_MUTE, + /* 161 */ KEY_RESERVED, + /* 162 */ KEY_PLAYPAUSE, + /* 163 */ KEY_RESERVED, + /* 164 */ KEY_RESERVED, + /* 165 */ KEY_RESERVED, + /* 166 */ KEY_RESERVED, + /* 167 */ KEY_RESERVED, + /* 168 */ KEY_RESERVED, + /* 169 */ KEY_RESERVED, + /* 170 */ KEY_PRINT, + /* 171 */ KEY_RESERVED, + /* 172 */ KEY_RESERVED, + /* 173 */ KEY_RESERVED, + /* 174 */ KEY_VOLUMEDOWN, + /* 175 */ KEY_RESERVED, + /* 176 */ KEY_VOLUMEUP, + /* 177 */ KEY_RESERVED, + /* 178 */ KEY_RESERVED, + /* 179 */ KEY_RESERVED, + /* 180 */ KEY_RESERVED, + /* 181 */ KEY_KPSLASH, + /* 182 */ KEY_RESERVED, + /* 183 */ KEY_PRINT, + /* 184 */ KEY_RIGHTALT, + /* 185 */ KEY_RESERVED, + /* 186 */ KEY_RESERVED, + /* 187 */ KEY_RESERVED, + /* 188 */ KEY_RESERVED, + /* 189 */ KEY_RESERVED, + /* 190 */ KEY_RESERVED, + /* 191 */ KEY_RESERVED, + /* 192 */ KEY_RESERVED, + /* 193 */ KEY_RESERVED, + /* 194 */ KEY_RESERVED, + /* 195 */ KEY_RESERVED, + /* 196 */ KEY_RESERVED, + /* 197 */ KEY_RESERVED, + /* 198 */ KEY_RESERVED, + /* 199 */ KEY_HOME, + /* 200 */ KEY_UP, + /* 201 */ KEY_PAGEUP, + /* 202 */ KEY_RESERVED, + /* 203 */ KEY_LEFT, + /* 204 */ KEY_RESERVED, + /* 205 */ KEY_RIGHT, + /* 206 */ KEY_RESERVED, + /* 207 */ KEY_END, + /* 208 */ KEY_DOWN, + /* 209 */ KEY_PAGEDOWN, + /* 210 */ KEY_INSERT, + /* 211 */ KEY_DELETE, + /* 212 */ KEY_RESERVED, + /* 213 */ KEY_RESERVED, + /* 214 */ KEY_RESERVED, + /* 215 */ KEY_RESERVED, + /* 216 */ KEY_RESERVED, + /* 217 */ KEY_RESERVED, + /* 218 */ KEY_RESERVED, + /* 219 */ KEY_LEFTMETA, + /* 220 */ KEY_RIGHTMETA, + /* 221 */ KEY_MENU, + /* 222 */ KEY_RESERVED, + /* 223 */ KEY_RESERVED, + /* 224 */ KEY_RESERVED, + /* 225 */ KEY_RESERVED, + /* 226 */ KEY_RESERVED, + /* 227 */ KEY_RESERVED, + /* 228 */ KEY_RESERVED, + /* 229 */ KEY_RESERVED, + /* 230 */ KEY_RESERVED, + /* 231 */ KEY_RESERVED, + /* 232 */ KEY_RESERVED, + /* 233 */ KEY_RESERVED, + /* 234 */ KEY_RESERVED, + /* 235 */ KEY_RESERVED, + /* 236 */ KEY_RESERVED, + /* 237 */ KEY_SETUP, +}; +#define WS_XT_MAP_SIZE (sizeof(wsXtMap)/sizeof(*wsXtMap)) + +static +struct TransMapRec wsXt = { + 0, + WS_XT_MAP_SIZE, + wsXtMap +}; + +static void +printWsType(struct libinput *libinput, const char *name, const char *type) +{ + log_info(libinput, "%s: Keyboard type: %s\n", name, type); +} + +int +wscons_keyboard_init(struct wscons_device *device) +{ + struct libinput_device *libinput_device = &device->base; + struct libinput *libinput = libinput_device->seat->libinput; + int fd = libinput_device->fd; + int type; + + if (ioctl(fd, WSKBDIO_GTYPE, &type) == -1) { + log_error(libinput, "getting WSKBD type: %s.\n", + strerror(errno)); + return -1; + } + switch (type) { + case WSKBD_TYPE_PC_XT: + printWsType(libinput, libinput_device->devname, "XT"); + device->scanCodeMap = &wsXt; + break; + case WSKBD_TYPE_PC_AT: + printWsType(libinput, libinput_device->devname, "AT"); + device->scanCodeMap = &wsXt; + break; + case WSKBD_TYPE_USB: + printWsType(libinput, libinput_device->devname, "USB"); + device->scanCodeMap = &wsUsb; + break; + default: + log_error(libinput, "Unsupported wskbd type %d\n", type); + device->scanCodeMap = NULL; + break; + } + return 0; +} + +uint32_t +wskey_transcode(struct TransMapRec *map, int wskey) +{ + if (map == NULL) + return KEY_UNKNOWN; + if (wskey < map->begin || wskey >= map->end) + return KEY_UNKNOWN; + return map->map[wskey]; +}