mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-03-28 08:40:35 +01:00
Compare commits
23 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eeb967b650 | ||
|
|
b437b2f196 | ||
|
|
1c15e162b8 | ||
|
|
40750c26f8 | ||
|
|
dd85749e61 | ||
|
|
2496923585 | ||
|
|
0fec9c65e9 | ||
|
|
c4fc98731d | ||
|
|
3efd7c82aa | ||
|
|
5f4d975861 | ||
|
|
298b28d7f1 | ||
|
|
68949fc5c5 | ||
|
|
25d1fbbf00 | ||
|
|
5c86ba7580 | ||
|
|
c5c6cc13be | ||
|
|
70258657b0 | ||
|
|
596a03a0fa | ||
|
|
71fe2b6ef4 | ||
|
|
fc78cdc4bb | ||
|
|
0fcbb58d97 | ||
|
|
c726f37ebd | ||
|
|
3d4712d10a | ||
|
|
076c7b6c00 |
24 changed files with 590 additions and 839 deletions
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 78 KiB |
10
meson.build
10
meson.build
|
|
@ -1,5 +1,5 @@
|
|||
project('libinput', 'c', 'cpp',
|
||||
version : '1.10.0',
|
||||
version : '1.10.2',
|
||||
license : 'MIT/Expat',
|
||||
default_options : [ 'c_std=gnu99', 'warning_level=2' ],
|
||||
meson_version : '>= 0.40.0')
|
||||
|
|
@ -234,7 +234,7 @@ pkgconfig.generate(
|
|||
# Restore the SELinux context for the libinput.so.a.b.c on install
|
||||
# meson bug https://github.com/mesonbuild/meson/issues/1967
|
||||
meson.add_install_script('src/libinput-restore-selinux-context.sh',
|
||||
get_option('libdir'),
|
||||
join_paths(get_option('prefix'), get_option('libdir')),
|
||||
lib_libinput.full_path())
|
||||
|
||||
############ documentation ############
|
||||
|
|
@ -496,7 +496,8 @@ configure_file(input : 'tools/libinput.man',
|
|||
install_dir : join_paths(get_option('mandir'), 'man1')
|
||||
)
|
||||
|
||||
meson.add_install_script('tools/install-compat-scripts.sh')
|
||||
meson.add_install_script('tools/install-compat-scripts.sh',
|
||||
join_paths(get_option('prefix'), get_option('bindir')))
|
||||
|
||||
ptraccel_debug_sources = [ 'tools/ptraccel-debug.c' ]
|
||||
executable('ptraccel-debug',
|
||||
|
|
@ -522,7 +523,7 @@ if get_option('tests')
|
|||
config_h.set10('HAVE_LIBUNWIND', dep_libunwind.found())
|
||||
|
||||
# for inhibit support during test run
|
||||
dep_libsystemd = dependency('libsystemd', required : false)
|
||||
dep_libsystemd = dependency('libsystemd', version : '>= 221', required : false)
|
||||
config_h.set10('HAVE_LIBSYSTEMD', dep_libsystemd.found())
|
||||
|
||||
lib_litest_sources = [
|
||||
|
|
@ -563,6 +564,7 @@ if get_option('tests')
|
|||
'test/litest-device-mouse-low-dpi.c',
|
||||
'test/litest-device-mouse-wheel-click-angle.c',
|
||||
'test/litest-device-mouse-wheel-click-count.c',
|
||||
'test/litest-device-ms-nano-transceiver-mouse.c',
|
||||
'test/litest-device-ms-surface-cover.c',
|
||||
'test/litest-device-protocol-a-touch-screen.c',
|
||||
'test/litest-device-qemu-usb-tablet.c',
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ debounce_state_to_str(enum debounce_state state)
|
|||
CASE_RETURN_STRING(DEBOUNCE_STATE_MAYBE_SPURIOUS);
|
||||
CASE_RETURN_STRING(DEBOUNCE_STATE_RELEASED);
|
||||
CASE_RETURN_STRING(DEBOUNCE_STATE_PRESS_PENDING);
|
||||
CASE_RETURN_STRING(DEBOUNCE_STATE_DISABLED);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
@ -394,6 +395,31 @@ debounce_press_pending_event(struct fallback_dispatch *fallback, enum debounce_e
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
debounce_disabled_event(struct fallback_dispatch *fallback,
|
||||
enum debounce_event event,
|
||||
uint64_t time)
|
||||
{
|
||||
switch (event) {
|
||||
case DEBOUNCE_EVENT_PRESS:
|
||||
fallback->debounce.button_time = time;
|
||||
debounce_notify_button(fallback,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
break;
|
||||
case DEBOUNCE_EVENT_RELEASE:
|
||||
fallback->debounce.button_time = time;
|
||||
debounce_notify_button(fallback,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case DEBOUNCE_EVENT_TIMEOUT_SHORT:
|
||||
case DEBOUNCE_EVENT_TIMEOUT:
|
||||
log_debounce_bug(fallback, event);
|
||||
break;
|
||||
case DEBOUNCE_EVENT_OTHERBUTTON:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
debounce_handle_event(struct fallback_dispatch *fallback,
|
||||
enum debounce_event event,
|
||||
|
|
@ -434,6 +460,9 @@ debounce_handle_event(struct fallback_dispatch *fallback,
|
|||
case DEBOUNCE_STATE_PRESS_PENDING:
|
||||
debounce_press_pending_event(fallback, event, time);
|
||||
break;
|
||||
case DEBOUNCE_STATE_DISABLED:
|
||||
debounce_disabled_event(fallback, event, time);
|
||||
break;
|
||||
}
|
||||
|
||||
evdev_log_debug(fallback->device,
|
||||
|
|
@ -484,7 +513,8 @@ fallback_debounce_handle_state(struct fallback_dispatch *dispatch,
|
|||
for (size_t i = 0; i < nchanged; i++) {
|
||||
bool is_down = hw_is_key_down(dispatch, changed[i]);
|
||||
|
||||
if (flushed) {
|
||||
if (flushed &&
|
||||
dispatch->debounce.state != DEBOUNCE_STATE_DISABLED) {
|
||||
debounce_set_state(dispatch,
|
||||
!is_down ?
|
||||
DEBOUNCE_STATE_IS_DOWN :
|
||||
|
|
@ -538,6 +568,12 @@ fallback_init_debounce(struct fallback_dispatch *dispatch)
|
|||
struct evdev_device *device = dispatch->device;
|
||||
char timer_name[64];
|
||||
|
||||
if (device->model_flags & EVDEV_MODEL_MS_NANO_TRANSCEIVER) {
|
||||
dispatch->debounce.state = DEBOUNCE_STATE_DISABLED;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
dispatch->debounce.state = DEBOUNCE_STATE_IS_UP;
|
||||
|
||||
snprintf(timer_name,
|
||||
|
|
|
|||
|
|
@ -127,12 +127,9 @@ fallback_filter_defuzz_touch(struct fallback_dispatch *dispatch,
|
|||
if (!dispatch->mt.want_hysteresis)
|
||||
return false;
|
||||
|
||||
point.x = evdev_hysteresis(slot->point.x,
|
||||
slot->hysteresis_center.x,
|
||||
dispatch->mt.hysteresis_margin.x);
|
||||
point.y = evdev_hysteresis(slot->point.y,
|
||||
slot->hysteresis_center.y,
|
||||
dispatch->mt.hysteresis_margin.y);
|
||||
point = evdev_hysteresis(&slot->point,
|
||||
&slot->hysteresis_center,
|
||||
&dispatch->mt.hysteresis_margin);
|
||||
|
||||
slot->hysteresis_center = slot->point;
|
||||
if (point.x == slot->point.x && point.y == slot->point.y)
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ enum debounce_state {
|
|||
DEBOUNCE_STATE_MAYBE_SPURIOUS,
|
||||
DEBOUNCE_STATE_RELEASED,
|
||||
DEBOUNCE_STATE_PRESS_PENDING,
|
||||
|
||||
DEBOUNCE_STATE_DISABLED = 999,
|
||||
};
|
||||
|
||||
struct fallback_dispatch {
|
||||
|
|
|
|||
|
|
@ -362,6 +362,13 @@ tp_edge_scroll_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
case TOUCH_UPDATE:
|
||||
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_MOTION);
|
||||
break;
|
||||
case TOUCH_MAYBE_END:
|
||||
/* This shouldn't happen we transfer to TOUCH_END
|
||||
* before processing state */
|
||||
evdev_log_debug(tp->device,
|
||||
"touch unexpected state %d\n",
|
||||
t->state);
|
||||
/* fallthrough */
|
||||
case TOUCH_END:
|
||||
tp_edge_scroll_handle_event(tp, t, SCROLL_EVENT_RELEASE);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1025,6 +1025,7 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
|
||||
} else if (t->state == TOUCH_END) {
|
||||
if (t->was_down) {
|
||||
assert(tp->tap.nfingers_down >= 1);
|
||||
tp->tap.nfingers_down--;
|
||||
tp_tap_handle_event(tp, t, TAP_EVENT_RELEASE, time);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,10 @@ tp_calculate_motion_speed(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
double distance;
|
||||
double speed;
|
||||
|
||||
/* Don't do this on single-touch or semi-mt devices */
|
||||
if (!tp->has_mt || tp->semi_mt)
|
||||
return;
|
||||
|
||||
/* This doesn't kick in until we have at least 4 events in the
|
||||
* motion history. As a side-effect, this automatically handles the
|
||||
* 2fg scroll where a finger is down and moving fast before the
|
||||
|
|
@ -131,46 +135,74 @@ tp_motion_history_push(struct tp_touch *t)
|
|||
t->history.index = motion_index;
|
||||
}
|
||||
|
||||
/* Idea: if we got a tuple of *very* quick moves like {Left, Right,
|
||||
* Left}, or {Right, Left, Right}, it means touchpad jitters since no
|
||||
* human can move like that within thresholds.
|
||||
*
|
||||
* We encode left moves as zeroes, and right as ones. We also drop
|
||||
* the array to all zeroes when contraints are not satisfied. Then we
|
||||
* search for the pattern {1,0,1}. It can't match {Left, Right, Left},
|
||||
* but it does match {Left, Right, Left, Right}, so it's okay.
|
||||
*
|
||||
* This only looks at x changes, y changes are ignored.
|
||||
*/
|
||||
static inline void
|
||||
tp_maybe_disable_hysteresis(struct tp_dispatch *tp, uint64_t time)
|
||||
tp_detect_wobbling(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
uint64_t time)
|
||||
{
|
||||
/* If the finger is down for 80ms without seeing motion events,
|
||||
the firmware filters and we don't need a software hysteresis */
|
||||
if (tp->nfingers_down >= 1 &&
|
||||
time - tp->hysteresis.last_motion_time > ms2us(80)) {
|
||||
tp->hysteresis.enabled = false;
|
||||
evdev_log_debug(tp->device, "hysteresis disabled\n");
|
||||
int dx, dy;
|
||||
uint64_t dtime;
|
||||
|
||||
if (!(tp->queued & TOUCHPAD_EVENT_MOTION) || tp->hysteresis.enabled)
|
||||
return;
|
||||
|
||||
if (t->last_point.x == 0) { /* first invocation */
|
||||
dx = 0;
|
||||
dy = 0;
|
||||
} else {
|
||||
dx = t->last_point.x - t->point.x;
|
||||
dy = t->last_point.y - t->point.y;
|
||||
}
|
||||
|
||||
dtime = time - tp->hysteresis.last_motion_time;
|
||||
|
||||
tp->hysteresis.last_motion_time = time;
|
||||
t->last_point = t->point;
|
||||
|
||||
if (dx == 0 && dy != 0) /* ignore y-only changes */
|
||||
return;
|
||||
|
||||
if (dtime > ms2us(40)) {
|
||||
t->hysteresis.x_motion_history = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (tp->queued & TOUCHPAD_EVENT_MOTION)
|
||||
tp->hysteresis.last_motion_time = time;
|
||||
t->hysteresis.x_motion_history <<= 1;
|
||||
if (dx > 0) { /* right move */
|
||||
static const char r_l_r = 0x5; /* {Right, Left, Right} */
|
||||
|
||||
t->hysteresis.x_motion_history |= 0x1;
|
||||
if (t->hysteresis.x_motion_history == r_l_r) {
|
||||
tp->hysteresis.enabled = true;
|
||||
evdev_log_debug(tp->device, "hysteresis enabled\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
tp_motion_hysteresis(struct tp_dispatch *tp,
|
||||
struct tp_touch *t)
|
||||
{
|
||||
int x = t->point.x,
|
||||
y = t->point.y;
|
||||
|
||||
if (!tp->hysteresis.enabled)
|
||||
return;
|
||||
|
||||
if (t->history.count == 0) {
|
||||
t->hysteresis_center = t->point;
|
||||
} else {
|
||||
x = evdev_hysteresis(x,
|
||||
t->hysteresis_center.x,
|
||||
tp->hysteresis.margin.x);
|
||||
y = evdev_hysteresis(y,
|
||||
t->hysteresis_center.y,
|
||||
tp->hysteresis.margin.y);
|
||||
t->hysteresis_center.x = x;
|
||||
t->hysteresis_center.y = y;
|
||||
t->point.x = x;
|
||||
t->point.y = y;
|
||||
}
|
||||
if (t->history.count > 0)
|
||||
t->point = evdev_hysteresis(&t->point,
|
||||
&t->hysteresis.center,
|
||||
&tp->hysteresis.margin);
|
||||
|
||||
t->hysteresis.center = t->point;
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
@ -276,6 +308,7 @@ tp_new_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
|||
t->time = time;
|
||||
t->speed.last_speed = 0;
|
||||
t->speed.exceeded_count = 0;
|
||||
t->hysteresis.x_motion_history = 0;
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
}
|
||||
|
||||
|
|
@ -297,22 +330,64 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
|||
}
|
||||
|
||||
/**
|
||||
* End a touch, even if the touch sequence is still active.
|
||||
* Schedule a touch to be ended, based on either the events or some
|
||||
* attributes of the touch (size, pressure). In some cases we need to
|
||||
* resurrect a touch that has ended, so this doesn't actually end the touch
|
||||
* yet. All the TOUCH_MAYBE_END touches get properly ended once the device
|
||||
* state has been processed once and we know how many zombie touches we
|
||||
* need.
|
||||
*/
|
||||
static inline void
|
||||
tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
||||
tp_maybe_end_touch(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
uint64_t time)
|
||||
{
|
||||
switch (t->state) {
|
||||
case TOUCH_HOVERING:
|
||||
t->state = TOUCH_NONE;
|
||||
/* fallthough */
|
||||
case TOUCH_NONE:
|
||||
case TOUCH_MAYBE_END:
|
||||
case TOUCH_HOVERING:
|
||||
return;
|
||||
case TOUCH_END:
|
||||
evdev_log_bug_libinput(tp->device,
|
||||
"touch already in TOUCH_END\n");
|
||||
return;
|
||||
case TOUCH_BEGIN:
|
||||
case TOUCH_UPDATE:
|
||||
break;
|
||||
}
|
||||
|
||||
t->dirty = true;
|
||||
t->state = TOUCH_MAYBE_END;
|
||||
|
||||
assert(tp->nfingers_down >= 1);
|
||||
tp->nfingers_down--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inverse to tp_maybe_end_touch(), restores a touch back to its previous
|
||||
* state.
|
||||
*/
|
||||
static inline void
|
||||
tp_recover_ended_touch(struct tp_dispatch *tp,
|
||||
struct tp_touch *t)
|
||||
{
|
||||
t->dirty = true;
|
||||
t->state = TOUCH_UPDATE;
|
||||
tp->nfingers_down++;
|
||||
}
|
||||
|
||||
/**
|
||||
* End a touch, even if the touch sequence is still active.
|
||||
* Use tp_maybe_end_touch() instead.
|
||||
*/
|
||||
static inline void
|
||||
tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
||||
{
|
||||
if (t->state != TOUCH_MAYBE_END) {
|
||||
evdev_log_bug_libinput(tp->device,
|
||||
"touch should be MAYBE_END, is %d\n",
|
||||
t->state);
|
||||
return;
|
||||
}
|
||||
|
||||
t->dirty = true;
|
||||
|
|
@ -321,8 +396,6 @@ tp_end_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
|||
t->pinned.is_pinned = false;
|
||||
t->time = time;
|
||||
t->palm.time = 0;
|
||||
assert(tp->nfingers_down >= 1);
|
||||
tp->nfingers_down--;
|
||||
tp->queued |= TOUCHPAD_EVENT_MOTION;
|
||||
}
|
||||
|
||||
|
|
@ -333,7 +406,7 @@ static inline void
|
|||
tp_end_sequence(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
||||
{
|
||||
t->has_ended = true;
|
||||
tp_end_touch(tp, t, time);
|
||||
tp_maybe_end_touch(tp, t, time);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -480,13 +553,11 @@ tp_restore_synaptics_touches(struct tp_dispatch *tp,
|
|||
for (i = 0; i < tp->num_slots; i++) {
|
||||
struct tp_touch *t = tp_get_touch(tp, i);
|
||||
|
||||
if (t->state != TOUCH_END)
|
||||
if (t->state != TOUCH_MAYBE_END)
|
||||
continue;
|
||||
|
||||
/* new touch, move it through begin to update immediately */
|
||||
tp_new_touch(tp, t, time);
|
||||
tp_begin_touch(tp, t, time);
|
||||
t->state = TOUCH_UPDATE;
|
||||
tp_recover_ended_touch(tp, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1070,11 +1141,13 @@ tp_unhover_pressure(struct tp_dispatch *tp, uint64_t time)
|
|||
tp_motion_history_reset(t);
|
||||
tp_begin_touch(tp, t, time);
|
||||
}
|
||||
} else {
|
||||
/* don't unhover for pressure if we have too many
|
||||
* fake fingers down, see comment below */
|
||||
} else if (nfake_touches <= tp->num_slots) {
|
||||
if (t->pressure < tp->pressure.low) {
|
||||
evdev_log_debug(tp->device,
|
||||
"pressure: end touch\n");
|
||||
tp_end_touch(tp, t, time);
|
||||
tp_maybe_end_touch(tp, t, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1092,14 +1165,16 @@ tp_unhover_pressure(struct tp_dispatch *tp, uint64_t time)
|
|||
* _all_ fingers have enough pressure, even if some of the slotted
|
||||
* ones don't. Anything else gets insane quickly.
|
||||
*/
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t->state == TOUCH_HOVERING) {
|
||||
/* avoid jumps when landing a finger */
|
||||
tp_motion_history_reset(t);
|
||||
tp_begin_touch(tp, t, time);
|
||||
if (real_fingers_down > 0) {
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t->state == TOUCH_HOVERING) {
|
||||
/* avoid jumps when landing a finger */
|
||||
tp_motion_history_reset(t);
|
||||
tp_begin_touch(tp, t, time);
|
||||
|
||||
if (tp->nfingers_down >= nfake_touches)
|
||||
break;
|
||||
if (tp->nfingers_down >= nfake_touches)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1109,10 +1184,11 @@ tp_unhover_pressure(struct tp_dispatch *tp, uint64_t time)
|
|||
t = tp_get_touch(tp, i);
|
||||
|
||||
if (t->state == TOUCH_HOVERING ||
|
||||
t->state == TOUCH_NONE)
|
||||
t->state == TOUCH_NONE ||
|
||||
t->state == TOUCH_MAYBE_END)
|
||||
continue;
|
||||
|
||||
tp_end_touch(tp, t, time);
|
||||
tp_maybe_end_touch(tp, t, time);
|
||||
|
||||
if (real_fingers_down > 0 &&
|
||||
tp->nfingers_down == nfake_touches)
|
||||
|
|
@ -1154,7 +1230,7 @@ tp_unhover_size(struct tp_dispatch *tp, uint64_t time)
|
|||
if (t->major < low || t->minor < low) {
|
||||
evdev_log_debug(tp->device,
|
||||
"touch-size: end touch\n");
|
||||
tp_end_touch(tp, t, time);
|
||||
tp_maybe_end_touch(tp, t, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1208,7 +1284,7 @@ tp_unhover_fake_touches(struct tp_dispatch *tp, uint64_t time)
|
|||
t->state == TOUCH_NONE)
|
||||
continue;
|
||||
|
||||
tp_end_touch(tp, t, time);
|
||||
tp_maybe_end_touch(tp, t, time);
|
||||
|
||||
if (tp_fake_finger_is_touching(tp) &&
|
||||
tp->nfingers_down == nfake_touches)
|
||||
|
|
@ -1375,6 +1451,21 @@ tp_detect_thumb_while_moving(struct tp_dispatch *tp)
|
|||
second->thumb.state = THUMB_STATE_YES;
|
||||
}
|
||||
|
||||
static void
|
||||
tp_pre_process_state(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
struct tp_touch *t;
|
||||
|
||||
tp_process_fake_touches(tp, time);
|
||||
tp_unhover_touches(tp, time);
|
||||
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (t->state == TOUCH_MAYBE_END)
|
||||
tp_end_touch(tp, t, time);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
tp_process_state(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
|
|
@ -1384,8 +1475,6 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
|
|||
bool have_new_touch = false;
|
||||
unsigned int speed_exceeded_count = 0;
|
||||
|
||||
tp_process_fake_touches(tp, time);
|
||||
tp_unhover_touches(tp, time);
|
||||
tp_position_fake_touches(tp);
|
||||
|
||||
want_motion_reset = tp_need_motion_history_reset(tp);
|
||||
|
|
@ -1420,7 +1509,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
|
|||
|
||||
tp_thumb_detect(tp, t, time);
|
||||
tp_palm_detect(tp, t, time);
|
||||
|
||||
tp_detect_wobbling(tp, t, time);
|
||||
tp_motion_hysteresis(tp, t);
|
||||
tp_motion_history_push(t);
|
||||
|
||||
|
|
@ -1544,9 +1633,7 @@ static void
|
|||
tp_handle_state(struct tp_dispatch *tp,
|
||||
uint64_t time)
|
||||
{
|
||||
if (tp->hysteresis.enabled)
|
||||
tp_maybe_disable_hysteresis(tp, time);
|
||||
|
||||
tp_pre_process_state(tp, time);
|
||||
tp_process_state(tp, time);
|
||||
tp_post_events(tp, time);
|
||||
tp_post_process_state(tp, time);
|
||||
|
|
@ -2936,7 +3023,7 @@ tp_init_hysteresis(struct tp_dispatch *tp)
|
|||
res_y = tp->device->abs.absinfo_y->resolution;
|
||||
tp->hysteresis.margin.x = res_x/2;
|
||||
tp->hysteresis.margin.y = res_y/2;
|
||||
tp->hysteresis.enabled = true;
|
||||
tp->hysteresis.enabled = false;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2995,7 +3082,9 @@ tp_init_pressure(struct tp_dispatch *tp,
|
|||
tp->pressure.low = lo;
|
||||
|
||||
evdev_log_debug(device,
|
||||
"using pressure-based touch detection\n");
|
||||
"using pressure-based touch detection (%d:%d)\n",
|
||||
lo,
|
||||
hi);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
|||
|
|
@ -46,10 +46,11 @@ enum touchpad_event {
|
|||
|
||||
enum touch_state {
|
||||
TOUCH_NONE = 0,
|
||||
TOUCH_HOVERING,
|
||||
TOUCH_BEGIN,
|
||||
TOUCH_UPDATE,
|
||||
TOUCH_END
|
||||
TOUCH_HOVERING = 1,
|
||||
TOUCH_BEGIN = 2,
|
||||
TOUCH_UPDATE = 3,
|
||||
TOUCH_MAYBE_END = 4,
|
||||
TOUCH_END = 5,
|
||||
};
|
||||
|
||||
enum touch_palm_state {
|
||||
|
|
@ -147,6 +148,7 @@ struct tp_touch {
|
|||
bool has_ended; /* TRACKING_ID == -1 */
|
||||
bool dirty;
|
||||
struct device_coords point;
|
||||
struct device_coords last_point;
|
||||
uint64_t time;
|
||||
int pressure;
|
||||
bool is_tool_palm; /* MT_TOOL_PALM */
|
||||
|
|
@ -173,7 +175,10 @@ struct tp_touch {
|
|||
unsigned int count;
|
||||
} history;
|
||||
|
||||
struct device_coords hysteresis_center;
|
||||
struct {
|
||||
struct device_coords center;
|
||||
uint8_t x_motion_history;
|
||||
} hysteresis;
|
||||
|
||||
/* A pinned touchpoint is the one that pressed the physical button
|
||||
* on a clickpad. After the release, it won't move until the center
|
||||
|
|
|
|||
|
|
@ -1264,6 +1264,7 @@ evdev_read_model_flags(struct evdev_device *device)
|
|||
MODEL(APPLE_TOUCHPAD_ONEBUTTON),
|
||||
MODEL(LOGITECH_MARBLE_MOUSE),
|
||||
MODEL(TABLET_NO_PROXIMITY_OUT),
|
||||
MODEL(MS_NANO_TRANSCEIVER),
|
||||
#undef MODEL
|
||||
{ "ID_INPUT_TRACKBALL", EVDEV_MODEL_TRACKBALL },
|
||||
{ NULL, EVDEV_MODEL_DEFAULT },
|
||||
|
|
@ -1917,6 +1918,11 @@ evdev_device_create(struct libinput_seat *seat,
|
|||
const char *devnode = udev_device_get_devnode(udev_device);
|
||||
const char *sysname = udev_device_get_sysname(udev_device);
|
||||
|
||||
if (!devnode) {
|
||||
log_info(libinput, "%s: no device node associated\n", sysname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (udev_device_should_be_ignored(udev_device)) {
|
||||
log_debug(libinput, "%s: device is ignored\n", sysname);
|
||||
return NULL;
|
||||
|
|
@ -2434,6 +2440,9 @@ evdev_device_resume(struct evdev_device *device)
|
|||
return -ENODEV;
|
||||
|
||||
devnode = udev_device_get_devnode(device->udev_device);
|
||||
if (!devnode)
|
||||
return -ENODEV;
|
||||
|
||||
fd = open_restricted(libinput, devnode,
|
||||
O_RDWR | O_NONBLOCK | O_CLOEXEC);
|
||||
|
||||
|
|
|
|||
93
src/evdev.h
93
src/evdev.h
|
|
@ -124,6 +124,7 @@ enum evdev_device_model {
|
|||
EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON = (1 << 25),
|
||||
EVDEV_MODEL_LOGITECH_MARBLE_MOUSE = (1 << 26),
|
||||
EVDEV_MODEL_TABLET_NO_PROXIMITY_OUT = (1 << 27),
|
||||
EVDEV_MODEL_MS_NANO_TRANSCEIVER = (1 << 28),
|
||||
};
|
||||
|
||||
enum evdev_button_scroll_state {
|
||||
|
|
@ -599,11 +600,11 @@ evdev_to_left_handed(struct evdev_device *device,
|
|||
* Apply a hysteresis filtering to the coordinate in, based on the current
|
||||
* hysteresis center and the margin. If 'in' is within 'margin' of center,
|
||||
* return the center (and thus filter the motion). If 'in' is outside,
|
||||
* return a point on the edge of the new margin. So for a point x in the
|
||||
* space outside c + margin we return r:
|
||||
* +---+ +---+
|
||||
* return a point on the edge of the new margin (which is an ellipse, usually
|
||||
* a circle). So for a point x in the space outside c + margin we return r:
|
||||
* ,---. ,---.
|
||||
* | c | x → | r x
|
||||
* +---+ +---+
|
||||
* `---' `---'
|
||||
*
|
||||
* The effect of this is that initial small motions are filtered. Once we
|
||||
* move into one direction we lag the real coordinates by 'margin' but any
|
||||
|
|
@ -616,41 +617,71 @@ evdev_to_left_handed(struct evdev_device *device,
|
|||
* Otherwise, the center has a dead zone of size margin around it and the
|
||||
* first reachable point is the margin edge.
|
||||
*
|
||||
* Hysteresis is handled separately per axis (and the window is thus
|
||||
* rectangular, not circular). It is unkown if that's an issue, but the
|
||||
* calculation to do circular hysteresis are nontrivial, especially since
|
||||
* many touchpads have uneven x/y resolutions.
|
||||
*
|
||||
* Given coordinates, 0, 1, 2, ... this is what we return for a margin of 3
|
||||
* and a center of 0:
|
||||
*
|
||||
* Input: 1 2 3 4 5 6 5 4 3 2 1 0 -1
|
||||
* Coord: 0 0 0 1 2 3 3 3 3 3 3 3 2
|
||||
* Center: 0 0 0 1 2 3 3 3 3 3 3 3 2
|
||||
*
|
||||
* Problem: viewed from a stationary finger that starts moving, the
|
||||
* hysteresis margin is M in both directions. Once we start moving
|
||||
* continuously though, the margin is 0 in the movement direction and 2*M to
|
||||
* change direction. That makes the finger less responsive to directional
|
||||
* changes than to the original movement.
|
||||
*
|
||||
* @param in The input coordinate
|
||||
* @param center Current center of the hysteresis
|
||||
* @param margin Hysteresis width (on each side)
|
||||
*
|
||||
* @return The new center of the hysteresis
|
||||
*/
|
||||
static inline int
|
||||
evdev_hysteresis(int in, int center, int margin)
|
||||
static inline struct device_coords
|
||||
evdev_hysteresis(const struct device_coords *in,
|
||||
const struct device_coords *center,
|
||||
const struct device_coords *margin)
|
||||
{
|
||||
int diff = in - center;
|
||||
if (abs(diff) <= margin)
|
||||
return center;
|
||||
int dx = in->x - center->x;
|
||||
int dy = in->y - center->y;
|
||||
int dx2 = dx * dx;
|
||||
int dy2 = dy * dy;
|
||||
int a = margin->x;
|
||||
int b = margin->y;
|
||||
double normalized_finger_distance, finger_distance, margin_distance;
|
||||
double lag_x, lag_y;
|
||||
struct device_coords result;
|
||||
|
||||
if (diff > 0)
|
||||
return in - margin;
|
||||
else
|
||||
return in + margin;
|
||||
if (!a || !b)
|
||||
return *in;
|
||||
|
||||
/*
|
||||
* Basic equation for an ellipse of radii a,b:
|
||||
* x²/a² + y²/b² = 1
|
||||
* But we start by making a scaled ellipse passing through the
|
||||
* relative finger location (dx,dy). So the scale of this ellipse is
|
||||
* the ratio of finger_distance to margin_distance:
|
||||
* dx²/a² + dy²/b² = normalized_finger_distance²
|
||||
*/
|
||||
normalized_finger_distance = sqrt((double)dx2 / (a * a) +
|
||||
(double)dy2 / (b * b));
|
||||
|
||||
/* Which means anything less than 1 is within the elliptical margin */
|
||||
if (normalized_finger_distance < 1.0)
|
||||
return *center;
|
||||
|
||||
finger_distance = sqrt(dx2 + dy2);
|
||||
margin_distance = finger_distance / normalized_finger_distance;
|
||||
|
||||
/*
|
||||
* Now calculate the x,y coordinates on the edge of the margin ellipse
|
||||
* where it intersects the finger vector. Shortcut: We achieve this by
|
||||
* finding the point with the same gradient as dy/dx.
|
||||
*/
|
||||
if (dx) {
|
||||
double gradient = (double)dy / dx;
|
||||
lag_x = margin_distance / sqrt(gradient * gradient + 1);
|
||||
lag_y = sqrt((margin_distance + lag_x) *
|
||||
(margin_distance - lag_x));
|
||||
} else { /* Infinite gradient */
|
||||
lag_x = 0.0;
|
||||
lag_y = margin_distance;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'result' is the centre of an ellipse (radii a,b) which has been
|
||||
* dragged by the finger moving inside it to 'in'. The finger is now
|
||||
* touching the margin ellipse at some point: (±lag_x,±lag_y)
|
||||
*/
|
||||
result.x = (dx >= 0) ? in->x - lag_x : in->x + lag_x;
|
||||
result.y = (dy >= 0) ? in->y - lag_y : in->y + lag_y;
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline struct libinput *
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ libdir="$1"
|
|||
sofile=$(basename "$2")
|
||||
|
||||
if command -v restorecon >/dev/null; then
|
||||
echo "Restoring SELinux context on $MESON_INSTALL_DESTDIR_PREFIX/$libdir/$sofile"
|
||||
restorecon "$MESON_INSTALL_DESTDIR_PREFIX/$libdir/$sofile"
|
||||
echo "Restoring SELinux context on ${DESTDIR}${libdir}/${sofile}"
|
||||
restorecon "${DESTDIR}${libdir}/${sofile}"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ udev_input_enable(struct libinput *libinput)
|
|||
struct udev *udev = input->udev;
|
||||
int fd;
|
||||
|
||||
if (input->udev_monitor)
|
||||
if (input->udev_monitor || !input->seat_id)
|
||||
return 0;
|
||||
|
||||
input->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
|
||||
|
|
|
|||
59
test/litest-device-ms-nano-transceiver-mouse.c
Normal file
59
test/litest-device-ms-nano-transceiver-mouse.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright © 2018 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "litest.h"
|
||||
#include "litest-int.h"
|
||||
|
||||
static struct input_id input_id = {
|
||||
.bustype = 0x3,
|
||||
.vendor = 0x045e,
|
||||
.product = 0x0800,
|
||||
};
|
||||
|
||||
static int events[] = {
|
||||
EV_KEY, BTN_LEFT,
|
||||
EV_KEY, BTN_RIGHT,
|
||||
EV_KEY, BTN_MIDDLE,
|
||||
EV_KEY, BTN_SIDE,
|
||||
EV_KEY, BTN_EXTRA,
|
||||
EV_REL, REL_X,
|
||||
EV_REL, REL_Y,
|
||||
EV_REL, REL_WHEEL,
|
||||
EV_REL, REL_DIAL,
|
||||
EV_REL, REL_HWHEEL,
|
||||
-1 , -1,
|
||||
};
|
||||
|
||||
TEST_DEVICE("ms-nano-mouse",
|
||||
.type = LITEST_MS_NANO_TRANSCEIVER_MOUSE,
|
||||
.features = LITEST_RELATIVE | LITEST_BUTTON | LITEST_WHEEL | LITEST_NO_DEBOUNCE,
|
||||
.interface = NULL,
|
||||
|
||||
.name = "Microsoft Microsoft® Nano Transceiver v2.0",
|
||||
.id = &input_id,
|
||||
.absinfo = NULL,
|
||||
.events = events,
|
||||
)
|
||||
|
||||
|
|
@ -270,6 +270,7 @@ enum litest_device_type {
|
|||
LITEST_WACOM_BAMBOO_2FG_PEN,
|
||||
LITEST_WACOM_BAMBOO_2FG_FINGER,
|
||||
LITEST_HP_WMI_HOTKEYS,
|
||||
LITEST_MS_NANO_TRANSCEIVER_MOUSE,
|
||||
};
|
||||
|
||||
enum litest_device_feature {
|
||||
|
|
@ -303,6 +304,7 @@ enum litest_device_feature {
|
|||
LITEST_LEDS = 1 << 25,
|
||||
LITEST_SWITCH = 1 << 26,
|
||||
LITEST_IGNORED = 1 << 27,
|
||||
LITEST_NO_DEBOUNCE = 1 << 28,
|
||||
};
|
||||
|
||||
/* this is a semi-mt device, so we keep track of the touches that the tests
|
||||
|
|
|
|||
|
|
@ -2602,11 +2602,11 @@ litest_setup_tests_pointer(void)
|
|||
|
||||
litest_add("pointer:time", pointer_time_usec, LITEST_RELATIVE, LITEST_ANY);
|
||||
|
||||
litest_add_ranged("pointer:debounce", debounce_bounce, LITEST_BUTTON, LITEST_TOUCHPAD, &buttons);
|
||||
litest_add("pointer:debounce", debounce_bounce_check_immediate, LITEST_BUTTON, LITEST_TOUCHPAD);
|
||||
litest_add_ranged("pointer:debounce", debounce_spurious, LITEST_BUTTON, LITEST_TOUCHPAD, &buttons);
|
||||
litest_add("pointer:debounce", debounce_spurious_multibounce, LITEST_BUTTON, LITEST_TOUCHPAD);
|
||||
litest_add("pointer:debounce_otherbutton", debounce_spurious_dont_enable_on_otherbutton, LITEST_BUTTON, LITEST_TOUCHPAD);
|
||||
litest_add("pointer:debounce_otherbutton", debounce_spurious_cancel_debounce_otherbutton, LITEST_BUTTON, LITEST_TOUCHPAD);
|
||||
litest_add("pointer:debounce_otherbutton", debounce_spurious_switch_to_otherbutton, LITEST_BUTTON, LITEST_TOUCHPAD);
|
||||
litest_add_ranged("pointer:debounce", debounce_bounce, LITEST_BUTTON, LITEST_TOUCHPAD|LITEST_NO_DEBOUNCE, &buttons);
|
||||
litest_add("pointer:debounce", debounce_bounce_check_immediate, LITEST_BUTTON, LITEST_TOUCHPAD|LITEST_NO_DEBOUNCE);
|
||||
litest_add_ranged("pointer:debounce", debounce_spurious, LITEST_BUTTON, LITEST_TOUCHPAD|LITEST_NO_DEBOUNCE, &buttons);
|
||||
litest_add("pointer:debounce", debounce_spurious_multibounce, LITEST_BUTTON, LITEST_TOUCHPAD|LITEST_NO_DEBOUNCE);
|
||||
litest_add("pointer:debounce_otherbutton", debounce_spurious_dont_enable_on_otherbutton, LITEST_BUTTON, LITEST_TOUCHPAD|LITEST_NO_DEBOUNCE);
|
||||
litest_add("pointer:debounce_otherbutton", debounce_spurious_cancel_debounce_otherbutton, LITEST_BUTTON, LITEST_TOUCHPAD|LITEST_NO_DEBOUNCE);
|
||||
litest_add("pointer:debounce_otherbutton", debounce_spurious_switch_to_otherbutton, LITEST_BUTTON, LITEST_TOUCHPAD|LITEST_NO_DEBOUNCE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1591,6 +1591,113 @@ START_TEST(touchpad_3fg_tap_quickrelease)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_3fg_tap_pressure_btntool)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
if (libevdev_get_abs_maximum(dev->evdev, ABS_MT_SLOT) >= 2)
|
||||
return;
|
||||
|
||||
/* libinput doesn't export when it uses pressure detection, so we
|
||||
* need to reconstruct this here. Specifically, semi-mt devices are
|
||||
* non-mt in libinput, so if they have ABS_PRESSURE, they'll use it.
|
||||
*/
|
||||
if (!libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_PRESSURE))
|
||||
return;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
litest_enable_edge_scroll(dev);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 1, 70, 50);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_touch_move_to(dev, 0, 50, 50, 50, 70, 10, 0);
|
||||
litest_touch_move_to(dev, 1, 70, 50, 50, 70, 10, 0);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* drop below the pressure threshold in the same frame as starting a */
|
||||
litest_event(dev, EV_ABS, ABS_MT_PRESSURE, 3);
|
||||
litest_event(dev, EV_ABS, ABS_PRESSURE, 3);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_push_event_frame(dev);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
|
||||
litest_pop_event_frame(dev);
|
||||
|
||||
litest_touch_up(dev, 0);
|
||||
litest_touch_up(dev, 1);
|
||||
libinput_dispatch(li);
|
||||
litest_timeout_tap();
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_3fg_tap_hover_btntool)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
|
||||
if (libevdev_get_abs_maximum(dev->evdev, ABS_MT_SLOT) >= 2)
|
||||
return;
|
||||
|
||||
/* libinput doesn't export when it uses pressure detection, so we
|
||||
* need to reconstruct this here. Specifically, semi-mt devices are
|
||||
* non-mt in libinput, so if they have ABS_PRESSURE, they'll use it.
|
||||
*/
|
||||
if (libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_PRESSURE))
|
||||
return;
|
||||
|
||||
if (libevdev_has_property(dev->evdev, INPUT_PROP_SEMI_MT) &&
|
||||
libevdev_has_event_code(dev->evdev, EV_ABS, ABS_PRESSURE))
|
||||
return;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
litest_enable_edge_scroll(dev);
|
||||
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 50, 50);
|
||||
litest_touch_down(dev, 1, 70, 50);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_touch_move_to(dev, 0, 50, 50, 50, 70, 10, 0);
|
||||
litest_touch_move_to(dev, 1, 70, 50, 50, 70, 10, 0);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* drop below the pressure threshold in the same frame as starting a
|
||||
* third touch */
|
||||
litest_event(dev, EV_KEY, BTN_TOUCH, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_push_event_frame(dev);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
|
||||
litest_pop_event_frame(dev);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_touch_up(dev, 0);
|
||||
litest_touch_up(dev, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_3fg_tap_btntool)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -3273,6 +3380,8 @@ litest_setup_tests_touchpad_tap(void)
|
|||
litest_add_ranged("tap-3fg:3fg", touchpad_3fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH, &tap_map_range);
|
||||
litest_add("tap-3fg:3fg", touchpad_3fg_tap_tap_again, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("tap-3fg:3fg", touchpad_3fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("tap-3fg:3fg", touchpad_3fg_tap_hover_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("tap-3fg:3fg", touchpad_3fg_tap_pressure_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add_for_device("tap-3fg:3fg", touchpad_3fg_tap_btntool_pointerjump, LITEST_SYNAPTICS_TOPBUTTONPAD);
|
||||
litest_add("tap-4fg:4fg", touchpad_4fg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
|
||||
litest_add("tap-4fg:4fg", touchpad_4fg_tap_quickrelease, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_SEMI_MT);
|
||||
|
|
|
|||
|
|
@ -5423,6 +5423,72 @@ START_TEST(touchpad_pressure_tap_2fg_1fg_light)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(touchpad_pressure_btntool)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
struct axis_replacement axes[] = {
|
||||
{ ABS_MT_PRESSURE, 5 },
|
||||
{ ABS_PRESSURE, 5 },
|
||||
{ -1, 0 }
|
||||
};
|
||||
|
||||
/* we only have tripletap, can't test 4 slots because nothing will
|
||||
* happen */
|
||||
if (libevdev_get_num_slots(dev->evdev) != 2)
|
||||
return;
|
||||
|
||||
if (!touchpad_has_pressure(dev))
|
||||
return;
|
||||
|
||||
litest_enable_tap(dev->libinput_device);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* Two light touches down, doesn't count */
|
||||
litest_touch_down_extended(dev, 0, 40, 50, axes);
|
||||
litest_touch_down_extended(dev, 1, 45, 50, axes);
|
||||
libinput_dispatch(li);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* Tripletap but since no finger is logically down, it doesn't count */
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
/* back to two fingers */
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
/* make one finger real */
|
||||
litest_touch_move_to(dev, 0, 40, 50, 41, 52, 10, 10);
|
||||
litest_drain_events(li);
|
||||
|
||||
/* tripletap should now be 3 fingers tap */
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 0);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, 1);
|
||||
litest_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, 0);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_timeout_tap();
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_PRESSED);
|
||||
litest_assert_button_event(li,
|
||||
BTN_MIDDLE,
|
||||
LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static inline bool
|
||||
touchpad_has_touch_size(struct litest_device *dev)
|
||||
{
|
||||
|
|
@ -5805,7 +5871,8 @@ litest_setup_tests_touchpad(void)
|
|||
litest_add("touchpad:pressure", touchpad_pressure_2fg_st, LITEST_TOUCHPAD|LITEST_SINGLE_TOUCH, LITEST_ANY);
|
||||
litest_add("touchpad:pressure", touchpad_pressure_tap, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:pressure", touchpad_pressure_tap_2fg, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:pressure", touchpad_pressure_tap_2fg_1fg_light, LITEST_TOUCHPAD, LITEST_ANY);
|
||||
litest_add("touchpad:pressure", touchpad_pressure_tap_2fg_1fg_light, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
litest_add("touchpad:pressure", touchpad_pressure_btntool, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
|
||||
|
||||
litest_add("touchpad:touch-size", touchpad_touch_size, LITEST_APPLE_CLICKPAD, LITEST_ANY);
|
||||
litest_add("touchpad:touch-size", touchpad_touch_size_2fg, LITEST_APPLE_CLICKPAD, LITEST_ANY);
|
||||
|
|
|
|||
|
|
@ -394,6 +394,47 @@ START_TEST(udev_suspend_resume)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(udev_resume_before_seat)
|
||||
{
|
||||
struct libinput *li;
|
||||
struct udev *udev;
|
||||
int rc;
|
||||
|
||||
udev = udev_new();
|
||||
ck_assert(udev != NULL);
|
||||
|
||||
li = libinput_udev_create_context(&simple_interface, NULL, udev);
|
||||
ck_assert(li != NULL);
|
||||
|
||||
rc = libinput_resume(li);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
|
||||
libinput_unref(li);
|
||||
udev_unref(udev);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(udev_suspend_resume_before_seat)
|
||||
{
|
||||
struct libinput *li;
|
||||
struct udev *udev;
|
||||
int rc;
|
||||
|
||||
udev = udev_new();
|
||||
ck_assert(udev != NULL);
|
||||
|
||||
li = libinput_udev_create_context(&simple_interface, NULL, udev);
|
||||
ck_assert(li != NULL);
|
||||
|
||||
libinput_suspend(li);
|
||||
rc = libinput_resume(li);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
|
||||
libinput_unref(li);
|
||||
udev_unref(udev);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(udev_device_sysname)
|
||||
{
|
||||
struct libinput *li;
|
||||
|
|
@ -619,6 +660,8 @@ litest_setup_tests_udev(void)
|
|||
litest_add_for_device("udev:suspend", udev_double_suspend, LITEST_SYNAPTICS_CLICKPAD_X220);
|
||||
litest_add_for_device("udev:suspend", udev_double_resume, LITEST_SYNAPTICS_CLICKPAD_X220);
|
||||
litest_add_for_device("udev:suspend", udev_suspend_resume, LITEST_SYNAPTICS_CLICKPAD_X220);
|
||||
litest_add_for_device("udev:suspend", udev_resume_before_seat, LITEST_SYNAPTICS_CLICKPAD_X220);
|
||||
litest_add_for_device("udev:suspend", udev_suspend_resume_before_seat, LITEST_SYNAPTICS_CLICKPAD_X220);
|
||||
litest_add_for_device("udev:device events", udev_device_sysname, LITEST_SYNAPTICS_CLICKPAD_X220);
|
||||
litest_add_for_device("udev:seat", udev_seat_recycle, LITEST_SYNAPTICS_CLICKPAD_X220);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# This does not honor $bindir properly, because we cannot get to it
|
||||
# here. Does anyone build to something but prefix/bin?
|
||||
#
|
||||
bindir="${DESTDIR}/${MESON_INSTALL_PREFIX}/bin"
|
||||
mkdir -p "$bindir"
|
||||
|
||||
bindir="${DESTDIR}${1}"
|
||||
|
||||
# Do not create bindir, because if it is not there now, we have a problem
|
||||
cp "${MESON_SOURCE_ROOT}/tools/libinput-list-devices.compat" "${bindir}/libinput-list-devices"
|
||||
cp "${MESON_SOURCE_ROOT}/tools/libinput-debug-events.compat" "${bindir}/libinput-debug-events"
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ class Device(object):
|
|||
ud = pyudev.Devices.from_device_file(context, self.path)
|
||||
v = ud.get('LIBINPUT_ATTR_TOUCH_SIZE_RANGE')
|
||||
if v:
|
||||
self.up, self.down = colon_tuple(v)
|
||||
self.down, self.up = colon_tuple(v)
|
||||
|
||||
v = ud.get('LIBINPUT_ATTR_PALM_SIZE_THRESHOLD')
|
||||
if v:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
#!/usr/bin/env python3
|
||||
# vim: set expandtab shiftwidth=4:
|
||||
# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
|
||||
#
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ main(int argc, char **argv)
|
|||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "h", opts, &option_index);
|
||||
c = getopt_long(argc, argv, "+h", opts, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -59,8 +59,10 @@ libinput:name:*Apple Inc. Apple Internal Keyboard*:dmi:*
|
|||
libinput:mouse:input:b0005v05ACp030D*
|
||||
LIBINPUT_MODEL_APPLE_MAGICMOUSE=1
|
||||
|
||||
# Magic Trackpad
|
||||
libinput:touchpad:input:b0005v05ACp030E*
|
||||
LIBINPUT_ATTR_SIZE_HINT=130x110
|
||||
LIBINPUT_ATTR_TOUCH_SIZE_RANGE=60:40
|
||||
|
||||
libinput:touchpad:input:b0003v05ACp021A*
|
||||
LIBINPUT_MODEL_APPLE_TOUCHPAD_ONEBUTTON=1
|
||||
|
|
@ -229,6 +231,10 @@ libinput:name:*Lid Switch*:dmi:*svnMicrosoftCorporation:pnSurface3:*
|
|||
libinput:name:*Microsoft Surface Type Cover Keyboard*:dmi:*svnMicrosoftCorporation:pnSurface3:*
|
||||
LIBINPUT_ATTR_KEYBOARD_INTEGRATION=internal
|
||||
|
||||
# Microsoft Microsoft® Nano Transceiver v2.0"
|
||||
libinput:mouse:input:b0003v045Ep0800*
|
||||
LIBINPUT_MODEL_MS_NANO_TRANSCEIVER=1
|
||||
|
||||
##########################################
|
||||
# Razer
|
||||
##########################################
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue