mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-30 22:20:07 +01:00
Merge branch 'master' into udev
This commit is contained in:
commit
97a277a9f0
19 changed files with 3180 additions and 0 deletions
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
*.o
|
||||
*.pc
|
||||
*.la
|
||||
*.lo
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
config.guess
|
||||
config.h
|
||||
config.h.in
|
||||
config.log
|
||||
config.status
|
||||
config.sub
|
||||
configure
|
||||
depcomp
|
||||
install-sh
|
||||
libtool
|
||||
ltmain.sh
|
||||
missing
|
||||
stamp-h1
|
||||
src/.libs/
|
||||
src/.deps/
|
||||
src/Makefile
|
||||
src/Makefile.in
|
||||
src/libinput-version.h
|
||||
3
Makefile.am
Normal file
3
Makefile.am
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
SUBDIRS = src
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
||||
9
README
Normal file
9
README
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
This library does processing on input device events while providing an API
|
||||
to the the user used for delegating more useful input events.
|
||||
|
||||
Input event processing includes scaling touch coordinates, generating
|
||||
pointer events from touchpads, pointer acceleration, etc.
|
||||
|
||||
It is based on the input code from the weston Wayland reference compositor.
|
||||
|
||||
It has no other dependencies than libmtdev and supports only evdev devices.
|
||||
9
autogen.sh
Executable file
9
autogen.sh
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
test -n "$srcdir" || srcdir=`dirname "$0"`
|
||||
test -n "$srcdir" || srcdir=.
|
||||
(
|
||||
cd "$srcdir" &&
|
||||
autoreconf --force -v --install
|
||||
) || exit
|
||||
test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
|
||||
56
configure.ac
Normal file
56
configure.ac
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
AC_PREREQ([2.64])
|
||||
|
||||
m4_define([libinput_major_version], [0])
|
||||
m4_define([libinput_minor_version], [0])
|
||||
m4_define([libinput_micro_version], [90])
|
||||
m4_define([libinput_version],
|
||||
[libinput_major_version.libinput_minor_version.libinput_micro_version])
|
||||
|
||||
AC_INIT([libinput],
|
||||
[libinput_version],
|
||||
[http://nobugtracker],
|
||||
[libinput],
|
||||
[http://nohomepage])
|
||||
|
||||
AC_SUBST([LIBINPUT_VERSION_MAJOR], [libinput_major_version])
|
||||
AC_SUBST([LIBINPUT_VERSION_MINOR], [libinput_minor_version])
|
||||
AC_SUBST([LIBINPUT_VERSION_MICRO], [libinput_micro_version])
|
||||
AC_SUBST([LIBINPUT_VERSION], [libinput_version])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
|
||||
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
# Check for programs
|
||||
AC_PROG_CC
|
||||
|
||||
# Initialize libtool
|
||||
LT_PREREQ([2.2])
|
||||
LT_INIT
|
||||
|
||||
AC_CHECK_DECL(EPOLL_CLOEXEC, [],
|
||||
[AC_MSG_ERROR("EPOLL_CLOEXEC is needed to compile libinput")],
|
||||
[[#include <sys/epoll.h>]])
|
||||
AC_CHECK_DECL(TFD_CLOEXEC,[],
|
||||
[AC_MSG_ERROR("TFD_CLOEXEC is needed to compile libinput")],
|
||||
[[#include <sys/timerfd.h>]])
|
||||
AC_CHECK_DECL(CLOCK_MONOTONIC,[],
|
||||
[AC_MSG_ERROR("CLOCK_MONOTONIC is needed to compile libinput")],
|
||||
[[#include <time.h>]])
|
||||
|
||||
PKG_PROG_PKG_CONFIG()
|
||||
PKG_CHECK_MODULES(MTDEV, [mtdev >= 1.1.0])
|
||||
|
||||
if test "x$GCC" = "xyes"; then
|
||||
GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
|
||||
fi
|
||||
AC_SUBST(GCC_CFLAGS)
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
src/Makefile
|
||||
src/libinput.pc
|
||||
src/libinput-version.h])
|
||||
AC_OUTPUT
|
||||
5
m4/.gitignore
vendored
Normal file
5
m4/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
libtool.m4
|
||||
ltoptions.m4
|
||||
ltsugar.m4
|
||||
ltversion.m4
|
||||
lt~obsolete.m4
|
||||
28
src/Makefile.am
Normal file
28
src/Makefile.am
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
lib_LTLIBRARIES = libinput.la
|
||||
|
||||
include_HEADERS = \
|
||||
libinput.h
|
||||
|
||||
libinput_la_SOURCES = \
|
||||
libinput.c \
|
||||
libinput.h \
|
||||
libinput-util.c \
|
||||
libinput-util.h \
|
||||
evdev.c \
|
||||
evdev.h \
|
||||
evdev-touchpad.c \
|
||||
filter.c \
|
||||
filter.h
|
||||
|
||||
libinput_la_LIBADD = $(MTDEV_LIBS)
|
||||
libinput_la_CFLAGS = $(MTDEV_CFLAGS) \
|
||||
$(GCC_CFLAGS)
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libinput.pc
|
||||
|
||||
AM_CPPFLAGS = $(FFI_CFLAGS)
|
||||
AM_CFLAGS = $(GCC_CFLAGS)
|
||||
|
||||
DISTCLEANFILES = libinput-version.h
|
||||
EXTRA_DIST = libinput-version.h.in
|
||||
833
src/evdev-touchpad.c
Normal file
833
src/evdev-touchpad.c
Normal file
|
|
@ -0,0 +1,833 @@
|
|||
/*
|
||||
* Copyright © 2012 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/input.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#include "evdev.h"
|
||||
#include "filter.h"
|
||||
#include "libinput-private.h"
|
||||
|
||||
/* Default values */
|
||||
#define DEFAULT_CONSTANT_ACCEL_NUMERATOR 50
|
||||
#define DEFAULT_MIN_ACCEL_FACTOR 0.16
|
||||
#define DEFAULT_MAX_ACCEL_FACTOR 1.0
|
||||
#define DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR 700.0
|
||||
|
||||
#define DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON BTN_LEFT
|
||||
#define DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT 100
|
||||
|
||||
enum touchpad_model {
|
||||
TOUCHPAD_MODEL_UNKNOWN = 0,
|
||||
TOUCHPAD_MODEL_SYNAPTICS,
|
||||
TOUCHPAD_MODEL_ALPS,
|
||||
TOUCHPAD_MODEL_APPLETOUCH,
|
||||
TOUCHPAD_MODEL_ELANTECH
|
||||
};
|
||||
|
||||
enum touchpad_event {
|
||||
TOUCHPAD_EVENT_NONE = 0,
|
||||
TOUCHPAD_EVENT_ABSOLUTE_ANY = (1 << 0),
|
||||
TOUCHPAD_EVENT_ABSOLUTE_X = (1 << 1),
|
||||
TOUCHPAD_EVENT_ABSOLUTE_Y = (1 << 2),
|
||||
TOUCHPAD_EVENT_REPORT = (1 << 3)
|
||||
};
|
||||
|
||||
struct touchpad_model_spec {
|
||||
short vendor;
|
||||
short product;
|
||||
enum touchpad_model model;
|
||||
};
|
||||
|
||||
static struct touchpad_model_spec touchpad_spec_table[] = {
|
||||
{0x0002, 0x0007, TOUCHPAD_MODEL_SYNAPTICS},
|
||||
{0x0002, 0x0008, TOUCHPAD_MODEL_ALPS},
|
||||
{0x05ac, 0x0000, TOUCHPAD_MODEL_APPLETOUCH},
|
||||
{0x0002, 0x000e, TOUCHPAD_MODEL_ELANTECH},
|
||||
{0x0000, 0x0000, TOUCHPAD_MODEL_UNKNOWN}
|
||||
};
|
||||
|
||||
enum touchpad_state {
|
||||
TOUCHPAD_STATE_NONE = 0,
|
||||
TOUCHPAD_STATE_TOUCH = (1 << 0),
|
||||
TOUCHPAD_STATE_MOVE = (1 << 1)
|
||||
};
|
||||
|
||||
#define TOUCHPAD_HISTORY_LENGTH 4
|
||||
|
||||
struct touchpad_motion {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
};
|
||||
|
||||
enum touchpad_fingers_state {
|
||||
TOUCHPAD_FINGERS_ONE = (1 << 0),
|
||||
TOUCHPAD_FINGERS_TWO = (1 << 1),
|
||||
TOUCHPAD_FINGERS_THREE = (1 << 2)
|
||||
};
|
||||
|
||||
enum fsm_event {
|
||||
FSM_EVENT_TOUCH,
|
||||
FSM_EVENT_RELEASE,
|
||||
FSM_EVENT_MOTION,
|
||||
FSM_EVENT_TIMEOUT
|
||||
};
|
||||
|
||||
enum fsm_state {
|
||||
FSM_IDLE,
|
||||
FSM_TOUCH,
|
||||
FSM_TAP,
|
||||
FSM_TAP_2,
|
||||
FSM_DRAG
|
||||
};
|
||||
|
||||
struct touchpad_dispatch {
|
||||
struct evdev_dispatch base;
|
||||
struct evdev_device *device;
|
||||
|
||||
enum touchpad_model model;
|
||||
unsigned int state;
|
||||
int finger_state;
|
||||
int last_finger_state;
|
||||
|
||||
double constant_accel_factor;
|
||||
double min_accel_factor;
|
||||
double max_accel_factor;
|
||||
|
||||
unsigned int event_mask;
|
||||
unsigned int event_mask_filter;
|
||||
|
||||
int reset;
|
||||
|
||||
struct {
|
||||
bool enable;
|
||||
|
||||
|
||||
enum fsm_event *events;
|
||||
size_t events_len;
|
||||
size_t events_count;
|
||||
enum fsm_state state;
|
||||
struct {
|
||||
int fd;
|
||||
struct libinput_source *source;
|
||||
} timer;
|
||||
} fsm;
|
||||
|
||||
struct {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} hw_abs;
|
||||
|
||||
int has_pressure;
|
||||
struct {
|
||||
int32_t touch_low;
|
||||
int32_t touch_high;
|
||||
} pressure;
|
||||
|
||||
struct {
|
||||
int32_t margin_x;
|
||||
int32_t margin_y;
|
||||
int32_t center_x;
|
||||
int32_t center_y;
|
||||
} hysteresis;
|
||||
|
||||
struct touchpad_motion motion_history[TOUCHPAD_HISTORY_LENGTH];
|
||||
int motion_index;
|
||||
unsigned int motion_count;
|
||||
|
||||
struct motion_filter *filter;
|
||||
};
|
||||
|
||||
static enum touchpad_model
|
||||
get_touchpad_model(struct evdev_device *device)
|
||||
{
|
||||
struct input_id id;
|
||||
unsigned int i;
|
||||
|
||||
if (ioctl(device->fd, EVIOCGID, &id) < 0)
|
||||
return TOUCHPAD_MODEL_UNKNOWN;
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(touchpad_spec_table); i++)
|
||||
if (touchpad_spec_table[i].vendor == id.vendor &&
|
||||
(!touchpad_spec_table[i].product ||
|
||||
touchpad_spec_table[i].product == id.product))
|
||||
return touchpad_spec_table[i].model;
|
||||
|
||||
return TOUCHPAD_MODEL_UNKNOWN;
|
||||
}
|
||||
|
||||
static void
|
||||
configure_touchpad_pressure(struct touchpad_dispatch *touchpad,
|
||||
int32_t pressure_min, int32_t pressure_max)
|
||||
{
|
||||
int32_t range = pressure_max - pressure_min + 1;
|
||||
|
||||
touchpad->has_pressure = 1;
|
||||
|
||||
/* Magic numbers from xf86-input-synaptics */
|
||||
switch (touchpad->model) {
|
||||
case TOUCHPAD_MODEL_ELANTECH:
|
||||
touchpad->pressure.touch_low = pressure_min + 1;
|
||||
touchpad->pressure.touch_high = pressure_min + 1;
|
||||
break;
|
||||
default:
|
||||
touchpad->pressure.touch_low =
|
||||
pressure_min + range * (25.0/256.0);
|
||||
touchpad->pressure.touch_high =
|
||||
pressure_min + range * (30.0/256.0);
|
||||
}
|
||||
}
|
||||
|
||||
static double
|
||||
touchpad_profile(struct motion_filter *filter,
|
||||
void *data,
|
||||
double velocity,
|
||||
uint32_t time)
|
||||
{
|
||||
struct touchpad_dispatch *touchpad =
|
||||
(struct touchpad_dispatch *) data;
|
||||
|
||||
double accel_factor;
|
||||
|
||||
accel_factor = velocity * touchpad->constant_accel_factor;
|
||||
|
||||
if (accel_factor > touchpad->max_accel_factor)
|
||||
accel_factor = touchpad->max_accel_factor;
|
||||
else if (accel_factor < touchpad->min_accel_factor)
|
||||
accel_factor = touchpad->min_accel_factor;
|
||||
|
||||
return accel_factor;
|
||||
}
|
||||
|
||||
static inline struct touchpad_motion *
|
||||
motion_history_offset(struct touchpad_dispatch *touchpad, int offset)
|
||||
{
|
||||
int offset_index =
|
||||
(touchpad->motion_index - offset + TOUCHPAD_HISTORY_LENGTH) %
|
||||
TOUCHPAD_HISTORY_LENGTH;
|
||||
|
||||
return &touchpad->motion_history[offset_index];
|
||||
}
|
||||
|
||||
static double
|
||||
estimate_delta(int x0, int x1, int x2, int x3)
|
||||
{
|
||||
return (x0 + x1 - x2 - x3) / 4;
|
||||
}
|
||||
|
||||
static int
|
||||
hysteresis(int in, int center, int margin)
|
||||
{
|
||||
int diff = in - center;
|
||||
if (abs(diff) <= margin)
|
||||
return center;
|
||||
|
||||
if (diff > margin)
|
||||
return center + diff - margin;
|
||||
else if (diff < -margin)
|
||||
return center + diff + margin;
|
||||
return center + diff;
|
||||
}
|
||||
|
||||
static void
|
||||
touchpad_get_delta(struct touchpad_dispatch *touchpad, double *dx, double *dy)
|
||||
{
|
||||
*dx = estimate_delta(motion_history_offset(touchpad, 0)->x,
|
||||
motion_history_offset(touchpad, 1)->x,
|
||||
motion_history_offset(touchpad, 2)->x,
|
||||
motion_history_offset(touchpad, 3)->x);
|
||||
*dy = estimate_delta(motion_history_offset(touchpad, 0)->y,
|
||||
motion_history_offset(touchpad, 1)->y,
|
||||
motion_history_offset(touchpad, 2)->y,
|
||||
motion_history_offset(touchpad, 3)->y);
|
||||
}
|
||||
|
||||
static void
|
||||
filter_motion(struct touchpad_dispatch *touchpad,
|
||||
double *dx, double *dy, uint32_t time)
|
||||
{
|
||||
struct motion_params motion;
|
||||
|
||||
motion.dx = *dx;
|
||||
motion.dy = *dy;
|
||||
|
||||
filter_dispatch(touchpad->filter, &motion, touchpad, time);
|
||||
|
||||
*dx = motion.dx;
|
||||
*dy = motion.dy;
|
||||
}
|
||||
|
||||
static void
|
||||
notify_button_pressed(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||
{
|
||||
pointer_notify_button(
|
||||
&touchpad->device->base,
|
||||
time,
|
||||
DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
|
||||
LIBINPUT_POINTER_BUTTON_STATE_PRESSED);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_button_released(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||
{
|
||||
pointer_notify_button(
|
||||
&touchpad->device->base,
|
||||
time,
|
||||
DEFAULT_TOUCHPAD_SINGLE_TAP_BUTTON,
|
||||
LIBINPUT_POINTER_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
|
||||
static void
|
||||
notify_tap(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||
{
|
||||
notify_button_pressed(touchpad, time);
|
||||
notify_button_released(touchpad, time);
|
||||
}
|
||||
|
||||
static void
|
||||
process_fsm_events(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||
{
|
||||
uint32_t timeout = UINT32_MAX;
|
||||
enum fsm_event event;
|
||||
unsigned int i;
|
||||
|
||||
if (!touchpad->fsm.enable)
|
||||
return;
|
||||
|
||||
if (touchpad->fsm.events_count == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < touchpad->fsm.events_count; ++i) {
|
||||
event = touchpad->fsm.events[i];
|
||||
timeout = 0;
|
||||
|
||||
switch (touchpad->fsm.state) {
|
||||
case FSM_IDLE:
|
||||
switch (event) {
|
||||
case FSM_EVENT_TOUCH:
|
||||
touchpad->fsm.state = FSM_TOUCH;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FSM_TOUCH:
|
||||
switch (event) {
|
||||
case FSM_EVENT_RELEASE:
|
||||
timeout = DEFAULT_TOUCHPAD_SINGLE_TAP_TIMEOUT;
|
||||
touchpad->fsm.state = FSM_TAP;
|
||||
break;
|
||||
default:
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FSM_TAP:
|
||||
switch (event) {
|
||||
case FSM_EVENT_TIMEOUT:
|
||||
notify_tap(touchpad, time);
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
break;
|
||||
case FSM_EVENT_TOUCH:
|
||||
notify_button_pressed(touchpad, time);
|
||||
touchpad->fsm.state = FSM_TAP_2;
|
||||
break;
|
||||
default:
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FSM_TAP_2:
|
||||
switch (event) {
|
||||
case FSM_EVENT_MOTION:
|
||||
touchpad->fsm.state = FSM_DRAG;
|
||||
break;
|
||||
case FSM_EVENT_RELEASE:
|
||||
notify_button_released(touchpad, time);
|
||||
notify_tap(touchpad, time);
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
break;
|
||||
default:
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FSM_DRAG:
|
||||
switch (event) {
|
||||
case FSM_EVENT_RELEASE:
|
||||
notify_button_released(touchpad, time);
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
break;
|
||||
default:
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout != UINT32_MAX) {
|
||||
struct itimerspec its;
|
||||
|
||||
its.it_interval.tv_sec = 0;
|
||||
its.it_interval.tv_nsec = 0;
|
||||
its.it_value.tv_sec = timeout / 1000;
|
||||
its.it_value.tv_nsec = (timeout % 1000) * 1000 * 1000;
|
||||
timerfd_settime(touchpad->fsm.timer.fd, 0, &its, NULL);
|
||||
}
|
||||
|
||||
touchpad->fsm.events_count = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
push_fsm_event(struct touchpad_dispatch *touchpad,
|
||||
enum fsm_event event)
|
||||
{
|
||||
enum fsm_event *events;
|
||||
size_t new_len = touchpad->fsm.events_len;
|
||||
|
||||
if (!touchpad->fsm.enable)
|
||||
return;
|
||||
|
||||
if (touchpad->fsm.events_count + 1 >= touchpad->fsm.events_len) {
|
||||
if (new_len == 0)
|
||||
new_len = 4;
|
||||
else
|
||||
new_len *= 2;
|
||||
events = realloc(touchpad->fsm.events,
|
||||
sizeof(enum fsm_event) * new_len);
|
||||
if (!events) {
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
touchpad->fsm.events = events;
|
||||
touchpad->fsm.events_len = new_len;
|
||||
}
|
||||
|
||||
touchpad->fsm.events[touchpad->fsm.events_count++] = event;
|
||||
}
|
||||
|
||||
static void
|
||||
fsm_timeout_handler(void *data)
|
||||
{
|
||||
struct touchpad_dispatch *touchpad = data;
|
||||
uint64_t expires;
|
||||
int len;
|
||||
struct timespec ts;
|
||||
uint32_t now;
|
||||
|
||||
len = read(touchpad->fsm.timer.fd, &expires, sizeof expires);
|
||||
if (len != sizeof expires)
|
||||
/* This will only happen if the application made the fd
|
||||
* non-blocking, but this function should only be called
|
||||
* upon the timeout, so lets continue anyway. */
|
||||
fprintf(stderr, "timerfd read error: %m\n");
|
||||
|
||||
if (touchpad->fsm.events_count == 0) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
now = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||
|
||||
push_fsm_event(touchpad, FSM_EVENT_TIMEOUT);
|
||||
process_fsm_events(touchpad, now);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
touchpad_update_state(struct touchpad_dispatch *touchpad, uint32_t time)
|
||||
{
|
||||
int motion_index;
|
||||
int center_x, center_y;
|
||||
double dx = 0.0, dy = 0.0;
|
||||
struct libinput_device *base = &touchpad->device->base;
|
||||
|
||||
if (touchpad->reset ||
|
||||
touchpad->last_finger_state != touchpad->finger_state) {
|
||||
touchpad->reset = 0;
|
||||
touchpad->motion_count = 0;
|
||||
touchpad->event_mask = TOUCHPAD_EVENT_NONE;
|
||||
touchpad->event_mask_filter =
|
||||
TOUCHPAD_EVENT_ABSOLUTE_X | TOUCHPAD_EVENT_ABSOLUTE_Y;
|
||||
|
||||
touchpad->last_finger_state = touchpad->finger_state;
|
||||
|
||||
process_fsm_events(touchpad, time);
|
||||
|
||||
return;
|
||||
}
|
||||
touchpad->last_finger_state = touchpad->finger_state;
|
||||
|
||||
if (!(touchpad->event_mask & TOUCHPAD_EVENT_REPORT))
|
||||
return;
|
||||
else
|
||||
touchpad->event_mask &= ~TOUCHPAD_EVENT_REPORT;
|
||||
|
||||
if ((touchpad->event_mask & touchpad->event_mask_filter) !=
|
||||
touchpad->event_mask_filter)
|
||||
return;
|
||||
|
||||
touchpad->event_mask_filter = TOUCHPAD_EVENT_ABSOLUTE_ANY;
|
||||
touchpad->event_mask = 0;
|
||||
|
||||
/* Avoid noice by moving center only when delta reaches a threshold
|
||||
* distance from the old center. */
|
||||
if (touchpad->motion_count > 0) {
|
||||
center_x = hysteresis(touchpad->hw_abs.x,
|
||||
touchpad->hysteresis.center_x,
|
||||
touchpad->hysteresis.margin_x);
|
||||
center_y = hysteresis(touchpad->hw_abs.y,
|
||||
touchpad->hysteresis.center_y,
|
||||
touchpad->hysteresis.margin_y);
|
||||
} else {
|
||||
center_x = touchpad->hw_abs.x;
|
||||
center_y = touchpad->hw_abs.y;
|
||||
}
|
||||
touchpad->hysteresis.center_x = center_x;
|
||||
touchpad->hysteresis.center_y = center_y;
|
||||
touchpad->hw_abs.x = center_x;
|
||||
touchpad->hw_abs.y = center_y;
|
||||
|
||||
/* Update motion history tracker */
|
||||
motion_index = (touchpad->motion_index + 1) % TOUCHPAD_HISTORY_LENGTH;
|
||||
touchpad->motion_index = motion_index;
|
||||
touchpad->motion_history[motion_index].x = touchpad->hw_abs.x;
|
||||
touchpad->motion_history[motion_index].y = touchpad->hw_abs.y;
|
||||
if (touchpad->motion_count < 4)
|
||||
touchpad->motion_count++;
|
||||
|
||||
if (touchpad->motion_count >= 4) {
|
||||
touchpad_get_delta(touchpad, &dx, &dy);
|
||||
|
||||
filter_motion(touchpad, &dx, &dy, time);
|
||||
|
||||
if (touchpad->finger_state == TOUCHPAD_FINGERS_ONE) {
|
||||
pointer_notify_motion(
|
||||
base,
|
||||
time,
|
||||
li_fixed_from_double(dx),
|
||||
li_fixed_from_double(dy));
|
||||
} else if (touchpad->finger_state == TOUCHPAD_FINGERS_TWO) {
|
||||
if (dx != 0.0)
|
||||
pointer_notify_axis(
|
||||
base,
|
||||
time,
|
||||
LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL,
|
||||
li_fixed_from_double(dx));
|
||||
if (dy != 0.0)
|
||||
pointer_notify_axis(
|
||||
base,
|
||||
time,
|
||||
LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL,
|
||||
li_fixed_from_double(dy));
|
||||
}
|
||||
}
|
||||
|
||||
if (!(touchpad->state & TOUCHPAD_STATE_MOVE) &&
|
||||
((int)dx || (int)dy)) {
|
||||
touchpad->state |= TOUCHPAD_STATE_MOVE;
|
||||
push_fsm_event(touchpad, FSM_EVENT_MOTION);
|
||||
}
|
||||
|
||||
process_fsm_events(touchpad, time);
|
||||
}
|
||||
|
||||
static void
|
||||
on_touch(struct touchpad_dispatch *touchpad)
|
||||
{
|
||||
touchpad->state |= TOUCHPAD_STATE_TOUCH;
|
||||
|
||||
push_fsm_event(touchpad, FSM_EVENT_TOUCH);
|
||||
}
|
||||
|
||||
static void
|
||||
on_release(struct touchpad_dispatch *touchpad)
|
||||
{
|
||||
|
||||
touchpad->reset = 1;
|
||||
touchpad->state &= ~(TOUCHPAD_STATE_MOVE | TOUCHPAD_STATE_TOUCH);
|
||||
|
||||
push_fsm_event(touchpad, FSM_EVENT_RELEASE);
|
||||
}
|
||||
|
||||
static inline void
|
||||
process_absolute(struct touchpad_dispatch *touchpad,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e)
|
||||
{
|
||||
switch (e->code) {
|
||||
case ABS_PRESSURE:
|
||||
if (e->value > touchpad->pressure.touch_high &&
|
||||
!(touchpad->state & TOUCHPAD_STATE_TOUCH))
|
||||
on_touch(touchpad);
|
||||
else if (e->value < touchpad->pressure.touch_low &&
|
||||
touchpad->state & TOUCHPAD_STATE_TOUCH)
|
||||
on_release(touchpad);
|
||||
|
||||
break;
|
||||
case ABS_X:
|
||||
if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
|
||||
touchpad->hw_abs.x = e->value;
|
||||
touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
|
||||
touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_X;
|
||||
}
|
||||
break;
|
||||
case ABS_Y:
|
||||
if (touchpad->state & TOUCHPAD_STATE_TOUCH) {
|
||||
touchpad->hw_abs.y = e->value;
|
||||
touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_ANY;
|
||||
touchpad->event_mask |= TOUCHPAD_EVENT_ABSOLUTE_Y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
process_key(struct touchpad_dispatch *touchpad,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint32_t time)
|
||||
{
|
||||
uint32_t code;
|
||||
|
||||
switch (e->code) {
|
||||
case BTN_TOUCH:
|
||||
if (!touchpad->has_pressure) {
|
||||
if (e->value && !(touchpad->state & TOUCHPAD_STATE_TOUCH))
|
||||
on_touch(touchpad);
|
||||
else if (!e->value)
|
||||
on_release(touchpad);
|
||||
}
|
||||
break;
|
||||
case BTN_LEFT:
|
||||
case BTN_RIGHT:
|
||||
case BTN_MIDDLE:
|
||||
case BTN_SIDE:
|
||||
case BTN_EXTRA:
|
||||
case BTN_FORWARD:
|
||||
case BTN_BACK:
|
||||
case BTN_TASK:
|
||||
if (!touchpad->fsm.enable && e->code == BTN_LEFT &&
|
||||
touchpad->finger_state == TOUCHPAD_FINGERS_TWO)
|
||||
code = BTN_RIGHT;
|
||||
else
|
||||
code = e->code;
|
||||
pointer_notify_button(
|
||||
&touchpad->device->base,
|
||||
time,
|
||||
code,
|
||||
e->value ? LIBINPUT_POINTER_BUTTON_STATE_PRESSED :
|
||||
LIBINPUT_POINTER_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case BTN_TOOL_PEN:
|
||||
case BTN_TOOL_RUBBER:
|
||||
case BTN_TOOL_BRUSH:
|
||||
case BTN_TOOL_PENCIL:
|
||||
case BTN_TOOL_AIRBRUSH:
|
||||
case BTN_TOOL_MOUSE:
|
||||
case BTN_TOOL_LENS:
|
||||
touchpad->reset = 1;
|
||||
break;
|
||||
case BTN_TOOL_FINGER:
|
||||
if (e->value)
|
||||
touchpad->finger_state |= TOUCHPAD_FINGERS_ONE;
|
||||
else
|
||||
touchpad->finger_state &= ~TOUCHPAD_FINGERS_ONE;
|
||||
break;
|
||||
case BTN_TOOL_DOUBLETAP:
|
||||
if (e->value)
|
||||
touchpad->finger_state |= TOUCHPAD_FINGERS_TWO;
|
||||
else
|
||||
touchpad->finger_state &= ~TOUCHPAD_FINGERS_TWO;
|
||||
break;
|
||||
case BTN_TOOL_TRIPLETAP:
|
||||
if (e->value)
|
||||
touchpad->finger_state |= TOUCHPAD_FINGERS_THREE;
|
||||
else
|
||||
touchpad->finger_state &= ~TOUCHPAD_FINGERS_THREE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
touchpad_process(struct evdev_dispatch *dispatch,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint32_t time)
|
||||
{
|
||||
struct touchpad_dispatch *touchpad =
|
||||
(struct touchpad_dispatch *) dispatch;
|
||||
|
||||
switch (e->type) {
|
||||
case EV_SYN:
|
||||
if (e->code == SYN_REPORT)
|
||||
touchpad->event_mask |= TOUCHPAD_EVENT_REPORT;
|
||||
break;
|
||||
case EV_ABS:
|
||||
process_absolute(touchpad, device, e);
|
||||
break;
|
||||
case EV_KEY:
|
||||
process_key(touchpad, device, e, time);
|
||||
break;
|
||||
}
|
||||
|
||||
touchpad_update_state(touchpad, time);
|
||||
}
|
||||
|
||||
static void
|
||||
touchpad_destroy(struct evdev_dispatch *dispatch)
|
||||
{
|
||||
struct touchpad_dispatch *touchpad =
|
||||
(struct touchpad_dispatch *) dispatch;
|
||||
struct libinput *libinput = touchpad->device->base.libinput;
|
||||
|
||||
touchpad->filter->interface->destroy(touchpad->filter);
|
||||
libinput_remove_source(libinput, touchpad->fsm.timer.source);
|
||||
free(touchpad->fsm.events);
|
||||
free(dispatch);
|
||||
}
|
||||
|
||||
struct evdev_dispatch_interface touchpad_interface = {
|
||||
touchpad_process,
|
||||
touchpad_destroy
|
||||
};
|
||||
|
||||
static int
|
||||
touchpad_init(struct touchpad_dispatch *touchpad,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
struct motion_filter *accel;
|
||||
|
||||
unsigned long prop_bits[INPUT_PROP_MAX];
|
||||
struct input_absinfo absinfo;
|
||||
unsigned long abs_bits[NBITS(ABS_MAX)];
|
||||
|
||||
bool has_buttonpad;
|
||||
|
||||
double width;
|
||||
double height;
|
||||
double diagonal;
|
||||
|
||||
touchpad->base.interface = &touchpad_interface;
|
||||
touchpad->device = device;
|
||||
|
||||
/* Detect model */
|
||||
touchpad->model = get_touchpad_model(device);
|
||||
|
||||
ioctl(device->fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits);
|
||||
has_buttonpad = TEST_BIT(prop_bits, INPUT_PROP_BUTTONPAD);
|
||||
|
||||
/* Configure pressure */
|
||||
ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
|
||||
if (TEST_BIT(abs_bits, ABS_PRESSURE)) {
|
||||
ioctl(device->fd, EVIOCGABS(ABS_PRESSURE), &absinfo);
|
||||
configure_touchpad_pressure(touchpad,
|
||||
absinfo.minimum,
|
||||
absinfo.maximum);
|
||||
}
|
||||
|
||||
/* Configure acceleration factor */
|
||||
width = abs(device->abs.max_x - device->abs.min_x);
|
||||
height = abs(device->abs.max_y - device->abs.min_y);
|
||||
diagonal = sqrt(width*width + height*height);
|
||||
|
||||
/* Set default parameters */
|
||||
touchpad->constant_accel_factor =
|
||||
DEFAULT_CONSTANT_ACCEL_NUMERATOR / diagonal;
|
||||
touchpad->min_accel_factor = DEFAULT_MIN_ACCEL_FACTOR;
|
||||
touchpad->max_accel_factor = DEFAULT_MAX_ACCEL_FACTOR;
|
||||
|
||||
touchpad->hysteresis.margin_x =
|
||||
diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
|
||||
touchpad->hysteresis.margin_y =
|
||||
diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
|
||||
touchpad->hysteresis.center_x = 0;
|
||||
touchpad->hysteresis.center_y = 0;
|
||||
|
||||
/* Configure acceleration profile */
|
||||
accel = create_pointer_accelator_filter(touchpad_profile);
|
||||
if (accel == NULL)
|
||||
return -1;
|
||||
touchpad->filter = accel;
|
||||
|
||||
/* Setup initial state */
|
||||
touchpad->reset = 1;
|
||||
|
||||
memset(touchpad->motion_history, 0, sizeof touchpad->motion_history);
|
||||
touchpad->motion_index = 0;
|
||||
touchpad->motion_count = 0;
|
||||
|
||||
touchpad->state = TOUCHPAD_STATE_NONE;
|
||||
touchpad->last_finger_state = 0;
|
||||
touchpad->finger_state = 0;
|
||||
|
||||
touchpad->fsm.events = NULL;
|
||||
touchpad->fsm.events_count = 0;
|
||||
touchpad->fsm.events_len = 0;
|
||||
touchpad->fsm.state = FSM_IDLE;
|
||||
|
||||
touchpad->fsm.timer.fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
||||
touchpad->fsm.timer.source =
|
||||
libinput_add_fd(touchpad->device->base.libinput,
|
||||
touchpad->fsm.timer.fd,
|
||||
fsm_timeout_handler,
|
||||
touchpad);
|
||||
|
||||
if (touchpad->fsm.timer.source == NULL) {
|
||||
close(touchpad->fsm.timer.fd);
|
||||
accel->interface->destroy(accel);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Configure */
|
||||
touchpad->fsm.enable = !has_buttonpad;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct evdev_dispatch *
|
||||
evdev_touchpad_create(struct evdev_device *device)
|
||||
{
|
||||
struct touchpad_dispatch *touchpad;
|
||||
|
||||
touchpad = malloc(sizeof *touchpad);
|
||||
if (touchpad == NULL)
|
||||
return NULL;
|
||||
|
||||
if (touchpad_init(touchpad, device) != 0) {
|
||||
free(touchpad);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &touchpad->base;
|
||||
}
|
||||
714
src/evdev.c
Normal file
714
src/evdev.c
Normal file
|
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* Copyright © 2010 Intel Corporation
|
||||
* Copyright © 2013 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <linux/input.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <mtdev.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "libinput.h"
|
||||
#include "evdev.h"
|
||||
#include "libinput-private.h"
|
||||
|
||||
#define DEFAULT_AXIS_STEP_DISTANCE li_fixed_from_int(10)
|
||||
|
||||
void
|
||||
evdev_device_led_update(struct evdev_device *device, enum libinput_led leds)
|
||||
{
|
||||
static const struct {
|
||||
enum libinput_led weston;
|
||||
int evdev;
|
||||
} map[] = {
|
||||
{ LIBINPUT_LED_NUM_LOCK, LED_NUML },
|
||||
{ LIBINPUT_LED_CAPS_LOCK, LED_CAPSL },
|
||||
{ LIBINPUT_LED_SCROLL_LOCK, LED_SCROLLL },
|
||||
};
|
||||
struct input_event ev[ARRAY_LENGTH(map) + 1];
|
||||
unsigned int i;
|
||||
|
||||
if (!device->caps & EVDEV_KEYBOARD)
|
||||
return;
|
||||
|
||||
memset(ev, 0, sizeof(ev));
|
||||
for (i = 0; i < ARRAY_LENGTH(map); i++) {
|
||||
ev[i].type = EV_LED;
|
||||
ev[i].code = map[i].evdev;
|
||||
ev[i].value = !!(leds & map[i].weston);
|
||||
}
|
||||
ev[i].type = EV_SYN;
|
||||
ev[i].code = SYN_REPORT;
|
||||
|
||||
i = write(device->fd, ev, sizeof ev);
|
||||
(void)i; /* no, we really don't care about the return value */
|
||||
}
|
||||
|
||||
static void
|
||||
transform_absolute(struct evdev_device *device, int32_t *x, int32_t *y)
|
||||
{
|
||||
if (!device->abs.apply_calibration) {
|
||||
*x = device->abs.x;
|
||||
*y = device->abs.y;
|
||||
return;
|
||||
} else {
|
||||
*x = device->abs.x * device->abs.calibration[0] +
|
||||
device->abs.y * device->abs.calibration[1] +
|
||||
device->abs.calibration[2];
|
||||
|
||||
*y = device->abs.x * device->abs.calibration[3] +
|
||||
device->abs.y * device->abs.calibration[4] +
|
||||
device->abs.calibration[5];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
evdev_flush_pending_event(struct evdev_device *device, uint32_t time)
|
||||
{
|
||||
int32_t cx, cy;
|
||||
int slot;
|
||||
struct libinput_device *base = &device->base;
|
||||
|
||||
slot = device->mt.slot;
|
||||
|
||||
switch (device->pending_event) {
|
||||
case EVDEV_NONE:
|
||||
return;
|
||||
case EVDEV_RELATIVE_MOTION:
|
||||
pointer_notify_motion(base,
|
||||
time,
|
||||
device->rel.dx,
|
||||
device->rel.dy);
|
||||
device->rel.dx = 0;
|
||||
device->rel.dy = 0;
|
||||
goto handled;
|
||||
case EVDEV_ABSOLUTE_MT_DOWN:
|
||||
touch_notify_touch(base,
|
||||
time,
|
||||
slot,
|
||||
li_fixed_from_int(device->mt.slots[slot].x),
|
||||
li_fixed_from_int(device->mt.slots[slot].y),
|
||||
LIBINPUT_TOUCH_TYPE_DOWN);
|
||||
goto handled;
|
||||
case EVDEV_ABSOLUTE_MT_MOTION:
|
||||
touch_notify_touch(base,
|
||||
time,
|
||||
slot,
|
||||
li_fixed_from_int(device->mt.slots[slot].x),
|
||||
li_fixed_from_int(device->mt.slots[slot].y),
|
||||
LIBINPUT_TOUCH_TYPE_MOTION);
|
||||
goto handled;
|
||||
case EVDEV_ABSOLUTE_MT_UP:
|
||||
touch_notify_touch(base,
|
||||
time,
|
||||
slot,
|
||||
0, 0,
|
||||
LIBINPUT_TOUCH_TYPE_UP);
|
||||
goto handled;
|
||||
case EVDEV_ABSOLUTE_TOUCH_DOWN:
|
||||
transform_absolute(device, &cx, &cy);
|
||||
touch_notify_touch(base,
|
||||
time,
|
||||
slot,
|
||||
li_fixed_from_int(cx),
|
||||
li_fixed_from_int(cy),
|
||||
LIBINPUT_TOUCH_TYPE_DOWN);
|
||||
goto handled;
|
||||
case EVDEV_ABSOLUTE_MOTION:
|
||||
transform_absolute(device, &cx, &cy);
|
||||
if (device->caps & EVDEV_TOUCH) {
|
||||
touch_notify_touch(base,
|
||||
time,
|
||||
slot,
|
||||
li_fixed_from_int(cx),
|
||||
li_fixed_from_int(cy),
|
||||
LIBINPUT_TOUCH_TYPE_DOWN);
|
||||
} else {
|
||||
pointer_notify_motion_absolute(base,
|
||||
time,
|
||||
li_fixed_from_int(cx),
|
||||
li_fixed_from_int(cy));
|
||||
}
|
||||
goto handled;
|
||||
case EVDEV_ABSOLUTE_TOUCH_UP:
|
||||
touch_notify_touch(base,
|
||||
time,
|
||||
0, 0, 0, LIBINPUT_TOUCH_TYPE_UP);
|
||||
goto handled;
|
||||
}
|
||||
|
||||
assert(0 && "Unknown pending event type");
|
||||
|
||||
handled:
|
||||
device->pending_event = EVDEV_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
evdev_process_touch_button(struct evdev_device *device, int time, int value)
|
||||
{
|
||||
if (device->pending_event != EVDEV_NONE &&
|
||||
device->pending_event != EVDEV_ABSOLUTE_MOTION)
|
||||
evdev_flush_pending_event(device, time);
|
||||
|
||||
device->pending_event = (value ?
|
||||
EVDEV_ABSOLUTE_TOUCH_DOWN :
|
||||
EVDEV_ABSOLUTE_TOUCH_UP);
|
||||
}
|
||||
|
||||
static inline void
|
||||
evdev_process_key(struct evdev_device *device, struct input_event *e, int time)
|
||||
{
|
||||
/* ignore kernel key repeat */
|
||||
if (e->value == 2)
|
||||
return;
|
||||
|
||||
if (e->code == BTN_TOUCH) {
|
||||
if (!device->is_mt)
|
||||
evdev_process_touch_button(device, time, e->value);
|
||||
return;
|
||||
}
|
||||
|
||||
evdev_flush_pending_event(device, time);
|
||||
|
||||
switch (e->code) {
|
||||
case BTN_LEFT:
|
||||
case BTN_RIGHT:
|
||||
case BTN_MIDDLE:
|
||||
case BTN_SIDE:
|
||||
case BTN_EXTRA:
|
||||
case BTN_FORWARD:
|
||||
case BTN_BACK:
|
||||
case BTN_TASK:
|
||||
pointer_notify_button(
|
||||
&device->base,
|
||||
time,
|
||||
e->code,
|
||||
e->value ? LIBINPUT_POINTER_BUTTON_STATE_PRESSED :
|
||||
LIBINPUT_POINTER_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
|
||||
default:
|
||||
keyboard_notify_key(
|
||||
&device->base,
|
||||
time,
|
||||
e->code,
|
||||
e->value ? LIBINPUT_KEYBOARD_KEY_STATE_PRESSED :
|
||||
LIBINPUT_KEYBOARD_KEY_STATE_RELEASED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
evdev_process_touch(struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint32_t time)
|
||||
{
|
||||
struct libinput *libinput = device->base.libinput;
|
||||
int screen_width;
|
||||
int screen_height;
|
||||
|
||||
libinput->interface->get_current_screen_dimensions(
|
||||
&device->base,
|
||||
&screen_width,
|
||||
&screen_height,
|
||||
libinput->user_data);
|
||||
|
||||
switch (e->code) {
|
||||
case ABS_MT_SLOT:
|
||||
evdev_flush_pending_event(device, time);
|
||||
device->mt.slot = e->value;
|
||||
break;
|
||||
case ABS_MT_TRACKING_ID:
|
||||
if (device->pending_event != EVDEV_NONE &&
|
||||
device->pending_event != EVDEV_ABSOLUTE_MT_MOTION)
|
||||
evdev_flush_pending_event(device, time);
|
||||
if (e->value >= 0)
|
||||
device->pending_event = EVDEV_ABSOLUTE_MT_DOWN;
|
||||
else
|
||||
device->pending_event = EVDEV_ABSOLUTE_MT_UP;
|
||||
break;
|
||||
case ABS_MT_POSITION_X:
|
||||
device->mt.slots[device->mt.slot].x =
|
||||
(e->value - device->abs.min_x) * screen_width /
|
||||
(device->abs.max_x - device->abs.min_x);
|
||||
if (device->pending_event == EVDEV_NONE)
|
||||
device->pending_event = EVDEV_ABSOLUTE_MT_MOTION;
|
||||
break;
|
||||
case ABS_MT_POSITION_Y:
|
||||
device->mt.slots[device->mt.slot].y =
|
||||
(e->value - device->abs.min_y) * screen_height /
|
||||
(device->abs.max_y - device->abs.min_y);
|
||||
if (device->pending_event == EVDEV_NONE)
|
||||
device->pending_event = EVDEV_ABSOLUTE_MT_MOTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
evdev_process_absolute_motion(struct evdev_device *device,
|
||||
struct input_event *e)
|
||||
{
|
||||
struct libinput *libinput = device->base.libinput;
|
||||
int screen_width;
|
||||
int screen_height;
|
||||
|
||||
libinput->interface->get_current_screen_dimensions(
|
||||
&device->base,
|
||||
&screen_width,
|
||||
&screen_height,
|
||||
libinput->user_data);
|
||||
|
||||
switch (e->code) {
|
||||
case ABS_X:
|
||||
device->abs.x =
|
||||
(e->value - device->abs.min_x) * screen_width /
|
||||
(device->abs.max_x - device->abs.min_x);
|
||||
if (device->pending_event == EVDEV_NONE)
|
||||
device->pending_event = EVDEV_ABSOLUTE_MOTION;
|
||||
break;
|
||||
case ABS_Y:
|
||||
device->abs.y =
|
||||
(e->value - device->abs.min_y) * screen_height /
|
||||
(device->abs.max_y - device->abs.min_y);
|
||||
if (device->pending_event == EVDEV_NONE)
|
||||
device->pending_event = EVDEV_ABSOLUTE_MOTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
evdev_process_relative(struct evdev_device *device,
|
||||
struct input_event *e, uint32_t time)
|
||||
{
|
||||
struct libinput_device *base = &device->base;
|
||||
|
||||
switch (e->code) {
|
||||
case REL_X:
|
||||
if (device->pending_event != EVDEV_RELATIVE_MOTION)
|
||||
evdev_flush_pending_event(device, time);
|
||||
device->rel.dx += li_fixed_from_int(e->value);
|
||||
device->pending_event = EVDEV_RELATIVE_MOTION;
|
||||
break;
|
||||
case REL_Y:
|
||||
if (device->pending_event != EVDEV_RELATIVE_MOTION)
|
||||
evdev_flush_pending_event(device, time);
|
||||
device->rel.dy += li_fixed_from_int(e->value);
|
||||
device->pending_event = EVDEV_RELATIVE_MOTION;
|
||||
break;
|
||||
case REL_WHEEL:
|
||||
evdev_flush_pending_event(device, time);
|
||||
switch (e->value) {
|
||||
case -1:
|
||||
/* Scroll down */
|
||||
case 1:
|
||||
/* Scroll up */
|
||||
pointer_notify_axis(
|
||||
base,
|
||||
time,
|
||||
LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL,
|
||||
-1 * e->value * DEFAULT_AXIS_STEP_DISTANCE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case REL_HWHEEL:
|
||||
evdev_flush_pending_event(device, time);
|
||||
switch (e->value) {
|
||||
case -1:
|
||||
/* Scroll left */
|
||||
case 1:
|
||||
/* Scroll right */
|
||||
pointer_notify_axis(
|
||||
base,
|
||||
time,
|
||||
LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL,
|
||||
e->value * DEFAULT_AXIS_STEP_DISTANCE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
evdev_process_absolute(struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint32_t time)
|
||||
{
|
||||
if (device->is_mt) {
|
||||
evdev_process_touch(device, e, time);
|
||||
} else {
|
||||
evdev_process_absolute_motion(device, e);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fallback_process(struct evdev_dispatch *dispatch,
|
||||
struct evdev_device *device,
|
||||
struct input_event *event,
|
||||
uint32_t time)
|
||||
{
|
||||
switch (event->type) {
|
||||
case EV_REL:
|
||||
evdev_process_relative(device, event, time);
|
||||
break;
|
||||
case EV_ABS:
|
||||
evdev_process_absolute(device, event, time);
|
||||
break;
|
||||
case EV_KEY:
|
||||
evdev_process_key(device, event, time);
|
||||
break;
|
||||
case EV_SYN:
|
||||
evdev_flush_pending_event(device, time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fallback_destroy(struct evdev_dispatch *dispatch)
|
||||
{
|
||||
free(dispatch);
|
||||
}
|
||||
|
||||
struct evdev_dispatch_interface fallback_interface = {
|
||||
fallback_process,
|
||||
fallback_destroy
|
||||
};
|
||||
|
||||
static struct evdev_dispatch *
|
||||
fallback_dispatch_create(void)
|
||||
{
|
||||
struct evdev_dispatch *dispatch = malloc(sizeof *dispatch);
|
||||
if (dispatch == NULL)
|
||||
return NULL;
|
||||
|
||||
dispatch->interface = &fallback_interface;
|
||||
|
||||
return dispatch;
|
||||
}
|
||||
|
||||
static void
|
||||
evdev_process_events(struct evdev_device *device,
|
||||
struct input_event *ev, int count)
|
||||
{
|
||||
struct evdev_dispatch *dispatch = device->dispatch;
|
||||
struct input_event *e, *end;
|
||||
uint32_t time = 0;
|
||||
|
||||
e = ev;
|
||||
end = e + count;
|
||||
for (e = ev; e < end; e++) {
|
||||
time = e->time.tv_sec * 1000 + e->time.tv_usec / 1000;
|
||||
|
||||
dispatch->interface->process(dispatch, device, e, time);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
evdev_device_dispatch(void *data)
|
||||
{
|
||||
struct evdev_device *device = data;
|
||||
int fd = device->fd;
|
||||
struct input_event ev[32];
|
||||
int len;
|
||||
|
||||
/* If the compositor is repainting, this function is called only once
|
||||
* per frame and we have to process all the events available on the
|
||||
* fd, otherwise there will be input lag. */
|
||||
do {
|
||||
if (device->mtdev)
|
||||
len = mtdev_get(device->mtdev, fd, ev,
|
||||
ARRAY_LENGTH(ev)) *
|
||||
sizeof (struct input_event);
|
||||
else
|
||||
len = read(fd, &ev, sizeof ev);
|
||||
|
||||
if (len < 0 || len % sizeof ev[0] != 0) {
|
||||
if (len < 0 && errno != EAGAIN && errno != EINTR) {
|
||||
libinput_remove_source(device->base.libinput,
|
||||
device->source);
|
||||
device->source = NULL;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
evdev_process_events(device, ev, len / sizeof ev[0]);
|
||||
|
||||
} while (len > 0);
|
||||
}
|
||||
|
||||
static int
|
||||
evdev_handle_device(struct evdev_device *device)
|
||||
{
|
||||
struct input_absinfo absinfo;
|
||||
unsigned long ev_bits[NBITS(EV_MAX)];
|
||||
unsigned long abs_bits[NBITS(ABS_MAX)];
|
||||
unsigned long rel_bits[NBITS(REL_MAX)];
|
||||
unsigned long key_bits[NBITS(KEY_MAX)];
|
||||
int has_key, has_abs;
|
||||
unsigned int i;
|
||||
|
||||
has_key = 0;
|
||||
has_abs = 0;
|
||||
device->caps = 0;
|
||||
|
||||
ioctl(device->fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
|
||||
if (TEST_BIT(ev_bits, EV_ABS)) {
|
||||
has_abs = 1;
|
||||
|
||||
ioctl(device->fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),
|
||||
abs_bits);
|
||||
|
||||
if (TEST_BIT(abs_bits, ABS_WHEEL) ||
|
||||
TEST_BIT(abs_bits, ABS_GAS) ||
|
||||
TEST_BIT(abs_bits, ABS_BRAKE) ||
|
||||
TEST_BIT(abs_bits, ABS_HAT0X)) {
|
||||
/* Device %s is a joystick, ignoring. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (TEST_BIT(abs_bits, ABS_X)) {
|
||||
ioctl(device->fd, EVIOCGABS(ABS_X), &absinfo);
|
||||
device->abs.min_x = absinfo.minimum;
|
||||
device->abs.max_x = absinfo.maximum;
|
||||
device->caps |= EVDEV_MOTION_ABS;
|
||||
}
|
||||
if (TEST_BIT(abs_bits, ABS_Y)) {
|
||||
ioctl(device->fd, EVIOCGABS(ABS_Y), &absinfo);
|
||||
device->abs.min_y = absinfo.minimum;
|
||||
device->abs.max_y = absinfo.maximum;
|
||||
device->caps |= EVDEV_MOTION_ABS;
|
||||
}
|
||||
/* We only handle the slotted Protocol B in weston.
|
||||
Devices with ABS_MT_POSITION_* but not ABS_MT_SLOT
|
||||
require mtdev for conversion. */
|
||||
if (TEST_BIT(abs_bits, ABS_MT_POSITION_X) &&
|
||||
TEST_BIT(abs_bits, ABS_MT_POSITION_Y)) {
|
||||
ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_X),
|
||||
&absinfo);
|
||||
device->abs.min_x = absinfo.minimum;
|
||||
device->abs.max_x = absinfo.maximum;
|
||||
ioctl(device->fd, EVIOCGABS(ABS_MT_POSITION_Y),
|
||||
&absinfo);
|
||||
device->abs.min_y = absinfo.minimum;
|
||||
device->abs.max_y = absinfo.maximum;
|
||||
device->is_mt = 1;
|
||||
device->caps |= EVDEV_TOUCH;
|
||||
|
||||
if (!TEST_BIT(abs_bits, ABS_MT_SLOT)) {
|
||||
device->mtdev = mtdev_new_open(device->fd);
|
||||
if (!device->mtdev) {
|
||||
/* mtdev required but failed to open. */
|
||||
return 0;
|
||||
}
|
||||
device->mt.slot = device->mtdev->caps.slot.value;
|
||||
} else {
|
||||
ioctl(device->fd, EVIOCGABS(ABS_MT_SLOT),
|
||||
&absinfo);
|
||||
device->mt.slot = absinfo.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TEST_BIT(ev_bits, EV_REL)) {
|
||||
ioctl(device->fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)),
|
||||
rel_bits);
|
||||
if (TEST_BIT(rel_bits, REL_X) || TEST_BIT(rel_bits, REL_Y))
|
||||
device->caps |= EVDEV_MOTION_REL;
|
||||
}
|
||||
if (TEST_BIT(ev_bits, EV_KEY)) {
|
||||
has_key = 1;
|
||||
ioctl(device->fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),
|
||||
key_bits);
|
||||
if (TEST_BIT(key_bits, BTN_TOOL_FINGER) &&
|
||||
!TEST_BIT(key_bits, BTN_TOOL_PEN) &&
|
||||
has_abs) {
|
||||
device->dispatch = evdev_touchpad_create(device);
|
||||
}
|
||||
for (i = KEY_ESC; i < KEY_MAX; i++) {
|
||||
if (i >= BTN_MISC && i < KEY_OK)
|
||||
continue;
|
||||
if (TEST_BIT(key_bits, i)) {
|
||||
device->caps |= EVDEV_KEYBOARD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (TEST_BIT(key_bits, BTN_TOUCH)) {
|
||||
device->caps |= EVDEV_TOUCH;
|
||||
}
|
||||
for (i = BTN_MISC; i < BTN_JOYSTICK; i++) {
|
||||
if (TEST_BIT(key_bits, i)) {
|
||||
device->caps |= EVDEV_BUTTON;
|
||||
device->caps &= ~EVDEV_TOUCH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TEST_BIT(ev_bits, EV_LED)) {
|
||||
device->caps |= EVDEV_KEYBOARD;
|
||||
}
|
||||
|
||||
/* This rule tries to catch accelerometer devices and opt out. We may
|
||||
* want to adjust the protocol later adding a proper event for dealing
|
||||
* with accelerometers and implement here accordingly */
|
||||
if (has_abs && !has_key && !device->is_mt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
evdev_configure_device(struct evdev_device *device)
|
||||
{
|
||||
if ((device->caps & (EVDEV_MOTION_ABS | EVDEV_MOTION_REL)) &&
|
||||
(device->caps & EVDEV_BUTTON)) {
|
||||
device_register_capability(&device->base,
|
||||
LIBINPUT_DEVICE_CAP_POINTER);
|
||||
device->seat_caps |= EVDEV_DEVICE_POINTER;
|
||||
}
|
||||
if ((device->caps & EVDEV_KEYBOARD)) {
|
||||
device_register_capability(&device->base,
|
||||
LIBINPUT_DEVICE_CAP_KEYBOARD);
|
||||
device->seat_caps |= EVDEV_DEVICE_KEYBOARD;
|
||||
}
|
||||
if ((device->caps & EVDEV_TOUCH)) {
|
||||
device_register_capability(&device->base,
|
||||
LIBINPUT_DEVICE_CAP_TOUCH);
|
||||
device->seat_caps |= EVDEV_DEVICE_TOUCH;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT struct libinput_device *
|
||||
libinput_device_create_evdev(
|
||||
struct libinput *libinput,
|
||||
const char *devnode,
|
||||
int fd,
|
||||
void *user_data)
|
||||
{
|
||||
struct evdev_device *device;
|
||||
char devname[256] = "unknown";
|
||||
|
||||
device = zalloc(sizeof *device);
|
||||
if (device == NULL)
|
||||
return NULL;
|
||||
|
||||
device->base.libinput = libinput;
|
||||
device->base.user_data = user_data;
|
||||
|
||||
device->seat_caps = 0;
|
||||
device->is_mt = 0;
|
||||
device->mtdev = NULL;
|
||||
device->devnode = strdup(devnode);
|
||||
device->mt.slot = -1;
|
||||
device->rel.dx = 0;
|
||||
device->rel.dy = 0;
|
||||
device->dispatch = NULL;
|
||||
device->fd = fd;
|
||||
device->pending_event = EVDEV_NONE;
|
||||
|
||||
ioctl(device->fd, EVIOCGNAME(sizeof(devname)), devname);
|
||||
devname[sizeof(devname) - 1] = '\0';
|
||||
device->devname = strdup(devname);
|
||||
|
||||
if (!evdev_handle_device(device)) {
|
||||
evdev_device_destroy(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (evdev_configure_device(device) == -1)
|
||||
goto err;
|
||||
|
||||
/* If the dispatch was not set up use the fallback. */
|
||||
if (device->dispatch == NULL)
|
||||
device->dispatch = fallback_dispatch_create();
|
||||
if (device->dispatch == NULL)
|
||||
goto err;
|
||||
|
||||
device->source =
|
||||
libinput_add_fd(libinput, fd, evdev_device_dispatch, device);
|
||||
if (!device->source)
|
||||
goto err;
|
||||
|
||||
return &device->base;
|
||||
|
||||
err:
|
||||
evdev_device_destroy(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
evdev_device_get_keys(struct evdev_device *device, char *keys, size_t size)
|
||||
{
|
||||
memset(keys, 0, size);
|
||||
return ioctl(device->fd, EVIOCGKEY(size), keys);
|
||||
}
|
||||
|
||||
void
|
||||
evdev_device_calibrate(struct evdev_device *device, float calibration[6])
|
||||
{
|
||||
device->abs.apply_calibration = 1;
|
||||
memcpy(device->abs.calibration, calibration, sizeof calibration);
|
||||
}
|
||||
|
||||
void
|
||||
evdev_device_terminate(struct evdev_device *device)
|
||||
{
|
||||
if (device->seat_caps & EVDEV_DEVICE_POINTER) {
|
||||
device_unregister_capability(&device->base,
|
||||
LIBINPUT_DEVICE_CAP_POINTER);
|
||||
}
|
||||
if (device->seat_caps & EVDEV_DEVICE_KEYBOARD) {
|
||||
device_unregister_capability(&device->base,
|
||||
LIBINPUT_DEVICE_CAP_KEYBOARD);
|
||||
}
|
||||
if (device->seat_caps & EVDEV_DEVICE_TOUCH) {
|
||||
device_unregister_capability(&device->base,
|
||||
LIBINPUT_DEVICE_CAP_TOUCH);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
evdev_device_destroy(struct evdev_device *device)
|
||||
{
|
||||
struct evdev_dispatch *dispatch;
|
||||
|
||||
dispatch = device->dispatch;
|
||||
if (dispatch)
|
||||
dispatch->interface->destroy(dispatch);
|
||||
|
||||
if (device->mtdev)
|
||||
mtdev_close_delete(device->mtdev);
|
||||
close(device->fd);
|
||||
free(device->devname);
|
||||
free(device->devnode);
|
||||
free(device);
|
||||
}
|
||||
153
src/evdev.h
Normal file
153
src/evdev.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright © 2011, 2012 Intel Corporation
|
||||
* Copyright © 2013 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef EVDEV_H
|
||||
#define EVDEV_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "evdev.h"
|
||||
#include "libinput-private.h"
|
||||
|
||||
static inline void *
|
||||
zalloc(size_t size)
|
||||
{
|
||||
return calloc(1, size);
|
||||
}
|
||||
|
||||
#define MAX_SLOTS 16
|
||||
|
||||
enum evdev_event_type {
|
||||
EVDEV_NONE,
|
||||
EVDEV_ABSOLUTE_TOUCH_DOWN,
|
||||
EVDEV_ABSOLUTE_MOTION,
|
||||
EVDEV_ABSOLUTE_TOUCH_UP,
|
||||
EVDEV_ABSOLUTE_MT_DOWN,
|
||||
EVDEV_ABSOLUTE_MT_MOTION,
|
||||
EVDEV_ABSOLUTE_MT_UP,
|
||||
EVDEV_RELATIVE_MOTION,
|
||||
};
|
||||
|
||||
enum evdev_device_capability {
|
||||
EVDEV_KEYBOARD = (1 << 0),
|
||||
EVDEV_BUTTON = (1 << 1),
|
||||
EVDEV_MOTION_ABS = (1 << 2),
|
||||
EVDEV_MOTION_REL = (1 << 3),
|
||||
EVDEV_TOUCH = (1 << 4),
|
||||
};
|
||||
|
||||
enum evdev_device_seat_capability {
|
||||
EVDEV_DEVICE_POINTER = (1 << 0),
|
||||
EVDEV_DEVICE_KEYBOARD = (1 << 1),
|
||||
EVDEV_DEVICE_TOUCH = (1 << 2)
|
||||
};
|
||||
|
||||
struct evdev_device {
|
||||
struct libinput_device base;
|
||||
|
||||
struct libinput_source *source;
|
||||
|
||||
struct evdev_dispatch *dispatch;
|
||||
char *devnode;
|
||||
char *devname;
|
||||
int fd;
|
||||
struct {
|
||||
int min_x, max_x, min_y, max_y;
|
||||
int32_t x, y;
|
||||
|
||||
int apply_calibration;
|
||||
float calibration[6];
|
||||
} abs;
|
||||
|
||||
struct {
|
||||
int slot;
|
||||
struct {
|
||||
int32_t x, y;
|
||||
} slots[MAX_SLOTS];
|
||||
} mt;
|
||||
struct mtdev *mtdev;
|
||||
|
||||
struct {
|
||||
li_fixed_t dx, dy;
|
||||
} rel;
|
||||
|
||||
enum evdev_event_type pending_event;
|
||||
enum evdev_device_capability caps;
|
||||
enum evdev_device_seat_capability seat_caps;
|
||||
|
||||
int is_mt;
|
||||
};
|
||||
|
||||
/* copied from udev/extras/input_id/input_id.c */
|
||||
/* we must use this kernel-compatible implementation */
|
||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
|
||||
#define OFF(x) ((x)%BITS_PER_LONG)
|
||||
#define BIT(x) (1UL<<OFF(x))
|
||||
#define LONG(x) ((x)/BITS_PER_LONG)
|
||||
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
||||
/* end copied */
|
||||
|
||||
#define EVDEV_UNHANDLED_DEVICE ((struct evdev_device *) 1)
|
||||
|
||||
struct evdev_dispatch;
|
||||
|
||||
struct evdev_dispatch_interface {
|
||||
/* Process an evdev input event. */
|
||||
void (*process)(struct evdev_dispatch *dispatch,
|
||||
struct evdev_device *device,
|
||||
struct input_event *event,
|
||||
uint32_t time);
|
||||
|
||||
/* Destroy an event dispatch handler and free all its resources. */
|
||||
void (*destroy)(struct evdev_dispatch *dispatch);
|
||||
};
|
||||
|
||||
struct evdev_dispatch {
|
||||
struct evdev_dispatch_interface *interface;
|
||||
};
|
||||
|
||||
struct evdev_dispatch *
|
||||
evdev_touchpad_create(struct evdev_device *device);
|
||||
|
||||
void
|
||||
evdev_device_proces_event(struct libinput_event *event);
|
||||
|
||||
void
|
||||
evdev_device_led_update(struct evdev_device *device, enum libinput_led leds);
|
||||
|
||||
int
|
||||
evdev_device_get_keys(struct evdev_device *device, char *keys, size_t size);
|
||||
|
||||
void
|
||||
evdev_device_calibrate(struct evdev_device *device, float calibration[6]);
|
||||
|
||||
void
|
||||
evdev_device_terminate(struct evdev_device *terminate);
|
||||
|
||||
void
|
||||
evdev_device_destroy(struct evdev_device *device);
|
||||
|
||||
#endif /* EVDEV_H */
|
||||
334
src/filter.c
Normal file
334
src/filter.c
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Copyright © 2012 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "filter.h"
|
||||
|
||||
void
|
||||
filter_dispatch(struct motion_filter *filter,
|
||||
struct motion_params *motion,
|
||||
void *data, uint32_t time)
|
||||
{
|
||||
filter->interface->filter(filter, motion, data, time);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pointer acceleration filter
|
||||
*/
|
||||
|
||||
#define MAX_VELOCITY_DIFF 1.0
|
||||
#define MOTION_TIMEOUT 300 /* (ms) */
|
||||
#define NUM_POINTER_TRACKERS 16
|
||||
|
||||
struct pointer_tracker {
|
||||
double dx;
|
||||
double dy;
|
||||
uint32_t time;
|
||||
int dir;
|
||||
};
|
||||
|
||||
struct pointer_accelerator;
|
||||
struct pointer_accelerator {
|
||||
struct motion_filter base;
|
||||
|
||||
accel_profile_func_t profile;
|
||||
|
||||
double velocity;
|
||||
double last_velocity;
|
||||
int last_dx;
|
||||
int last_dy;
|
||||
|
||||
struct pointer_tracker *trackers;
|
||||
int cur_tracker;
|
||||
};
|
||||
|
||||
enum directions {
|
||||
N = 1 << 0,
|
||||
NE = 1 << 1,
|
||||
E = 1 << 2,
|
||||
SE = 1 << 3,
|
||||
S = 1 << 4,
|
||||
SW = 1 << 5,
|
||||
W = 1 << 6,
|
||||
NW = 1 << 7,
|
||||
UNDEFINED_DIRECTION = 0xff
|
||||
};
|
||||
|
||||
static int
|
||||
get_direction(int dx, int dy)
|
||||
{
|
||||
int dir = UNDEFINED_DIRECTION;
|
||||
int d1, d2;
|
||||
double r;
|
||||
|
||||
if (abs(dx) < 2 && abs(dy) < 2) {
|
||||
if (dx > 0 && dy > 0)
|
||||
dir = S | SE | E;
|
||||
else if (dx > 0 && dy < 0)
|
||||
dir = N | NE | E;
|
||||
else if (dx < 0 && dy > 0)
|
||||
dir = S | SW | W;
|
||||
else if (dx < 0 && dy < 0)
|
||||
dir = N | NW | W;
|
||||
else if (dx > 0)
|
||||
dir = NW | W | SW;
|
||||
else if (dx < 0)
|
||||
dir = NE | E | SE;
|
||||
else if (dy > 0)
|
||||
dir = SE | S | SW;
|
||||
else if (dy < 0)
|
||||
dir = NE | N | NW;
|
||||
}
|
||||
else {
|
||||
/* Calculate r within the interval [0 to 8)
|
||||
*
|
||||
* r = [0 .. 2π] where 0 is North
|
||||
* d_f = r / 2π ([0 .. 1))
|
||||
* d_8 = 8 * d_f
|
||||
*/
|
||||
r = atan2(dy, dx);
|
||||
r = fmod(r + 2.5*M_PI, 2*M_PI);
|
||||
r *= 4*M_1_PI;
|
||||
|
||||
/* Mark one or two close enough octants */
|
||||
d1 = (int)(r + 0.9) % 8;
|
||||
d2 = (int)(r + 0.1) % 8;
|
||||
|
||||
dir = (1 << d1) | (1 << d2);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
static void
|
||||
feed_trackers(struct pointer_accelerator *accel,
|
||||
double dx, double dy,
|
||||
uint32_t time)
|
||||
{
|
||||
int i, current;
|
||||
struct pointer_tracker *trackers = accel->trackers;
|
||||
|
||||
for (i = 0; i < NUM_POINTER_TRACKERS; i++) {
|
||||
trackers[i].dx += dx;
|
||||
trackers[i].dy += dy;
|
||||
}
|
||||
|
||||
current = (accel->cur_tracker + 1) % NUM_POINTER_TRACKERS;
|
||||
accel->cur_tracker = current;
|
||||
|
||||
trackers[current].dx = 0.0;
|
||||
trackers[current].dy = 0.0;
|
||||
trackers[current].time = time;
|
||||
trackers[current].dir = get_direction(dx, dy);
|
||||
}
|
||||
|
||||
static struct pointer_tracker *
|
||||
tracker_by_offset(struct pointer_accelerator *accel, unsigned int offset)
|
||||
{
|
||||
unsigned int index =
|
||||
(accel->cur_tracker + NUM_POINTER_TRACKERS - offset)
|
||||
% NUM_POINTER_TRACKERS;
|
||||
return &accel->trackers[index];
|
||||
}
|
||||
|
||||
static double
|
||||
calculate_tracker_velocity(struct pointer_tracker *tracker, uint32_t time)
|
||||
{
|
||||
int dx;
|
||||
int dy;
|
||||
double distance;
|
||||
|
||||
dx = tracker->dx;
|
||||
dy = tracker->dy;
|
||||
distance = sqrt(dx*dx + dy*dy);
|
||||
return distance / (double)(time - tracker->time);
|
||||
}
|
||||
|
||||
static double
|
||||
calculate_velocity(struct pointer_accelerator *accel, uint32_t time)
|
||||
{
|
||||
struct pointer_tracker *tracker;
|
||||
double velocity;
|
||||
double result = 0.0;
|
||||
double initial_velocity;
|
||||
double velocity_diff;
|
||||
unsigned int offset;
|
||||
|
||||
unsigned int dir = tracker_by_offset(accel, 0)->dir;
|
||||
|
||||
/* Find first velocity */
|
||||
for (offset = 1; offset < NUM_POINTER_TRACKERS; offset++) {
|
||||
tracker = tracker_by_offset(accel, offset);
|
||||
|
||||
if (time <= tracker->time)
|
||||
continue;
|
||||
|
||||
result = initial_velocity =
|
||||
calculate_tracker_velocity(tracker, time);
|
||||
if (initial_velocity > 0.0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find least recent vector within a timelimit, maximum velocity diff
|
||||
* and direction threshold. */
|
||||
for (; offset < NUM_POINTER_TRACKERS; offset++) {
|
||||
tracker = tracker_by_offset(accel, offset);
|
||||
|
||||
/* Stop if too far away in time */
|
||||
if (time - tracker->time > MOTION_TIMEOUT ||
|
||||
tracker->time > time)
|
||||
break;
|
||||
|
||||
/* Stop if direction changed */
|
||||
dir &= tracker->dir;
|
||||
if (dir == 0)
|
||||
break;
|
||||
|
||||
velocity = calculate_tracker_velocity(tracker, time);
|
||||
|
||||
/* Stop if velocity differs too much from initial */
|
||||
velocity_diff = fabs(initial_velocity - velocity);
|
||||
if (velocity_diff > MAX_VELOCITY_DIFF)
|
||||
break;
|
||||
|
||||
result = velocity;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static double
|
||||
acceleration_profile(struct pointer_accelerator *accel,
|
||||
void *data, double velocity, uint32_t time)
|
||||
{
|
||||
return accel->profile(&accel->base, data, velocity, time);
|
||||
}
|
||||
|
||||
static double
|
||||
calculate_acceleration(struct pointer_accelerator *accel,
|
||||
void *data, double velocity, uint32_t time)
|
||||
{
|
||||
double factor;
|
||||
|
||||
/* Use Simpson's rule to calculate the avarage acceleration between
|
||||
* the previous motion and the most recent. */
|
||||
factor = acceleration_profile(accel, data, velocity, time);
|
||||
factor += acceleration_profile(accel, data, accel->last_velocity, time);
|
||||
factor += 4.0 *
|
||||
acceleration_profile(accel, data,
|
||||
(accel->last_velocity + velocity) / 2,
|
||||
time);
|
||||
|
||||
factor = factor / 6.0;
|
||||
|
||||
return factor;
|
||||
}
|
||||
|
||||
static double
|
||||
soften_delta(double last_delta, double delta)
|
||||
{
|
||||
if (delta < -1.0 || delta > 1.0) {
|
||||
if (delta > last_delta)
|
||||
return delta - 0.5;
|
||||
else if (delta < last_delta)
|
||||
return delta + 0.5;
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
static void
|
||||
apply_softening(struct pointer_accelerator *accel,
|
||||
struct motion_params *motion)
|
||||
{
|
||||
motion->dx = soften_delta(accel->last_dx, motion->dx);
|
||||
motion->dy = soften_delta(accel->last_dy, motion->dy);
|
||||
}
|
||||
|
||||
static void
|
||||
accelerator_filter(struct motion_filter *filter,
|
||||
struct motion_params *motion,
|
||||
void *data, uint32_t time)
|
||||
{
|
||||
struct pointer_accelerator *accel =
|
||||
(struct pointer_accelerator *) filter;
|
||||
double velocity;
|
||||
double accel_value;
|
||||
|
||||
feed_trackers(accel, motion->dx, motion->dy, time);
|
||||
velocity = calculate_velocity(accel, time);
|
||||
accel_value = calculate_acceleration(accel, data, velocity, time);
|
||||
|
||||
motion->dx = accel_value * motion->dx;
|
||||
motion->dy = accel_value * motion->dy;
|
||||
|
||||
apply_softening(accel, motion);
|
||||
|
||||
accel->last_dx = motion->dx;
|
||||
accel->last_dy = motion->dy;
|
||||
|
||||
accel->last_velocity = velocity;
|
||||
}
|
||||
|
||||
static void
|
||||
accelerator_destroy(struct motion_filter *filter)
|
||||
{
|
||||
struct pointer_accelerator *accel =
|
||||
(struct pointer_accelerator *) filter;
|
||||
|
||||
free(accel->trackers);
|
||||
free(accel);
|
||||
}
|
||||
|
||||
struct motion_filter_interface accelerator_interface = {
|
||||
accelerator_filter,
|
||||
accelerator_destroy
|
||||
};
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelator_filter(accel_profile_func_t profile)
|
||||
{
|
||||
struct pointer_accelerator *filter;
|
||||
|
||||
filter = malloc(sizeof *filter);
|
||||
if (filter == NULL)
|
||||
return NULL;
|
||||
|
||||
filter->base.interface = &accelerator_interface;
|
||||
|
||||
filter->profile = profile;
|
||||
filter->last_velocity = 0.0;
|
||||
filter->last_dx = 0;
|
||||
filter->last_dy = 0;
|
||||
|
||||
filter->trackers =
|
||||
calloc(NUM_POINTER_TRACKERS, sizeof *filter->trackers);
|
||||
filter->cur_tracker = 0;
|
||||
|
||||
return &filter->base;
|
||||
}
|
||||
62
src/filter.h
Normal file
62
src/filter.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright © 2012 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FILTER_H
|
||||
#define FILTER_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
struct motion_params {
|
||||
double dx, dy;
|
||||
};
|
||||
|
||||
struct motion_filter;
|
||||
|
||||
void
|
||||
filter_dispatch(struct motion_filter *filter,
|
||||
struct motion_params *motion,
|
||||
void *data, uint32_t time);
|
||||
|
||||
|
||||
struct motion_filter_interface {
|
||||
void (*filter)(struct motion_filter *filter,
|
||||
struct motion_params *motion,
|
||||
void *data, uint32_t time);
|
||||
void (*destroy)(struct motion_filter *filter);
|
||||
};
|
||||
|
||||
struct motion_filter {
|
||||
struct motion_filter_interface *interface;
|
||||
};
|
||||
|
||||
struct motion_filter *
|
||||
create_linear_acceleration_filter(double speed);
|
||||
|
||||
typedef double (*accel_profile_func_t)(struct motion_filter *filter,
|
||||
void *data,
|
||||
double velocity,
|
||||
uint32_t time);
|
||||
|
||||
struct motion_filter *
|
||||
create_pointer_accelator_filter(accel_profile_func_t filter);
|
||||
|
||||
#endif /* FILTER_H */
|
||||
113
src/libinput-private.h
Normal file
113
src/libinput-private.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright © 2013 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBINPUT_PRIVATE_H
|
||||
#define LIBINPUT_PRIVATE_H
|
||||
|
||||
#include "libinput.h"
|
||||
#include "libinput-util.h"
|
||||
|
||||
struct libinput {
|
||||
int epoll_fd;
|
||||
struct list source_destroy_list;
|
||||
|
||||
struct libinput_event **events;
|
||||
size_t events_count;
|
||||
size_t events_len;
|
||||
size_t events_in;
|
||||
size_t events_out;
|
||||
|
||||
const struct libinput_interface *interface;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct libinput_device {
|
||||
struct libinput *libinput;
|
||||
void *user_data;
|
||||
int terminated;
|
||||
};
|
||||
|
||||
typedef void (*libinput_source_dispatch_t)(void *data);
|
||||
|
||||
struct libinput_source;
|
||||
|
||||
struct libinput_source *
|
||||
libinput_add_fd(struct libinput *libinput,
|
||||
int fd,
|
||||
libinput_source_dispatch_t dispatch,
|
||||
void *data);
|
||||
|
||||
void
|
||||
libinput_remove_source(struct libinput *libinput,
|
||||
struct libinput_source *source);
|
||||
|
||||
void
|
||||
libinput_post_event(struct libinput *libinput,
|
||||
struct libinput_event *event);
|
||||
|
||||
void
|
||||
device_register_capability(struct libinput_device *device,
|
||||
enum libinput_device_capability capability);
|
||||
|
||||
void
|
||||
device_unregister_capability(struct libinput_device *device,
|
||||
enum libinput_device_capability capability);
|
||||
|
||||
void
|
||||
keyboard_notify_key(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
uint32_t key,
|
||||
enum libinput_keyboard_key_state state);
|
||||
|
||||
void
|
||||
pointer_notify_motion(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
li_fixed_t dx,
|
||||
li_fixed_t dy);
|
||||
|
||||
void
|
||||
pointer_notify_motion_absolute(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
li_fixed_t x,
|
||||
li_fixed_t y);
|
||||
|
||||
void
|
||||
pointer_notify_button(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
int32_t button,
|
||||
enum libinput_pointer_button_state state);
|
||||
|
||||
void
|
||||
pointer_notify_axis(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
enum libinput_pointer_axis axis,
|
||||
li_fixed_t value);
|
||||
|
||||
void
|
||||
touch_notify_touch(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
int32_t slot,
|
||||
li_fixed_t x,
|
||||
li_fixed_t y,
|
||||
enum libinput_touch_type touch_type);
|
||||
|
||||
#endif /* LIBINPUT_PRIVATE_H */
|
||||
62
src/libinput-util.c
Normal file
62
src/libinput-util.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2011 Intel Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This list data structure is verbatim copy from wayland-util.h from the
|
||||
* Wayland project; except that wl_ prefix has been removed.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "libinput-private.h"
|
||||
|
||||
void
|
||||
list_init(struct list *list)
|
||||
{
|
||||
list->prev = list;
|
||||
list->next = list;
|
||||
}
|
||||
|
||||
void
|
||||
list_insert(struct list *list, struct list *elm)
|
||||
{
|
||||
elm->prev = list;
|
||||
elm->next = list->next;
|
||||
list->next = elm;
|
||||
elm->next->prev = elm;
|
||||
}
|
||||
|
||||
void
|
||||
list_remove(struct list *elm)
|
||||
{
|
||||
elm->prev->next = elm->next;
|
||||
elm->next->prev = elm->prev;
|
||||
elm->next = NULL;
|
||||
elm->prev = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
list_empty(const struct list *list)
|
||||
{
|
||||
return list->next == list;
|
||||
}
|
||||
91
src/libinput-util.h
Normal file
91
src/libinput-util.h
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright © 2008 Kristian Høgsberg
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBINPUT_UTIL_H
|
||||
#define LIBINPUT_UTIL_H
|
||||
|
||||
/*
|
||||
* This list data structure is a verbatim copy from wayland-util.h from the
|
||||
* Wayland project; except that wl_ prefix has been removed.
|
||||
*/
|
||||
|
||||
struct list {
|
||||
struct list *prev;
|
||||
struct list *next;
|
||||
};
|
||||
|
||||
void list_init(struct list *list);
|
||||
void list_insert(struct list *list, struct list *elm);
|
||||
void list_remove(struct list *elm);
|
||||
int list_empty(const struct list *list);
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define container_of(ptr, sample, member) \
|
||||
(__typeof__(sample))((char *)(ptr) - \
|
||||
((char *)&(sample)->member - (char *)(sample)))
|
||||
#else
|
||||
#define container_of(ptr, sample, member) \
|
||||
(void *)((char *)(ptr) - \
|
||||
((char *)&(sample)->member - (char *)(sample)))
|
||||
#endif
|
||||
|
||||
#define list_for_each(pos, head, member) \
|
||||
for (pos = 0, pos = container_of((head)->next, pos, member); \
|
||||
&pos->member != (head); \
|
||||
pos = container_of(pos->member.next, pos, member))
|
||||
|
||||
#define list_for_each_safe(pos, tmp, head, member) \
|
||||
for (pos = 0, tmp = 0, \
|
||||
pos = container_of((head)->next, pos, member), \
|
||||
tmp = container_of((pos)->member.next, tmp, member); \
|
||||
&pos->member != (head); \
|
||||
pos = tmp, \
|
||||
tmp = container_of(pos->member.next, tmp, member))
|
||||
|
||||
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
|
||||
|
||||
/*
|
||||
* This fixed point implementation is a verbatim copy from wayland-util.h from
|
||||
* the Wayland project, with the wl_ prefix renamed li_.
|
||||
*/
|
||||
|
||||
static inline li_fixed_t li_fixed_from_int(int i)
|
||||
{
|
||||
return i * 256;
|
||||
}
|
||||
|
||||
static inline li_fixed_t
|
||||
li_fixed_from_double(double d)
|
||||
{
|
||||
union {
|
||||
double d;
|
||||
int64_t i;
|
||||
} u;
|
||||
|
||||
u.d = d + (3LL << (51 - 8));
|
||||
|
||||
return u.i;
|
||||
}
|
||||
|
||||
#define LIBINPUT_EXPORT __attribute__ ((visibility("default")))
|
||||
|
||||
#endif /* LIBINPUT_UTIL_H */
|
||||
31
src/libinput-version.h.in
Normal file
31
src/libinput-version.h.in
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright © 2013 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBINPUT_VERSION_H
|
||||
#define LIBINPUT_VERSION_H
|
||||
|
||||
#define LIBINPUT_VERSION_MAJOR @LIBINPUT_VERSION_MAJOR@
|
||||
#define LIBINPUT_VERSION_MINOR @LIBINPUT_VERSION_MINOR@
|
||||
#define LIBINPUT_VERSION_MICRO @LIBINPUT_VERSION_MICRO@
|
||||
#define LIBINPUT_VERSION "@LIBINPUT_VERSION@"
|
||||
|
||||
#endif
|
||||
444
src/libinput.c
Normal file
444
src/libinput.c
Normal file
|
|
@ -0,0 +1,444 @@
|
|||
/*
|
||||
* Copyright © 2013 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "libinput.h"
|
||||
#include "evdev.h"
|
||||
#include "libinput-private.h"
|
||||
|
||||
struct libinput_source {
|
||||
libinput_source_dispatch_t dispatch;
|
||||
void *user_data;
|
||||
int fd;
|
||||
struct list link;
|
||||
};
|
||||
|
||||
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 = malloc(sizeof *source);
|
||||
if (!source)
|
||||
return NULL;
|
||||
|
||||
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) {
|
||||
close(source->fd);
|
||||
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);
|
||||
close(source->fd);
|
||||
source->fd = -1;
|
||||
list_insert(&libinput->source_destroy_list, &source->link);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT struct libinput *
|
||||
libinput_create(const struct libinput_interface *interface, void *user_data)
|
||||
{
|
||||
struct libinput *libinput;
|
||||
|
||||
libinput = zalloc(sizeof *libinput);
|
||||
if (!libinput)
|
||||
return NULL;
|
||||
|
||||
list_init(&libinput->source_destroy_list);
|
||||
|
||||
libinput->interface = interface;
|
||||
libinput->user_data = user_data;
|
||||
|
||||
libinput->epoll_fd = epoll_create1(EPOLL_CLOEXEC);;
|
||||
if (libinput->epoll_fd < 0)
|
||||
return NULL;
|
||||
|
||||
return libinput;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT void
|
||||
libinput_destroy(struct libinput *libinput)
|
||||
{
|
||||
struct libinput_event *event;
|
||||
|
||||
while ((event = libinput_get_event(libinput)))
|
||||
free(event);
|
||||
free(libinput->events);
|
||||
|
||||
close(libinput->epoll_fd);
|
||||
free(libinput);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_get_fd(struct libinput *libinput)
|
||||
{
|
||||
return libinput->epoll_fd;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_dispatch(struct libinput *libinput)
|
||||
{
|
||||
struct libinput_source *source, *next;
|
||||
struct epoll_event ep[32];
|
||||
int i, count;
|
||||
|
||||
count = epoll_wait(libinput->epoll_fd, ep, ARRAY_LENGTH(ep), 0);
|
||||
if (count < 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
source = ep[i].data.ptr;
|
||||
if (source->fd == -1)
|
||||
continue;
|
||||
|
||||
source->dispatch(source->user_data);
|
||||
}
|
||||
|
||||
list_for_each_safe(source, next, &libinput->source_destroy_list, link)
|
||||
free(source);
|
||||
list_init(&libinput->source_destroy_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
init_event_base(struct libinput_event *event,
|
||||
enum libinput_event_type type,
|
||||
struct libinput_device *device)
|
||||
{
|
||||
event->type = type;
|
||||
event->device = device;
|
||||
}
|
||||
|
||||
static void
|
||||
post_device_event(struct libinput_device *device,
|
||||
enum libinput_event_type type,
|
||||
struct libinput_event *event)
|
||||
{
|
||||
init_event_base(event, type, device);
|
||||
libinput_post_event(device->libinput, event);
|
||||
}
|
||||
|
||||
void
|
||||
device_register_capability(struct libinput_device *device,
|
||||
enum libinput_device_capability capability)
|
||||
{
|
||||
struct libinput_event_device_register_capability *capability_event;
|
||||
|
||||
capability_event = malloc(sizeof *capability_event);
|
||||
|
||||
*capability_event = (struct libinput_event_device_register_capability) {
|
||||
.capability = capability,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
LIBINPUT_EVENT_DEVICE_REGISTER_CAPABILITY,
|
||||
&capability_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
device_unregister_capability(struct libinput_device *device,
|
||||
enum libinput_device_capability capability)
|
||||
{
|
||||
struct libinput_event_device_unregister_capability *capability_event;
|
||||
|
||||
capability_event = malloc(sizeof *capability_event);
|
||||
|
||||
*capability_event = (struct libinput_event_device_unregister_capability) {
|
||||
.capability = capability,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
LIBINPUT_EVENT_DEVICE_UNREGISTER_CAPABILITY,
|
||||
&capability_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
keyboard_notify_key(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
uint32_t key,
|
||||
enum libinput_keyboard_key_state state)
|
||||
{
|
||||
struct libinput_event_keyboard_key *key_event;
|
||||
|
||||
key_event = malloc(sizeof *key_event);
|
||||
if (!key_event)
|
||||
return;
|
||||
|
||||
*key_event = (struct libinput_event_keyboard_key) {
|
||||
.time = time,
|
||||
.key = key,
|
||||
.state = state,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
LIBINPUT_EVENT_KEYBOARD_KEY,
|
||||
&key_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
pointer_notify_motion(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
li_fixed_t dx,
|
||||
li_fixed_t dy)
|
||||
{
|
||||
struct libinput_event_pointer_motion *motion_event;
|
||||
|
||||
motion_event = malloc(sizeof *motion_event);
|
||||
if (!motion_event)
|
||||
return;
|
||||
|
||||
*motion_event = (struct libinput_event_pointer_motion) {
|
||||
.time = time,
|
||||
.dx = dx,
|
||||
.dy = dy,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
LIBINPUT_EVENT_POINTER_MOTION,
|
||||
&motion_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
pointer_notify_motion_absolute(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
li_fixed_t x,
|
||||
li_fixed_t y)
|
||||
{
|
||||
struct libinput_event_pointer_motion_absolute *motion_absolute_event;
|
||||
|
||||
motion_absolute_event = malloc(sizeof *motion_absolute_event);
|
||||
if (!motion_absolute_event)
|
||||
return;
|
||||
|
||||
*motion_absolute_event = (struct libinput_event_pointer_motion_absolute) {
|
||||
.time = time,
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
|
||||
&motion_absolute_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
pointer_notify_button(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
int32_t button,
|
||||
enum libinput_pointer_button_state state)
|
||||
{
|
||||
struct libinput_event_pointer_button *button_event;
|
||||
|
||||
button_event = malloc(sizeof *button_event);
|
||||
if (!button_event)
|
||||
return;
|
||||
|
||||
*button_event = (struct libinput_event_pointer_button) {
|
||||
.time = time,
|
||||
.button = button,
|
||||
.state = state,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
LIBINPUT_EVENT_POINTER_BUTTON,
|
||||
&button_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
pointer_notify_axis(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
enum libinput_pointer_axis axis,
|
||||
li_fixed_t value)
|
||||
{
|
||||
struct libinput_event_pointer_axis *axis_event;
|
||||
|
||||
axis_event = malloc(sizeof *axis_event);
|
||||
if (!axis_event)
|
||||
return;
|
||||
|
||||
*axis_event = (struct libinput_event_pointer_axis) {
|
||||
.time = time,
|
||||
.axis = axis,
|
||||
.value = value,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
LIBINPUT_EVENT_POINTER_AXIS,
|
||||
&axis_event->base);
|
||||
}
|
||||
|
||||
void
|
||||
touch_notify_touch(struct libinput_device *device,
|
||||
uint32_t time,
|
||||
int32_t slot,
|
||||
li_fixed_t x,
|
||||
li_fixed_t y,
|
||||
enum libinput_touch_type touch_type)
|
||||
{
|
||||
struct libinput_event_touch_touch *touch_event;
|
||||
|
||||
touch_event = malloc(sizeof *touch_event);
|
||||
if (!touch_event)
|
||||
return;
|
||||
|
||||
*touch_event = (struct libinput_event_touch_touch) {
|
||||
.time = time,
|
||||
.slot = slot,
|
||||
.x = x,
|
||||
.y = y,
|
||||
.touch_type = touch_type,
|
||||
};
|
||||
|
||||
post_device_event(device,
|
||||
LIBINPUT_EVENT_TOUCH_TOUCH,
|
||||
&touch_event->base);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
events_count++;
|
||||
if (events_count > events_len) {
|
||||
if (events_len == 0)
|
||||
events_len = 4;
|
||||
else
|
||||
events_len *= 2;
|
||||
events = realloc(events, events_len * sizeof *events);
|
||||
if (!events) {
|
||||
fprintf(stderr, "Failed to reallocate event ring "
|
||||
"buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
libinput->events + libinput->events_out,
|
||||
move_len * sizeof *events);
|
||||
libinput->events_out = new_out;
|
||||
}
|
||||
|
||||
libinput->events = events;
|
||||
libinput->events_len = events_len;
|
||||
}
|
||||
|
||||
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 void
|
||||
libinput_device_terminate(struct libinput_device *device)
|
||||
{
|
||||
evdev_device_terminate((struct evdev_device *) device);
|
||||
device->terminated = 1;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT void
|
||||
libinput_device_destroy(struct libinput_device *device)
|
||||
{
|
||||
assert(device->terminated);
|
||||
evdev_device_destroy((struct evdev_device *) device);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT void *
|
||||
libinput_device_get_user_data(struct libinput_device *device)
|
||||
{
|
||||
return device->user_data;
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT void
|
||||
libinput_device_led_update(struct libinput_device *device,
|
||||
enum libinput_led leds)
|
||||
{
|
||||
evdev_device_led_update((struct evdev_device *) device, leds);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT int
|
||||
libinput_device_get_keys(struct libinput_device *device,
|
||||
char *keys, size_t size)
|
||||
{
|
||||
return evdev_device_get_keys((struct evdev_device *) device,
|
||||
keys,
|
||||
size);
|
||||
}
|
||||
|
||||
LIBINPUT_EXPORT void
|
||||
libinput_device_calibrate(struct libinput_device *device,
|
||||
float calibration[6])
|
||||
{
|
||||
evdev_device_calibrate((struct evdev_device *) device, calibration);
|
||||
}
|
||||
195
src/libinput.h
Normal file
195
src/libinput.h
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* Copyright © 2013 Jonas Ådahl
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and
|
||||
* its documentation for any purpose is hereby granted without fee, provided
|
||||
* that the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of the copyright holders not be used in
|
||||
* advertising or publicity pertaining to distribution of the software
|
||||
* without specific, written prior permission. The copyright holders make
|
||||
* no representations about the suitability of this software for any
|
||||
* purpose. It is provided "as is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
||||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LIBINPUT_H
|
||||
#define LIBINPUT_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int32_t li_fixed_t;
|
||||
|
||||
enum libinput_device_capability {
|
||||
LIBINPUT_DEVICE_CAP_KEYBOARD = 0,
|
||||
LIBINPUT_DEVICE_CAP_POINTER = 1,
|
||||
LIBINPUT_DEVICE_CAP_TOUCH = 2,
|
||||
};
|
||||
|
||||
enum libinput_keyboard_key_state {
|
||||
LIBINPUT_KEYBOARD_KEY_STATE_RELEASED = 0,
|
||||
LIBINPUT_KEYBOARD_KEY_STATE_PRESSED = 1,
|
||||
};
|
||||
|
||||
enum libinput_led {
|
||||
LIBINPUT_LED_NUM_LOCK = (1 << 0),
|
||||
LIBINPUT_LED_CAPS_LOCK = (1 << 1),
|
||||
LIBINPUT_LED_SCROLL_LOCK = (1 << 2),
|
||||
};
|
||||
|
||||
enum libinput_pointer_button_state {
|
||||
LIBINPUT_POINTER_BUTTON_STATE_RELEASED = 0,
|
||||
LIBINPUT_POINTER_BUTTON_STATE_PRESSED = 1,
|
||||
};
|
||||
|
||||
enum libinput_pointer_axis {
|
||||
LIBINPUT_POINTER_AXIS_VERTICAL_SCROLL = 0,
|
||||
LIBINPUT_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
|
||||
};
|
||||
|
||||
enum libinput_touch_type {
|
||||
LIBINPUT_TOUCH_TYPE_DOWN = 0,
|
||||
LIBINPUT_TOUCH_TYPE_UP = 1,
|
||||
LIBINPUT_TOUCH_TYPE_MOTION = 2,
|
||||
LIBINPUT_TOUCH_TYPE_FRAME = 3,
|
||||
LIBINPUT_TOUCH_TYPE_CANCEL = 4,
|
||||
};
|
||||
|
||||
enum libinput_event_type {
|
||||
LIBINPUT_EVENT_DEVICE_REGISTER_CAPABILITY = 200,
|
||||
LIBINPUT_EVENT_DEVICE_UNREGISTER_CAPABILITY,
|
||||
|
||||
LIBINPUT_EVENT_KEYBOARD_KEY = 300,
|
||||
|
||||
LIBINPUT_EVENT_POINTER_MOTION = 400,
|
||||
LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE,
|
||||
LIBINPUT_EVENT_POINTER_BUTTON,
|
||||
LIBINPUT_EVENT_POINTER_AXIS,
|
||||
|
||||
LIBINPUT_EVENT_TOUCH_TOUCH = 500,
|
||||
};
|
||||
|
||||
struct libinput_event {
|
||||
enum libinput_event_type type;
|
||||
struct libinput_device *device;
|
||||
};
|
||||
|
||||
struct libinput_event_device_register_capability {
|
||||
struct libinput_event base;
|
||||
enum libinput_device_capability capability;
|
||||
};
|
||||
|
||||
struct libinput_event_device_unregister_capability {
|
||||
struct libinput_event base;
|
||||
enum libinput_device_capability capability;
|
||||
};
|
||||
|
||||
struct libinput_event_keyboard_key {
|
||||
struct libinput_event base;
|
||||
uint32_t time;
|
||||
uint32_t key;
|
||||
enum libinput_keyboard_key_state state;
|
||||
};
|
||||
|
||||
struct libinput_event_pointer_motion {
|
||||
struct libinput_event base;
|
||||
uint32_t time;
|
||||
li_fixed_t dx;
|
||||
li_fixed_t dy;
|
||||
};
|
||||
|
||||
struct libinput_event_pointer_motion_absolute {
|
||||
struct libinput_event base;
|
||||
uint32_t time;
|
||||
li_fixed_t x;
|
||||
li_fixed_t y;
|
||||
};
|
||||
|
||||
struct libinput_event_pointer_button {
|
||||
struct libinput_event base;
|
||||
uint32_t time;
|
||||
int32_t button;
|
||||
enum libinput_pointer_button_state state;
|
||||
};
|
||||
|
||||
struct libinput_event_pointer_axis {
|
||||
struct libinput_event base;
|
||||
uint32_t time;
|
||||
enum libinput_pointer_axis axis;
|
||||
li_fixed_t value;
|
||||
};
|
||||
|
||||
struct libinput_event_touch_touch {
|
||||
struct libinput_event base;
|
||||
uint32_t time;
|
||||
int32_t slot;
|
||||
li_fixed_t x;
|
||||
li_fixed_t y;
|
||||
enum libinput_touch_type touch_type;
|
||||
};
|
||||
|
||||
struct libinput_fd_handle;
|
||||
|
||||
typedef void (*libinput_fd_callback)(int fd, void *data);
|
||||
|
||||
struct libinput_interface {
|
||||
void (*get_current_screen_dimensions)(struct libinput_device *device,
|
||||
int *width,
|
||||
int *height,
|
||||
void *user_data);
|
||||
};
|
||||
|
||||
struct libinput;
|
||||
struct libinput_device;
|
||||
|
||||
struct libinput *
|
||||
libinput_create(const struct libinput_interface *interface, void *user_data);
|
||||
|
||||
int
|
||||
libinput_get_fd(struct libinput *libinput);
|
||||
|
||||
int
|
||||
libinput_dispatch(struct libinput *libinput);
|
||||
|
||||
struct libinput_event *
|
||||
libinput_get_event(struct libinput *libinput);
|
||||
|
||||
void
|
||||
libinput_destroy(struct libinput *libinput);
|
||||
|
||||
struct libinput_device *
|
||||
libinput_device_create_evdev(struct libinput *libinput,
|
||||
const char *devnode,
|
||||
int fd,
|
||||
void *user_data);
|
||||
|
||||
void
|
||||
libinput_device_terminate(struct libinput_device *device);
|
||||
|
||||
void
|
||||
libinput_device_destroy(struct libinput_device *device);
|
||||
|
||||
void *
|
||||
libinput_device_get_user_data(struct libinput_device *device);
|
||||
|
||||
void
|
||||
libinput_device_led_update(struct libinput_device *device,
|
||||
enum libinput_led leds);
|
||||
|
||||
int
|
||||
libinput_device_get_keys(struct libinput_device *device,
|
||||
char *keys, size_t size);
|
||||
|
||||
void
|
||||
libinput_device_calibrate(struct libinput_device *device,
|
||||
float calibration[6]);
|
||||
|
||||
#endif /* LIBINPUT_H */
|
||||
12
src/libinput.pc.in
Normal file
12
src/libinput.pc.in
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
datarootdir=@datarootdir@
|
||||
pkgdatadir=@datadir@/@PACKAGE@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: Libinput
|
||||
Description: Input device library
|
||||
Version: @LIBINPUT_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
Libs: -L${libdir} -linput
|
||||
Loading…
Add table
Reference in a new issue