mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-27 19:40:08 +01:00
Merge branch 'master' into tablet-support
This commit is contained in:
commit
9e705bf334
61 changed files with 1732 additions and 284 deletions
10
configure.ac
10
configure.ac
|
|
@ -194,6 +194,12 @@ AM_CONDITIONAL(HAVE_VALGRIND, [test "x$VALGRIND" != "x"])
|
|||
AM_CONDITIONAL(BUILD_TESTS, [test "x$build_tests" = "xyes"])
|
||||
AM_CONDITIONAL(BUILD_DOCS, [test "x$build_documentation" = "xyes"])
|
||||
|
||||
# Used by the udev rules so we can use callouts during testing without
|
||||
# installing everything first. Default is the empty string so the installed
|
||||
# rule will use udev's default path. Override is in udev/Makefile.am
|
||||
AC_SUBST(UDEV_TEST_PATH, "")
|
||||
AC_PATH_PROG(SED, [sed])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
doc/Makefile
|
||||
doc/libinput.doxygen
|
||||
|
|
@ -202,7 +208,9 @@ AC_CONFIG_FILES([Makefile
|
|||
src/libinput-version.h
|
||||
test/Makefile
|
||||
tools/Makefile
|
||||
udev/Makefile])
|
||||
udev/Makefile
|
||||
udev/80-libinput-device-groups.rules
|
||||
udev/90-libinput-model-quirks.rules])
|
||||
AC_CONFIG_FILES([test/symbols-leak-test],
|
||||
[chmod +x test/symbols-leak-test])
|
||||
AC_OUTPUT
|
||||
|
|
|
|||
|
|
@ -67,6 +67,10 @@ to normalize them.
|
|||
<dd><b>This prefix is reserved as private API, do not use.</b>. See @ref
|
||||
model_specific_configuration for details.
|
||||
</dd>
|
||||
<dt>LIBINPUT_ATTR_*</dt>
|
||||
<dd><b>This prefix is reserved as private API, do not use.</b>. See @ref
|
||||
model_specific_configuration for details.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
Below is an example udev rule to assign "seat1" to a device from vendor
|
||||
|
|
@ -103,13 +107,13 @@ ENV{ID_MODEL_ID}=="034b", ENV{ID_INPUT_TOUCHPAD}="", ENV{ID_INPUT_TABLET}="1"
|
|||
|
||||
@section model_specific_configuration Model-specific configuration
|
||||
|
||||
libinput reserves the property prefix <b>LIBINPUT_MODEL_</b> for
|
||||
model-specific configuration. <b>This prefix is reserved as private API, do
|
||||
not use.</b>
|
||||
libinput reserves the property prefixes <b>LIBINPUT_MODEL_</b> and
|
||||
<b>LIBINPUT_ATTR_*</b> for model-specific configuration. <b>These prefixes
|
||||
are reserved as private API, do not use.</b>
|
||||
|
||||
The effect of this property may be to enable or disable certain
|
||||
The effect of these properties may be to enable or disable certain
|
||||
features on a specific device or set of devices, to change configuration
|
||||
defaults or any other reason. The effects of setting this property, the
|
||||
defaults or any other reason. The effects of setting these properties, the
|
||||
format of the property and the value of the property are subject to change
|
||||
at any time.
|
||||
|
||||
|
|
|
|||
|
|
@ -55,10 +55,8 @@ scroll).
|
|||
Due to the layout of the edges, diagonal scrolling is not possible. The
|
||||
behavior of edge scrolling using both edges at the same time is undefined.
|
||||
|
||||
Edge scrolling conflicts with @ref clickpad_softbuttons and is
|
||||
not usually available on clickpads. See
|
||||
http://who-t.blogspot.com.au/2015/03/why-libinput-doesnt-support-edge.html
|
||||
for details.
|
||||
Edge scrolling overlaps with @ref clickpad_softbuttons. A physical click on
|
||||
a clickpad ends scrolling.
|
||||
|
||||
@section button_scrolling On-Button scrolling
|
||||
|
||||
|
|
|
|||
|
|
@ -1179,5 +1179,23 @@
|
|||
[Not supported by viewer]</text>
|
||||
</switch>
|
||||
</g>
|
||||
<path d="M 2095.54 407 C 2098.34 403.86 2102.32 402.05 2106.52 402 L 2140.49 402 C 2144.69 402.05 2148.67 403.86 2151.47 407 L 2171.45 430 C 2172.01 431.28 2172.01 432.72 2171.45 434 L 2151.47 457 C 2148.67 460.14 2144.69 461.95 2140.49 462 L 2106.52 462 C 2102.32 461.95 2098.34 460.14 2095.54 457 L 2075.56 434 C 2075 432.72 2075 431.28 2075.56 430 L 2095.54 407 Z" fill="#ff99cc" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
|
||||
<text x="2123.25" y="435.75">
|
||||
thumb</text>
|
||||
</g>
|
||||
<path d="M 1801.42 332 L 2068.92 415.05" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 2073.93 416.61 L 2066.21 417.88 L 2068.92 415.05 L 2068.28 411.19 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 2152.5 488.7 C 2168.62 494.91 2186.38 494.91 2202.5 488.7 C 2218.62 482.5 2236.38 482.5 2252.5 488.7 L 2252.5 541.28 C 2236.38 535.08 2218.62 535.08 2202.5 541.28 C 2186.38 547.49 2168.62 547.49 2152.5 541.28 L 2152.5 488.7 Z" fill="#ffd966" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
|
||||
<text x="2202.25" y="518.75">
|
||||
TOUCH_DEAD</text>
|
||||
</g>
|
||||
<path d="M 2152.05 462 L 2167.18 477.89" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 2170.8 481.69 L 2163.43 479.03 L 2167.18 477.89 L 2168.5 474.21 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 2217.81 547.5 L 2324.65 774.24" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 2326.89 778.99 L 2320.74 774.15 L 2324.65 774.24 L 2327.07 771.16 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 1959.61 577 L 2084.82 466.22" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
<path d="M 2088.75 462.74 L 2085.83 470 L 2084.82 466.22 L 2081.19 464.76 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 122 KiB |
|
|
@ -525,20 +525,19 @@ tp_init_softbuttons(struct tp_dispatch *tp,
|
|||
absinfo_y = device->abs.absinfo_y;
|
||||
|
||||
xoffset = absinfo_x->minimum,
|
||||
yoffset = absinfo_y->minimum;
|
||||
yoffset = absinfo_y->minimum,
|
||||
yres = absinfo_y->resolution;
|
||||
width = device->abs.dimensions.x;
|
||||
height = device->abs.dimensions.y;
|
||||
|
||||
/* button height: 10mm or 15% of the touchpad height,
|
||||
/* button height: 10mm or 15% orf the touchpad height,
|
||||
whichever is smaller */
|
||||
if (!device->abs.fake_resolution && (height * 0.15/yres) > 10) {
|
||||
if ((height * 0.15)/yres > 10) {
|
||||
tp->buttons.bottom_area.top_edge =
|
||||
absinfo_y->maximum - 10 * yres;
|
||||
absinfo_y->maximum - 10 * yres;
|
||||
} else {
|
||||
tp->buttons.bottom_area.top_edge = height * .85 + yoffset;
|
||||
}
|
||||
|
||||
tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
|
||||
}
|
||||
|
||||
|
|
@ -547,7 +546,7 @@ tp_init_top_softbuttons(struct tp_dispatch *tp,
|
|||
struct evdev_device *device,
|
||||
double topbutton_size_mult)
|
||||
{
|
||||
int width, height;
|
||||
int width;
|
||||
const struct input_absinfo *absinfo_x, *absinfo_y;
|
||||
int xoffset, yoffset;
|
||||
int yres;
|
||||
|
|
@ -559,7 +558,6 @@ tp_init_top_softbuttons(struct tp_dispatch *tp,
|
|||
yoffset = absinfo_y->minimum;
|
||||
yres = absinfo_y->resolution;
|
||||
width = device->abs.dimensions.x;
|
||||
height = device->abs.dimensions.y;
|
||||
|
||||
if (tp->buttons.has_topbuttons) {
|
||||
/* T440s has the top button line 5mm from the top, event
|
||||
|
|
@ -567,14 +565,8 @@ tp_init_top_softbuttons(struct tp_dispatch *tp,
|
|||
top - which maps to 15%. We allow the caller to enlarge the
|
||||
area using a multiplier for the touchpad disabled case. */
|
||||
double topsize_mm = 10 * topbutton_size_mult;
|
||||
double topsize_pct = .15 * topbutton_size_mult;
|
||||
|
||||
if (!device->abs.fake_resolution) {
|
||||
tp->buttons.top_area.bottom_edge =
|
||||
yoffset + topsize_mm * yres;
|
||||
} else {
|
||||
tp->buttons.top_area.bottom_edge = height * topsize_pct + yoffset;
|
||||
}
|
||||
tp->buttons.top_area.bottom_edge = yoffset + topsize_mm * yres;
|
||||
tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
|
||||
tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
|
||||
} else {
|
||||
|
|
@ -713,8 +705,6 @@ tp_init_buttons(struct tp_dispatch *tp,
|
|||
{
|
||||
struct libinput *libinput = tp_libinput_context(tp);
|
||||
struct tp_touch *t;
|
||||
int width, height;
|
||||
double diagonal;
|
||||
const struct input_absinfo *absinfo_x, *absinfo_y;
|
||||
|
||||
tp->buttons.is_clickpad = libevdev_has_property(device->evdev,
|
||||
|
|
@ -738,19 +728,9 @@ tp_init_buttons(struct tp_dispatch *tp,
|
|||
absinfo_x = device->abs.absinfo_x;
|
||||
absinfo_y = device->abs.absinfo_y;
|
||||
|
||||
/* pinned-finger motion threshold, see tp_unpin_finger.
|
||||
The MAGIC for resolution-less touchpads ends up as 2% of the diagonal */
|
||||
if (device->abs.fake_resolution) {
|
||||
const double BUTTON_MOTION_MAGIC = 0.007;
|
||||
width = device->abs.dimensions.x;
|
||||
height = device->abs.dimensions.y;
|
||||
diagonal = sqrt(width*width + height*height);
|
||||
tp->buttons.motion_dist.x_scale_coeff = diagonal * BUTTON_MOTION_MAGIC;
|
||||
tp->buttons.motion_dist.y_scale_coeff = diagonal * BUTTON_MOTION_MAGIC;
|
||||
} else {
|
||||
tp->buttons.motion_dist.x_scale_coeff = 1.0/absinfo_x->resolution;
|
||||
tp->buttons.motion_dist.y_scale_coeff = 1.0/absinfo_y->resolution;
|
||||
}
|
||||
/* pinned-finger motion threshold, see tp_unpin_finger. */
|
||||
tp->buttons.motion_dist.x_scale_coeff = 1.0/absinfo_x->resolution;
|
||||
tp->buttons.motion_dist.y_scale_coeff = 1.0/absinfo_y->resolution;
|
||||
|
||||
tp->buttons.config_method.get_methods = tp_button_config_click_get_methods;
|
||||
tp->buttons.config_method.set_method = tp_button_config_click_set_method;
|
||||
|
|
@ -825,33 +805,53 @@ tp_check_clickfinger_distance(struct tp_dispatch *tp,
|
|||
struct tp_touch *t2)
|
||||
{
|
||||
double x, y;
|
||||
int within_distance = 0;
|
||||
int xres, yres;
|
||||
int bottom_threshold;
|
||||
|
||||
if (!t1 || !t2)
|
||||
return 0;
|
||||
|
||||
if (t1->is_thumb || t2->is_thumb)
|
||||
return 0;
|
||||
|
||||
x = abs(t1->point.x - t2->point.x);
|
||||
y = abs(t1->point.y - t2->point.y);
|
||||
|
||||
/* no resolution, so let's assume they're close enough together if
|
||||
they're within 30% of the touchpad width or height */
|
||||
if (tp->device->abs.fake_resolution) {
|
||||
int w, h;
|
||||
w = tp->device->abs.dimensions.x;
|
||||
h = tp->device->abs.dimensions.y;
|
||||
xres = tp->device->abs.absinfo_x->resolution;
|
||||
yres = tp->device->abs.absinfo_y->resolution;
|
||||
x /= xres;
|
||||
y /= yres;
|
||||
|
||||
return (x < w * 0.3 && y < h * 0.3) ? 1 : 0;
|
||||
} else {
|
||||
/* maximum spread is 40mm horiz, 20mm vert. Anything wider than that
|
||||
* is probably a gesture. The y spread is small so we ignore clicks
|
||||
* with thumbs at the bottom of the touchpad while the pointer
|
||||
* moving finger is still on the pad */
|
||||
/* maximum horiz spread is 40mm horiz, 30mm vert, anything wider
|
||||
* than that is probably a gesture. */
|
||||
if (x > 40 || y > 30)
|
||||
goto out;
|
||||
|
||||
x /= tp->device->abs.absinfo_x->resolution;
|
||||
y /= tp->device->abs.absinfo_y->resolution;
|
||||
within_distance = 1;
|
||||
|
||||
return (x < 40 && y < 20) ? 1 : 0;
|
||||
}
|
||||
/* if y spread is <= 20mm, they're definitely together. */
|
||||
if (y <= 20)
|
||||
goto out;
|
||||
|
||||
/* if they're vertically spread between 20-40mm, they're not
|
||||
* together if:
|
||||
* - the touchpad's vertical size is >50mm, anything smaller is
|
||||
* unlikely to have a thumb resting on it
|
||||
* - and one of the touches is in the bottom 20mm of the touchpad
|
||||
* and the other one isn't
|
||||
*/
|
||||
|
||||
if (tp->device->abs.dimensions.y/yres < 50)
|
||||
goto out;
|
||||
|
||||
bottom_threshold = tp->device->abs.absinfo_y->maximum - 20 * yres;
|
||||
if ((t1->point.y > bottom_threshold) !=
|
||||
(t2->point.y > bottom_threshold))
|
||||
within_distance = 0;
|
||||
|
||||
out:
|
||||
return within_distance;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
|
|
@ -941,6 +941,10 @@ tp_notify_clickpadbutton(struct tp_dispatch *tp,
|
|||
if (tp->device->suspended)
|
||||
return 0;
|
||||
|
||||
/* A button click always terminates edge scrolling, even if we
|
||||
* don't end up sending a button event. */
|
||||
tp_edge_scroll_stop_events(tp, time);
|
||||
|
||||
/*
|
||||
* If the user has requested clickfinger replace the button chosen
|
||||
* by the softbutton code with one based on the number of fingers.
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
|
||||
#define CASE_RETURN_STRING(a) case a: return #a
|
||||
|
||||
#define DEFAULT_SCROLL_LOCK_TIMEOUT 300 /* ms */
|
||||
/* Use a reasonably large threshold until locked into scrolling mode, to
|
||||
avoid accidentally locking in scrolling mode when trying to use the entire
|
||||
touchpad to move the pointer. The user can wait for the timeout to trigger
|
||||
|
|
@ -92,6 +91,23 @@ tp_touch_get_edge(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
return edge;
|
||||
}
|
||||
|
||||
static inline void
|
||||
tp_edge_scroll_set_timer(struct tp_dispatch *tp,
|
||||
struct tp_touch *t)
|
||||
{
|
||||
const int DEFAULT_SCROLL_LOCK_TIMEOUT = 300; /* ms */
|
||||
/* if we use software buttons, we disable timeout-based
|
||||
* edge scrolling. A finger resting on the button areas is
|
||||
* likely there to trigger a button event.
|
||||
*/
|
||||
if (tp->buttons.click_method ==
|
||||
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS)
|
||||
return;
|
||||
|
||||
libinput_timer_set(&t->scroll.timer,
|
||||
t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_edge_scroll_set_state(struct tp_dispatch *tp,
|
||||
struct tp_touch *t,
|
||||
|
|
@ -108,8 +124,7 @@ tp_edge_scroll_set_state(struct tp_dispatch *tp,
|
|||
case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
|
||||
t->scroll.edge = tp_touch_get_edge(tp, t);
|
||||
t->scroll.initial = t->point;
|
||||
libinput_timer_set(&t->scroll.timer,
|
||||
t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
|
||||
tp_edge_scroll_set_timer(tp, t);
|
||||
break;
|
||||
case EDGE_SCROLL_TOUCH_STATE_EDGE:
|
||||
break;
|
||||
|
|
@ -290,8 +305,7 @@ tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device)
|
|||
default:
|
||||
/* For elantech and synaptics, note for lenovo #40 series,
|
||||
* e.g. the T440s min/max are the absolute edges, not the
|
||||
* recommended ones as usual with synaptics. But these are
|
||||
* clickpads, so N/A.
|
||||
* recommended ones as usual with synaptics.
|
||||
*/
|
||||
edge_width = width * .04;
|
||||
edge_height = height * .054;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,20 @@
|
|||
#define DEFAULT_GESTURE_SWITCH_TIMEOUT 100 /* ms */
|
||||
#define DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT 1000 /* ms */
|
||||
|
||||
#define CASE_RETURN_STRING(a) case a: return #a
|
||||
|
||||
static inline const char*
|
||||
gesture_state_to_str(enum tp_gesture_2fg_state state)
|
||||
{
|
||||
switch (state) {
|
||||
CASE_RETURN_STRING(GESTURE_2FG_STATE_NONE);
|
||||
CASE_RETURN_STRING(GESTURE_2FG_STATE_UNKNOWN);
|
||||
CASE_RETURN_STRING(GESTURE_2FG_STATE_SCROLL);
|
||||
CASE_RETURN_STRING(GESTURE_2FG_STATE_PINCH);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct normalized_coords
|
||||
tp_get_touches_delta(struct tp_dispatch *tp, bool average)
|
||||
{
|
||||
|
|
@ -380,6 +394,8 @@ tp_gesture_twofinger_handle_state_pinch(struct tp_dispatch *tp, uint64_t time)
|
|||
static void
|
||||
tp_gesture_post_twofinger(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
enum tp_gesture_2fg_state oldstate = tp->gesture.twofinger_state;
|
||||
|
||||
if (tp->gesture.twofinger_state == GESTURE_2FG_STATE_NONE)
|
||||
tp->gesture.twofinger_state =
|
||||
tp_gesture_twofinger_handle_state_none(tp, time);
|
||||
|
|
@ -395,6 +411,11 @@ tp_gesture_post_twofinger(struct tp_dispatch *tp, uint64_t time)
|
|||
if (tp->gesture.twofinger_state == GESTURE_2FG_STATE_PINCH)
|
||||
tp->gesture.twofinger_state =
|
||||
tp_gesture_twofinger_handle_state_pinch(tp, time);
|
||||
|
||||
log_debug(tp_libinput_context(tp),
|
||||
"gesture state: %s → %s\n",
|
||||
gesture_state_to_str(oldstate),
|
||||
gesture_state_to_str(tp->gesture.twofinger_state));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -525,11 +546,34 @@ tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
{
|
||||
unsigned int active_touches = 0;
|
||||
struct tp_touch *t;
|
||||
uint32_t old_thumb_mask, thumb_mask = 0;
|
||||
int i = 0;
|
||||
|
||||
tp_for_each_touch(tp, t)
|
||||
tp_for_each_touch(tp, t) {
|
||||
if (tp_touch_active(tp, t))
|
||||
active_touches++;
|
||||
|
||||
if (t->is_thumb)
|
||||
thumb_mask |= 1 << i;
|
||||
i++;
|
||||
}
|
||||
|
||||
old_thumb_mask = tp->gesture.thumb_mask;
|
||||
tp->gesture.thumb_mask = thumb_mask;
|
||||
|
||||
/* active touches does not include thumb touches, need to count those
|
||||
* separately, in a bitmask.
|
||||
* then, if the finger count changes and/or the thumb count changes
|
||||
* -> cancel gesture.
|
||||
*/
|
||||
if (thumb_mask != old_thumb_mask) {
|
||||
/* if a thumb is detected during a gesture, that gesture is
|
||||
* cancelled and the user effectively needs to restart. we
|
||||
* could be smarter, but the complexity isn't worth it */
|
||||
tp_gesture_cancel(tp, time);
|
||||
return;
|
||||
}
|
||||
|
||||
if (active_touches != tp->gesture.finger_count) {
|
||||
/* If all fingers are lifted immediately end the gesture */
|
||||
if (active_touches == 0) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ enum tap_event {
|
|||
TAP_EVENT_RELEASE,
|
||||
TAP_EVENT_BUTTON,
|
||||
TAP_EVENT_TIMEOUT,
|
||||
TAP_EVENT_THUMB,
|
||||
};
|
||||
|
||||
/*****************************************
|
||||
|
|
@ -93,6 +94,7 @@ tap_event_to_str(enum tap_event event)
|
|||
CASE_RETURN_STRING(TAP_EVENT_RELEASE);
|
||||
CASE_RETURN_STRING(TAP_EVENT_TIMEOUT);
|
||||
CASE_RETURN_STRING(TAP_EVENT_BUTTON);
|
||||
CASE_RETURN_STRING(TAP_EVENT_THUMB);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -166,6 +168,10 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
log_bug_libinput(libinput,
|
||||
"invalid tap event, no fingers down, no thumb\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -193,6 +199,12 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
tp->tap.state = TAP_STATE_IDLE;
|
||||
t->tap.is_thumb = true;
|
||||
t->tap.state = TAP_TOUCH_STATE_DEAD;
|
||||
tp_tap_clear_timer(tp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +228,11 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
tp->tap.state = TAP_STATE_IDLE;
|
||||
t->tap.is_thumb = true;
|
||||
t->tap.state = TAP_TOUCH_STATE_DEAD;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -244,6 +261,8 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp,
|
|||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -275,6 +294,8 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -299,6 +320,8 @@ tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -328,6 +351,8 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,6 +376,8 @@ tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_EVENT_BUTTON:
|
||||
tp->tap.state = TAP_STATE_DEAD;
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -375,6 +402,8 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
|
|||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -408,6 +437,8 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp,
|
|||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -433,6 +464,8 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp,
|
|||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -459,6 +492,8 @@ tp_tap_dragging_tap_handle_event(struct tp_dispatch *tp,
|
|||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -484,6 +519,8 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp,
|
|||
tp->tap.state = TAP_STATE_DEAD;
|
||||
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -518,6 +555,8 @@ tp_tap_multitap_handle_event(struct tp_dispatch *tp,
|
|||
tp->tap.state = TAP_STATE_IDLE;
|
||||
tp_tap_clear_timer(tp);
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -556,6 +595,8 @@ tp_tap_multitap_down_handle_event(struct tp_dispatch *tp,
|
|||
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
|
||||
tp_tap_clear_timer(tp);
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -576,6 +617,8 @@ tp_tap_dead_handle_event(struct tp_dispatch *tp,
|
|||
case TAP_EVENT_TIMEOUT:
|
||||
case TAP_EVENT_BUTTON:
|
||||
break;
|
||||
case TAP_EVENT_THUMB:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -691,7 +734,20 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
|
||||
t->tap.state = TAP_TOUCH_STATE_DEAD;
|
||||
|
||||
/* If a touch was considered thumb for tapping once, we
|
||||
* ignore it for the rest of lifetime */
|
||||
if (t->tap.is_thumb)
|
||||
continue;
|
||||
|
||||
if (t->state == TOUCH_BEGIN) {
|
||||
/* The simple version: if a touch is a thumb on
|
||||
* begin we ignore it. All other thumb touches
|
||||
* follow the normal tap state for now */
|
||||
if (t->is_thumb) {
|
||||
t->tap.is_thumb = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
t->tap.state = TAP_TOUCH_STATE_TOUCH;
|
||||
t->tap.initial = t->point;
|
||||
tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time);
|
||||
|
|
@ -718,6 +774,10 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
|
|||
}
|
||||
|
||||
tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time);
|
||||
} else if (tp->tap.state != TAP_STATE_IDLE &&
|
||||
t->is_thumb &&
|
||||
!t->tap.is_thumb) {
|
||||
tp_tap_handle_event(tp, t, TAP_EVENT_THUMB, time);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,6 +212,8 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
|||
t->millis = time;
|
||||
tp->nfingers_down++;
|
||||
t->palm.time = time;
|
||||
t->is_thumb = false;
|
||||
t->tap.is_thumb = false;
|
||||
assert(tp->nfingers_down >= 1);
|
||||
}
|
||||
|
||||
|
|
@ -314,6 +316,9 @@ tp_process_absolute(struct tp_dispatch *tp,
|
|||
else
|
||||
tp_end_sequence(tp, t, time);
|
||||
break;
|
||||
case ABS_MT_PRESSURE:
|
||||
t->pressure = e->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -461,6 +466,7 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
|
|||
return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
|
||||
t->palm.state == PALM_NONE &&
|
||||
!t->pinned.is_pinned &&
|
||||
!t->is_thumb &&
|
||||
tp_button_touch_active(tp, t) &&
|
||||
tp_edge_scroll_touch_active(tp, t);
|
||||
}
|
||||
|
|
@ -496,8 +502,7 @@ tp_palm_detect_dwt(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
|
|||
return 1;
|
||||
} else if (!tp->dwt.keyboard_active &&
|
||||
t->state == TOUCH_UPDATE &&
|
||||
t->palm.state == PALM_TYPING)
|
||||
{
|
||||
t->palm.state == PALM_TYPING) {
|
||||
/* If a touch has started before the first or after the last
|
||||
key press, release it on timeout. Benefit: a palm rested
|
||||
while typing on the touchpad will be ignored, but a touch
|
||||
|
|
@ -603,6 +608,33 @@ out:
|
|||
t->palm.state == PALM_TYPING ? "typing" : "trackpoint");
|
||||
}
|
||||
|
||||
static void
|
||||
tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t)
|
||||
{
|
||||
/* once a thumb, always a thumb */
|
||||
if (!tp->thumb.detect_thumbs || t->is_thumb)
|
||||
return;
|
||||
|
||||
/* Note: a thumb at the edge of the touchpad won't trigger the
|
||||
* threshold, the surface areas is usually too small.
|
||||
*/
|
||||
if (t->pressure < tp->thumb.threshold)
|
||||
return;
|
||||
|
||||
t->is_thumb = true;
|
||||
|
||||
/* now what? we marked it as thumb, so:
|
||||
*
|
||||
* - pointer motion must ignore this touch
|
||||
* - clickfinger must ignore this touch for finger count
|
||||
* - software buttons are unaffected
|
||||
* - edge scrolling unaffected
|
||||
* - gestures: cancel
|
||||
* - tapping: honour thumb on begin, ignore it otherwise for now,
|
||||
* this gets a tad complicated otherwise
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
tp_unhover_abs_distance(struct tp_dispatch *tp, uint64_t time)
|
||||
{
|
||||
|
|
@ -721,6 +753,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
|
|||
if (!t->dirty)
|
||||
continue;
|
||||
|
||||
tp_thumb_detect(tp, t);
|
||||
tp_palm_detect(tp, t, time);
|
||||
|
||||
tp_motion_hysteresis(tp, t);
|
||||
|
|
@ -1319,17 +1352,8 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
|
|||
* and y resolution, so that a circle on the
|
||||
* touchpad does not turn into an elipse on the screen.
|
||||
*/
|
||||
if (!tp->device->abs.fake_resolution) {
|
||||
tp->accel.x_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_x;
|
||||
tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
|
||||
} else {
|
||||
/*
|
||||
* For touchpads where the driver does not provide resolution, fall
|
||||
* back to scaling motion events based on the diagonal size in units.
|
||||
*/
|
||||
tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
|
||||
tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
|
||||
}
|
||||
tp->accel.x_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_x;
|
||||
tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
|
||||
|
||||
switch (tp->device->model) {
|
||||
case EVDEV_MODEL_LENOVO_X230:
|
||||
|
|
@ -1351,14 +1375,11 @@ tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
|
|||
{
|
||||
struct evdev_device *evdev = (struct evdev_device*)device;
|
||||
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
|
||||
uint32_t methods = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
|
||||
uint32_t methods = LIBINPUT_CONFIG_SCROLL_EDGE;
|
||||
|
||||
if (tp->ntouches >= 2)
|
||||
methods |= LIBINPUT_CONFIG_SCROLL_2FG;
|
||||
|
||||
if (!tp->buttons.is_clickpad)
|
||||
methods |= LIBINPUT_CONFIG_SCROLL_EDGE;
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
|
@ -1481,6 +1502,30 @@ tp_init_sendevents(struct tp_dispatch *tp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tp_init_thumb(struct tp_dispatch *tp)
|
||||
{
|
||||
struct evdev_device *device = tp->device;
|
||||
const struct input_absinfo *abs;
|
||||
|
||||
abs = libevdev_get_abs_info(device->evdev, ABS_MT_PRESSURE);
|
||||
if (!abs)
|
||||
return 0;
|
||||
|
||||
if (abs->maximum - abs->minimum < 255)
|
||||
return 0;
|
||||
|
||||
/* The touchpads we looked at so far have a clear thumb threshold of
|
||||
* ~100, you don't reach that with a normal finger interaction.
|
||||
* Note: "thumb" means massive touch that should not interact, not
|
||||
* "using the tip of my thumb for a pinch gestures".
|
||||
*/
|
||||
tp->thumb.threshold = 100;
|
||||
tp->thumb.detect_thumbs = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tp_sanity_check(struct tp_dispatch *tp,
|
||||
struct evdev_device *device)
|
||||
|
|
@ -1505,12 +1550,50 @@ error:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
tp_init_default_resolution(struct tp_dispatch *tp,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
const int touchpad_width_mm = 69, /* 1 under palm detection */
|
||||
touchpad_height_mm = 50;
|
||||
int xres, yres;
|
||||
|
||||
if (!device->abs.fake_resolution)
|
||||
return 0 ;
|
||||
|
||||
/* we only get here if
|
||||
* - the touchpad provides no resolution
|
||||
* - the udev hwdb didn't override the resoluion
|
||||
* - no ATTR_SIZE_HINT is set
|
||||
*
|
||||
* The majority of touchpads that triggers all these conditions
|
||||
* are old ones, so let's assume a small touchpad size and assume
|
||||
* that.
|
||||
*/
|
||||
log_info(tp_libinput_context(tp),
|
||||
"%s: no resolution or size hints, assuming a size of %dx%dmm\n",
|
||||
device->devname,
|
||||
touchpad_width_mm,
|
||||
touchpad_height_mm);
|
||||
|
||||
xres = device->abs.dimensions.x/touchpad_width_mm;
|
||||
yres = device->abs.dimensions.y/touchpad_height_mm;
|
||||
libevdev_set_abs_resolution(device->evdev, ABS_X, xres);
|
||||
libevdev_set_abs_resolution(device->evdev, ABS_Y, yres);
|
||||
libevdev_set_abs_resolution(device->evdev, ABS_MT_POSITION_X, xres);
|
||||
libevdev_set_abs_resolution(device->evdev, ABS_MT_POSITION_Y, yres);
|
||||
device->abs.fake_resolution = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tp_init(struct tp_dispatch *tp,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
int width, height;
|
||||
double diagonal;
|
||||
int res_x, res_y;
|
||||
|
||||
tp->base.interface = &tp_interface;
|
||||
tp->device = device;
|
||||
|
|
@ -1518,9 +1601,14 @@ tp_init(struct tp_dispatch *tp,
|
|||
if (tp_sanity_check(tp, device) != 0)
|
||||
return -1;
|
||||
|
||||
if (tp_init_default_resolution(tp, device) != 0)
|
||||
return -1;
|
||||
|
||||
if (tp_init_slots(tp, device) != 0)
|
||||
return -1;
|
||||
|
||||
res_x = tp->device->abs.absinfo_x->resolution;
|
||||
res_y = tp->device->abs.absinfo_y->resolution;
|
||||
width = device->abs.dimensions.x;
|
||||
height = device->abs.dimensions.y;
|
||||
diagonal = sqrt(width*width + height*height);
|
||||
|
|
@ -1529,18 +1617,8 @@ tp_init(struct tp_dispatch *tp,
|
|||
EV_ABS,
|
||||
ABS_MT_DISTANCE);
|
||||
|
||||
if (device->abs.fake_resolution) {
|
||||
tp->hysteresis_margin.x =
|
||||
diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
|
||||
tp->hysteresis_margin.y =
|
||||
diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
|
||||
} else {
|
||||
int res_x = tp->device->abs.absinfo_x->resolution,
|
||||
res_y = tp->device->abs.absinfo_y->resolution;
|
||||
|
||||
tp->hysteresis_margin.x = res_x/2;
|
||||
tp->hysteresis_margin.y = res_y/2;
|
||||
}
|
||||
tp->hysteresis_margin.x = res_x/2;
|
||||
tp->hysteresis_margin.y = res_y/2;
|
||||
|
||||
if (tp_init_accel(tp, diagonal) != 0)
|
||||
return -1;
|
||||
|
|
@ -1563,6 +1641,9 @@ tp_init(struct tp_dispatch *tp,
|
|||
if (tp_init_gesture(tp) != 0)
|
||||
return -1;
|
||||
|
||||
if (tp_init_thumb(tp) != 0)
|
||||
return -1;
|
||||
|
||||
device->seat_caps |= EVDEV_DEVICE_POINTER;
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -141,9 +141,11 @@ struct tp_touch {
|
|||
enum touch_state state;
|
||||
bool has_ended; /* TRACKING_ID == -1 */
|
||||
bool dirty;
|
||||
bool is_thumb;
|
||||
struct device_coords point;
|
||||
uint64_t millis;
|
||||
int distance; /* distance == 0 means touch */
|
||||
int pressure;
|
||||
|
||||
struct {
|
||||
struct device_coords samples[TOUCHPAD_HISTORY_LENGTH];
|
||||
|
|
@ -173,6 +175,7 @@ struct tp_touch {
|
|||
struct {
|
||||
enum tp_tap_touch_state state;
|
||||
struct device_coords initial;
|
||||
bool is_thumb;
|
||||
} tap;
|
||||
|
||||
struct {
|
||||
|
|
@ -234,6 +237,7 @@ struct tp_dispatch {
|
|||
double prev_scale;
|
||||
double angle;
|
||||
struct device_float_coords center;
|
||||
uint32_t thumb_mask;
|
||||
} gesture;
|
||||
|
||||
struct {
|
||||
|
|
@ -317,6 +321,11 @@ struct tp_dispatch {
|
|||
|
||||
uint64_t keyboard_last_press_time;
|
||||
} dwt;
|
||||
|
||||
struct {
|
||||
bool detect_thumbs;
|
||||
int threshold;
|
||||
} thumb;
|
||||
};
|
||||
|
||||
#define tp_for_each_touch(_tp, _t) \
|
||||
|
|
|
|||
79
src/evdev.c
79
src/evdev.c
|
|
@ -1552,19 +1552,35 @@ evdev_read_model(struct evdev_device *device)
|
|||
return m->model;
|
||||
}
|
||||
|
||||
/* Return 1 if the given resolutions have been set, or 0 otherwise */
|
||||
static inline int
|
||||
evdev_read_attr_size_prop(struct evdev_device *device,
|
||||
size_t *size_x,
|
||||
size_t *size_y)
|
||||
{
|
||||
struct udev_device *udev;
|
||||
const char *size_prop;
|
||||
|
||||
udev = device->udev_device;
|
||||
size_prop = udev_device_get_property_value(udev,
|
||||
"LIBINPUT_ATTR_SIZE_HINT");
|
||||
if (!size_prop)
|
||||
return false;
|
||||
|
||||
return parse_dimension_property(size_prop, size_x, size_y);
|
||||
}
|
||||
|
||||
/* Return 1 if the device is set to the fake resolution or 0 otherwise */
|
||||
static inline int
|
||||
evdev_fix_abs_resolution(struct evdev_device *device,
|
||||
unsigned int xcode,
|
||||
unsigned int ycode,
|
||||
int xresolution,
|
||||
int yresolution)
|
||||
unsigned int ycode)
|
||||
{
|
||||
struct libinput *libinput = device->base.seat->libinput;
|
||||
struct libevdev *evdev = device->evdev;
|
||||
const struct input_absinfo *absx, *absy;
|
||||
struct input_absinfo fixed;
|
||||
int rc = 0;
|
||||
size_t widthmm = 0, heightmm = 0;
|
||||
int xres = EVDEV_FAKE_RESOLUTION,
|
||||
yres = EVDEV_FAKE_RESOLUTION;
|
||||
|
||||
if (!(xcode == ABS_X && ycode == ABS_Y) &&
|
||||
!(xcode == ABS_MT_POSITION_X && ycode == ABS_MT_POSITION_Y)) {
|
||||
|
|
@ -1574,37 +1590,28 @@ evdev_fix_abs_resolution(struct evdev_device *device,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (xresolution == 0 || yresolution == 0 ||
|
||||
(xresolution == EVDEV_FAKE_RESOLUTION && xresolution != yresolution) ||
|
||||
(yresolution == EVDEV_FAKE_RESOLUTION && xresolution != yresolution)) {
|
||||
log_bug_libinput(libinput,
|
||||
"Invalid x/y resolutions %d/%d\n",
|
||||
xresolution, yresolution);
|
||||
return 0;
|
||||
}
|
||||
|
||||
absx = libevdev_get_abs_info(evdev, xcode);
|
||||
absy = libevdev_get_abs_info(evdev, ycode);
|
||||
|
||||
if (absx->resolution == 0 || absx->resolution == EVDEV_FAKE_RESOLUTION) {
|
||||
fixed = *absx;
|
||||
fixed.resolution = xresolution;
|
||||
/* libevdev_set_abs_info() changes the absinfo we already
|
||||
have a pointer to, no need to fetch it again */
|
||||
libevdev_set_abs_info(evdev, xcode, &fixed);
|
||||
rc = 1;
|
||||
if (absx->resolution != 0 || absy->resolution != 0)
|
||||
return 0;
|
||||
|
||||
/* Note: we *do not* override resolutions if provided by the kernel.
|
||||
* If a device needs this, add it to 60-evdev.hwdb. The libinput
|
||||
* property is only for general size hints where we can make
|
||||
* educated guesses but don't know better.
|
||||
*/
|
||||
if (evdev_read_attr_size_prop(device, &widthmm, &heightmm)) {
|
||||
xres = (absx->maximum - absx->minimum)/widthmm;
|
||||
yres = (absy->maximum - absy->minimum)/heightmm;
|
||||
}
|
||||
|
||||
if (absy->resolution == 0 || absy->resolution == EVDEV_FAKE_RESOLUTION) {
|
||||
fixed = *absy;
|
||||
fixed.resolution = yresolution;
|
||||
/* libevdev_set_abs_info() changes the absinfo we already
|
||||
have a pointer to, no need to fetch it again */
|
||||
libevdev_set_abs_info(evdev, ycode, &fixed);
|
||||
rc = 1;
|
||||
}
|
||||
/* libevdev_set_abs_resolution() changes the absinfo we already
|
||||
have a pointer to, no need to fetch it again */
|
||||
libevdev_set_abs_resolution(evdev, xcode, xres);
|
||||
libevdev_set_abs_resolution(evdev, ycode, yres);
|
||||
|
||||
return rc;
|
||||
return xres == EVDEV_FAKE_RESOLUTION;
|
||||
}
|
||||
|
||||
static enum evdev_device_udev_tags
|
||||
|
|
@ -1775,9 +1782,7 @@ evdev_configure_mt_device(struct evdev_device *device)
|
|||
|
||||
if (evdev_fix_abs_resolution(device,
|
||||
ABS_MT_POSITION_X,
|
||||
ABS_MT_POSITION_Y,
|
||||
EVDEV_FAKE_RESOLUTION,
|
||||
EVDEV_FAKE_RESOLUTION))
|
||||
ABS_MT_POSITION_Y))
|
||||
device->abs.fake_resolution = 1;
|
||||
|
||||
device->abs.absinfo_x = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X);
|
||||
|
|
@ -1902,11 +1907,7 @@ evdev_configure_device(struct evdev_device *device)
|
|||
evdev_fix_android_mt(device);
|
||||
|
||||
if (libevdev_has_event_code(evdev, EV_ABS, ABS_X)) {
|
||||
if (evdev_fix_abs_resolution(device,
|
||||
ABS_X,
|
||||
ABS_Y,
|
||||
EVDEV_FAKE_RESOLUTION,
|
||||
EVDEV_FAKE_RESOLUTION))
|
||||
if (evdev_fix_abs_resolution(device, ABS_X, ABS_Y))
|
||||
device->abs.fake_resolution = 1;
|
||||
device->abs.absinfo_x = libevdev_get_abs_info(evdev, ABS_X);
|
||||
device->abs.absinfo_y = libevdev_get_abs_info(evdev, ABS_Y);
|
||||
|
|
|
|||
|
|
@ -234,3 +234,33 @@ parse_trackpoint_accel_property(const char *prop)
|
|||
|
||||
return accel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a simple dimension string in the form of "10x40". The two
|
||||
* numbers must be positive integers in decimal notation.
|
||||
* On success, the two numbers are stored in w and h. On failure, w and h
|
||||
* are unmodified.
|
||||
*
|
||||
* @param prop The value of the property
|
||||
* @param w Returns the first component of the dimension
|
||||
* @param h Returns the second component of the dimension
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
bool
|
||||
parse_dimension_property(const char *prop, size_t *w, size_t *h)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
if (!prop)
|
||||
return false;
|
||||
|
||||
if (sscanf(prop, "%dx%d", &x, &y) != 2)
|
||||
return false;
|
||||
|
||||
if (x < 0 || y < 0)
|
||||
return false;
|
||||
|
||||
*w = (size_t)x;
|
||||
*h = (size_t)y;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
|
@ -321,6 +322,7 @@ enum ratelimit_state ratelimit_test(struct ratelimit *r);
|
|||
int parse_mouse_dpi_property(const char *prop);
|
||||
int parse_mouse_wheel_click_angle_property(const char *prop);
|
||||
double parse_trackpoint_accel_property(const char *prop);
|
||||
bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
|
||||
|
||||
static inline double
|
||||
vector_length(double x, double y)
|
||||
|
|
|
|||
|
|
@ -13,42 +13,44 @@ noinst_LTLIBRARIES = liblitest.la
|
|||
liblitest_la_SOURCES = \
|
||||
litest.h \
|
||||
litest-int.h \
|
||||
litest-alps-semi-mt.c \
|
||||
litest-alps-dualpoint.c \
|
||||
litest-atmel-hover.c \
|
||||
litest-bcm5974.c \
|
||||
litest-generic-singletouch.c \
|
||||
litest-keyboard.c \
|
||||
litest-keyboard-razer-blackwidow.c \
|
||||
litest-logitech-trackball.c \
|
||||
litest-nexus4-touch-screen.c \
|
||||
litest-mouse.c \
|
||||
litest-mouse-roccat.c \
|
||||
litest-mouse-low-dpi.c \
|
||||
litest-ms-surface-cover.c \
|
||||
litest-protocol-a-touch-screen.c \
|
||||
litest-qemu-usb-tablet.c \
|
||||
litest-synaptics.c \
|
||||
litest-synaptics-hover.c \
|
||||
litest-synaptics-st.c \
|
||||
litest-synaptics-t440.c \
|
||||
litest-synaptics-x1-carbon-3rd.c \
|
||||
litest-trackpoint.c \
|
||||
litest-touch-screen.c \
|
||||
litest-wacom-bamboo-tablet.c \
|
||||
litest-wacom-cintiq-tablet.c \
|
||||
litest-wacom-intuos-tablet.c \
|
||||
litest-wacom-isdv4-tablet.c \
|
||||
litest-wacom-touch.c \
|
||||
litest-wacom-intuos-finger.c \
|
||||
litest-waltop-tablet.c \
|
||||
litest-wheel-only.c \
|
||||
litest-xen-virtual-pointer.c \
|
||||
litest-vmware-virtual-usb-mouse.c \
|
||||
litest-device-alps-semi-mt.c \
|
||||
litest-device-alps-dualpoint.c \
|
||||
litest-device-atmel-hover.c \
|
||||
litest-device-bcm5974.c \
|
||||
litest-device-elantech-touchpad.c \
|
||||
litest-device-generic-singletouch.c \
|
||||
litest-device-keyboard.c \
|
||||
litest-device-keyboard-razer-blackwidow.c \
|
||||
litest-device-logitech-trackball.c \
|
||||
litest-device-nexus4-touch-screen.c \
|
||||
litest-device-magic-trackpad.c \
|
||||
litest-device-mouse.c \
|
||||
litest-device-mouse-roccat.c \
|
||||
litest-device-mouse-low-dpi.c \
|
||||
litest-device-ms-surface-cover.c \
|
||||
litest-device-protocol-a-touch-screen.c \
|
||||
litest-device-qemu-usb-tablet.c \
|
||||
litest-device-synaptics.c \
|
||||
litest-device-synaptics-hover.c \
|
||||
litest-device-synaptics-st.c \
|
||||
litest-device-synaptics-t440.c \
|
||||
litest-device-synaptics-x1-carbon-3rd.c \
|
||||
litest-device-trackpoint.c \
|
||||
litest-device-touch-screen.c \
|
||||
litest-device-wacom-bamboo-tablet.c \
|
||||
litest-device-wacom-cintiq-tablet.c \
|
||||
litest-device-wacom-intuos-tablet.c \
|
||||
litest-device-wacom-isdv4-tablet.c \
|
||||
litest-device-wacom-touch.c \
|
||||
litest-device-wacom-intuos-finger.c \
|
||||
litest-device-waltop-tablet.c \
|
||||
litest-device-wheel-only.c \
|
||||
litest-device-xen-virtual-pointer.c \
|
||||
litest-device-vmware-virtual-usb-mouse.c \
|
||||
litest.c
|
||||
liblitest_la_LIBADD = $(top_builddir)/src/libinput-util.la
|
||||
liblitest_la_CFLAGS = $(AM_CFLAGS) \
|
||||
-DLIBINPUT_UDEV_RULES_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks.rules\"" \
|
||||
-DLIBINPUT_UDEV_RULES_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks-litest.rules\"" \
|
||||
-DLIBINPUT_UDEV_HWDB_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks.hwdb\""
|
||||
if HAVE_LIBUNWIND
|
||||
liblitest_la_LIBADD += $(LIBUNWIND_LIBS) -ldl
|
||||
|
|
|
|||
|
|
@ -70,7 +70,8 @@ START_TEST(device_sendevents_config_touchpad)
|
|||
expected = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
|
||||
|
||||
/* The wacom devices in the test suite are external */
|
||||
if (libevdev_get_id_vendor(dev->evdev) != VENDOR_ID_WACOM)
|
||||
if (libevdev_get_id_vendor(dev->evdev) != VENDOR_ID_WACOM &&
|
||||
libevdev_get_id_bustype(dev->evdev) != BUS_BLUETOOTH)
|
||||
expected |=
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
|
||||
|
||||
|
|
@ -89,7 +90,8 @@ START_TEST(device_sendevents_config_touchpad_superset)
|
|||
uint32_t modes;
|
||||
|
||||
/* The wacom devices in the test suite are external */
|
||||
if (libevdev_get_id_vendor(dev->evdev) == 0x56a) /* wacom */
|
||||
if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM ||
|
||||
libevdev_get_id_bustype(dev->evdev) == BUS_BLUETOOTH)
|
||||
return;
|
||||
|
||||
device = dev->libinput_device;
|
||||
|
|
|
|||
|
|
@ -37,11 +37,12 @@ static void litest_bcm5974_setup(void)
|
|||
static struct input_event down[] = {
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
|
@ -50,15 +51,31 @@ static struct input_event move[] = {
|
|||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static int
|
||||
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
|
||||
{
|
||||
switch (evcode) {
|
||||
case ABS_PRESSURE:
|
||||
case ABS_MT_PRESSURE:
|
||||
*value = 30;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
|
||||
.get_axis_default = get_axis_default,
|
||||
};
|
||||
|
||||
static struct input_absinfo absinfo[] = {
|
||||
121
test/litest-device-elantech-touchpad.c
Normal file
121
test/litest-device-elantech-touchpad.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright © 2015 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.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "litest.h"
|
||||
#include "litest-int.h"
|
||||
|
||||
static void
|
||||
litest_elantech_touchpad_setup(void)
|
||||
{
|
||||
struct litest_device *d = litest_create_device(LITEST_ELANTECH_TOUCHPAD);
|
||||
litest_set_current_device(d);
|
||||
}
|
||||
|
||||
static struct input_event down[] = {
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct input_event move[] = {
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static int
|
||||
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
|
||||
{
|
||||
switch (evcode) {
|
||||
case ABS_PRESSURE:
|
||||
case ABS_MT_PRESSURE:
|
||||
*value = 30;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
|
||||
.get_axis_default = get_axis_default,
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
.bustype = 0x11,
|
||||
.vendor = 0x2,
|
||||
.product = 0xe,
|
||||
};
|
||||
|
||||
static int events[] = {
|
||||
EV_KEY, BTN_LEFT,
|
||||
EV_KEY, BTN_RIGHT,
|
||||
EV_KEY, BTN_TOOL_FINGER,
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_KEY, BTN_TOOL_DOUBLETAP,
|
||||
EV_KEY, BTN_TOOL_TRIPLETAP,
|
||||
EV_KEY, BTN_TOOL_QUADTAP,
|
||||
INPUT_PROP_MAX, INPUT_PROP_POINTER,
|
||||
-1, -1,
|
||||
};
|
||||
|
||||
static struct input_absinfo absinfo[] = {
|
||||
{ ABS_X, 0, 1280, 0, 0, 0 },
|
||||
{ ABS_Y, 0, 704, 0, 0, 0 },
|
||||
{ ABS_PRESSURE, 0, 255, 0, 0, 0 },
|
||||
{ ABS_TOOL_WIDTH, 0, 15, 0, 0, 0 },
|
||||
{ ABS_MT_SLOT, 0, 1, 0, 0, 0 },
|
||||
{ ABS_MT_POSITION_X, 0, 1280, 0, 0, 0 },
|
||||
{ ABS_MT_POSITION_Y, 0, 704, 0, 0, 0 },
|
||||
{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
|
||||
{ .value = -1 }
|
||||
};
|
||||
|
||||
struct litest_test_device litest_elantech_touchpad_device = {
|
||||
.type = LITEST_ELANTECH_TOUCHPAD,
|
||||
.features = LITEST_TOUCHPAD | LITEST_BUTTON,
|
||||
.shortname = "elantech",
|
||||
.setup = litest_elantech_touchpad_setup,
|
||||
.interface = &interface,
|
||||
|
||||
.name = "ETPS/2 Elantech Touchpad",
|
||||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
};
|
||||
110
test/litest-device-magic-trackpad.c
Normal file
110
test/litest-device-magic-trackpad.c
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright © 2015 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.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "litest.h"
|
||||
#include "litest-int.h"
|
||||
|
||||
static void litest_magicpad_setup(void)
|
||||
{
|
||||
struct litest_device *d = litest_create_device(LITEST_MAGIC_TRACKPAD);
|
||||
litest_set_current_device(d);
|
||||
}
|
||||
|
||||
static struct input_event down[] = {
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOUCH_MAJOR, .value = 272 },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOUCH_MINOR, .value = 400 },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct input_event move[] = {
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOUCH_MAJOR, .value = 272 },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TOUCH_MINOR, .value = 400 },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
};
|
||||
|
||||
static struct input_absinfo absinfo[] = {
|
||||
{ ABS_X, -2909, 3167, 4, 0, 46 },
|
||||
{ ABS_Y, -2456, 2565, 4, 0, 45 },
|
||||
{ ABS_MT_SLOT, 0, 15, 0, 0, 0 },
|
||||
{ ABS_MT_POSITION_X, -2909, 3167, 4, 0, 46 },
|
||||
{ ABS_MT_POSITION_Y, -2456, 2565, 4, 0, 45 },
|
||||
{ ABS_MT_ORIENTATION, -31, 32, 1, 0, 0 },
|
||||
{ ABS_MT_TOUCH_MAJOR, 0, 1020, 4, 0, 0 },
|
||||
{ ABS_MT_TOUCH_MINOR, 0, 1020, 4, 0, 0 },
|
||||
{ ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
|
||||
{ .value = -1 },
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
.bustype = 0x5,
|
||||
.vendor = 0x5ac,
|
||||
.product = 0x30e,
|
||||
};
|
||||
|
||||
static int events[] = {
|
||||
EV_KEY, BTN_LEFT,
|
||||
EV_KEY, BTN_TOOL_FINGER,
|
||||
EV_KEY, BTN_TOOL_QUINTTAP,
|
||||
EV_KEY, BTN_TOUCH,
|
||||
EV_KEY, BTN_TOOL_DOUBLETAP,
|
||||
EV_KEY, BTN_TOOL_TRIPLETAP,
|
||||
EV_KEY, BTN_TOOL_QUADTAP,
|
||||
INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD,
|
||||
-1, -1
|
||||
};
|
||||
|
||||
struct litest_test_device litest_magicpad_device = {
|
||||
.type = LITEST_MAGIC_TRACKPAD,
|
||||
.features = LITEST_TOUCHPAD | LITEST_CLICKPAD |
|
||||
LITEST_BUTTON | LITEST_APPLE_CLICKPAD,
|
||||
.shortname = "magic trackpad",
|
||||
.setup = litest_magicpad_setup,
|
||||
.interface = &interface,
|
||||
|
||||
.name = "Apple Wireless Trackpad",
|
||||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
};
|
||||
|
|
@ -38,11 +38,12 @@ litest_synaptics_t440_setup(void)
|
|||
static struct input_event down[] = {
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
|
@ -51,15 +52,31 @@ static struct input_event move[] = {
|
|||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static int
|
||||
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
|
||||
{
|
||||
switch (evcode) {
|
||||
case ABS_PRESSURE:
|
||||
case ABS_MT_PRESSURE:
|
||||
*value = 30;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
|
||||
.get_axis_default = get_axis_default,
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
|
|
@ -38,11 +38,12 @@ litest_synaptics_carbon3rd_setup(void)
|
|||
static struct input_event down[] = {
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
|
@ -51,15 +52,31 @@ static struct input_event move[] = {
|
|||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static int
|
||||
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
|
||||
{
|
||||
switch (evcode) {
|
||||
case ABS_PRESSURE:
|
||||
case ABS_MT_PRESSURE:
|
||||
*value = 30;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
|
||||
.get_axis_default = get_axis_default,
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
|
|
@ -38,11 +38,12 @@ litest_synaptics_clickpad_setup(void)
|
|||
static struct input_event down[] = {
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
|
@ -51,15 +52,31 @@ static struct input_event move[] = {
|
|||
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
static int
|
||||
get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
|
||||
{
|
||||
switch (evcode) {
|
||||
case ABS_PRESSURE:
|
||||
case ABS_MT_PRESSURE:
|
||||
*value = 30;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct litest_device_interface interface = {
|
||||
.touch_down_events = down,
|
||||
.touch_move_events = move,
|
||||
|
||||
.get_axis_default = get_axis_default,
|
||||
};
|
||||
|
||||
static struct input_id input_id = {
|
||||
|
|
@ -79,6 +79,12 @@ struct litest_device_interface {
|
|||
void (*touch_move)(struct litest_device *d, unsigned int slot, double x, double y);
|
||||
void (*touch_up)(struct litest_device *d, unsigned int slot);
|
||||
|
||||
/**
|
||||
* Default value for the given EV_ABS axis.
|
||||
* @return 0 on success, nonzero otherwise
|
||||
*/
|
||||
int (*get_axis_default)(struct litest_device *d, unsigned int code, int32_t *value);
|
||||
|
||||
/**
|
||||
* Set of of events to execute on touch down, terminated by a .type
|
||||
* and .code value of -1. If the event value is LITEST_AUTO_ASSIGN,
|
||||
|
|
|
|||
|
|
@ -360,6 +360,8 @@ extern struct litest_test_device litest_alps_dualpoint_device;
|
|||
extern struct litest_test_device litest_mouse_low_dpi_device;
|
||||
extern struct litest_test_device litest_generic_multitouch_screen_device;
|
||||
extern struct litest_test_device litest_nexus4_device;
|
||||
extern struct litest_test_device litest_magicpad_device;
|
||||
extern struct litest_test_device litest_elantech_touchpad_device;
|
||||
extern struct litest_test_device litest_waltop_tablet_device;
|
||||
|
||||
struct litest_test_device* devices[] = {
|
||||
|
|
@ -394,6 +396,8 @@ struct litest_test_device* devices[] = {
|
|||
&litest_mouse_low_dpi_device,
|
||||
&litest_generic_multitouch_screen_device,
|
||||
&litest_nexus4_device,
|
||||
&litest_magicpad_device,
|
||||
&litest_elantech_touchpad_device,
|
||||
&litest_waltop_tablet_device,
|
||||
NULL,
|
||||
};
|
||||
|
|
@ -1222,19 +1226,22 @@ litest_event(struct litest_device *d, unsigned int type,
|
|||
litest_assert_int_eq(ret, 0);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
static bool
|
||||
axis_replacement_value(struct axis_replacement *axes,
|
||||
int32_t evcode)
|
||||
int32_t evcode,
|
||||
int32_t *value)
|
||||
{
|
||||
struct axis_replacement *axis = axes;
|
||||
|
||||
while (axis->evcode != -1) {
|
||||
if (axis->evcode == evcode)
|
||||
return axis->value;
|
||||
if (axis->evcode == evcode) {
|
||||
*value = axis->value;
|
||||
return true;
|
||||
}
|
||||
axis++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -1269,8 +1276,13 @@ litest_auto_assign_value(struct litest_device *d,
|
|||
value = touching ? 0 : 1;
|
||||
break;
|
||||
default:
|
||||
if (axes)
|
||||
value = axis_replacement_value(axes, ev->code);
|
||||
value = -1;
|
||||
if (!axes)
|
||||
break;
|
||||
|
||||
if (!axis_replacement_value(axes, ev->code, &value) &&
|
||||
d->interface->get_axis_default)
|
||||
d->interface->get_axis_default(d, ev->code, &value);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1466,7 +1478,7 @@ auto_assign_tablet_value(struct litest_device *d,
|
|||
value = litest_scale(d, ABS_Y, y);
|
||||
break;
|
||||
default:
|
||||
value = axis_replacement_value(axes, ev->code);
|
||||
axis_replacement_value(axes, ev->code, &value);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,11 +140,13 @@ enum litest_device_type {
|
|||
LITEST_MOUSE_LOW_DPI = -26,
|
||||
LITEST_GENERIC_MULTITOUCH_SCREEN = -27,
|
||||
LITEST_NEXUS4_TOUCH_SCREEN = -28,
|
||||
LITEST_WACOM_BAMBOO = -29,
|
||||
LITEST_WACOM_CINTIQ = -30,
|
||||
LITEST_WACOM_INTUOS = -31,
|
||||
LITEST_WACOM_ISDV4 = -32,
|
||||
LITEST_WALTOP = -33,
|
||||
LITEST_MAGIC_TRACKPAD = -29,
|
||||
LITEST_ELANTECH_TOUCHPAD = -30,
|
||||
LITEST_WACOM_BAMBOO = -31,
|
||||
LITEST_WACOM_CINTIQ = -32,
|
||||
LITEST_WACOM_INTUOS = -33,
|
||||
LITEST_WACOM_ISDV4 = -34,
|
||||
LITEST_WALTOP = -35,
|
||||
};
|
||||
|
||||
enum litest_device_feature {
|
||||
|
|
|
|||
47
test/misc.c
47
test/misc.c
|
|
@ -673,6 +673,52 @@ START_TEST(trackpoint_accel_parser)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
struct parser_test_dimension {
|
||||
char *tag;
|
||||
bool success;
|
||||
int x, y;
|
||||
};
|
||||
|
||||
START_TEST(dimension_prop_parser)
|
||||
{
|
||||
struct parser_test_dimension tests[] = {
|
||||
{ "10x10", true, 10, 10 },
|
||||
{ "1x20", true, 1, 20 },
|
||||
{ "1x8000", true, 1, 8000 },
|
||||
{ "238492x428210", true, 238492, 428210 },
|
||||
{ "0x0", true, 0, 0 },
|
||||
{ "-10x10", false, 0, 0 },
|
||||
{ "-1", false, 0, 0 },
|
||||
{ "1x-99", false, 0, 0 },
|
||||
{ "0", false, 0, 0 },
|
||||
{ "100", false, 0, 0 },
|
||||
{ "", false, 0, 0 },
|
||||
{ "abd", false, 0, 0 },
|
||||
{ "xabd", false, 0, 0 },
|
||||
{ "0xaf", false, 0, 0 },
|
||||
{ "0x0x", true, 0, 0 },
|
||||
{ "x10", false, 0, 0 },
|
||||
{ NULL, false, 0, 0 }
|
||||
};
|
||||
int i;
|
||||
size_t x, y;
|
||||
bool success;
|
||||
|
||||
for (i = 0; tests[i].tag != NULL; i++) {
|
||||
x = y = 0xad;
|
||||
success = parse_dimension_property(tests[i].tag, &x, &y);
|
||||
ck_assert(success == tests[i].success);
|
||||
if (success) {
|
||||
ck_assert_int_eq(x, tests[i].x);
|
||||
ck_assert_int_eq(y, tests[i].y);
|
||||
} else {
|
||||
ck_assert_int_eq(x, 0xad);
|
||||
ck_assert_int_eq(y, 0xad);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
litest_setup_tests(void)
|
||||
{
|
||||
|
|
@ -693,4 +739,5 @@ litest_setup_tests(void)
|
|||
litest_add_no_device("misc:parser", dpi_parser);
|
||||
litest_add_no_device("misc:parser", wheel_click_parser);
|
||||
litest_add_no_device("misc:parser", trackpoint_accel_parser);
|
||||
litest_add_no_device("misc:parser", dimension_prop_parser);
|
||||
}
|
||||
|
|
|
|||
843
test/touchpad.c
843
test/touchpad.c
File diff suppressed because it is too large
Load diff
|
|
@ -413,8 +413,11 @@ START_TEST(udev_device_sysname)
|
|||
libinput_dispatch(li);
|
||||
|
||||
while ((ev = libinput_get_event(li))) {
|
||||
if (libinput_event_get_type(ev) != LIBINPUT_EVENT_DEVICE_ADDED)
|
||||
if (libinput_event_get_type(ev) !=
|
||||
LIBINPUT_EVENT_DEVICE_ADDED) {
|
||||
libinput_event_destroy(ev);
|
||||
continue;
|
||||
}
|
||||
|
||||
device = libinput_event_get_device(ev);
|
||||
sysname = libinput_device_get_sysname(device);
|
||||
|
|
|
|||
2
udev/.gitignore
vendored
2
udev/.gitignore
vendored
|
|
@ -1 +1,3 @@
|
|||
libinput-device-group
|
||||
libinput-model-quirks
|
||||
*.rules
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ ACTION!="add|change", GOTO="libinput_device_group_end"
|
|||
KERNEL!="event[0-9]*", GOTO="libinput_device_group_end"
|
||||
|
||||
ATTRS{phys}=="?*", \
|
||||
PROGRAM="libinput-device-group %S%p", \
|
||||
PROGRAM="@UDEV_TEST_PATH@libinput-device-group %S%p", \
|
||||
ENV{LIBINPUT_DEVICE_GROUP}="%c"
|
||||
|
||||
LABEL="libinput_device_group_end"
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
# Match string formats:
|
||||
# libinput:<modalias>
|
||||
# libinput:name:<name>:dmi:<dmi string>
|
||||
|
||||
# libinput:name:<name>:fwversion:<version>
|
||||
#
|
||||
# Sort by brand, model
|
||||
|
||||
|
|
@ -22,12 +22,17 @@ libinput:name:*AlpsPS/2 ALPS DualPoint TouchPad:dmi:*
|
|||
libinput:name:*AlpsPS/2 ALPS GlidePoint:dmi:*
|
||||
LIBINPUT_MODEL_ALPS_TOUCHPAD=1
|
||||
|
||||
libinput:name:*AlpsPS/2 ALPS DualPoint TouchPad:fwversion:8
|
||||
libinput:name:*AlpsPS/2 ALPS GlidePoint:fwversion:8
|
||||
LIBINPUT_ATTR_SIZE_HINT=100x55
|
||||
|
||||
##########################################
|
||||
# Apple
|
||||
##########################################
|
||||
libinput:touchpad:input:b0003v05ACp*
|
||||
libinput:touchpad:input:b0005v05ACp*
|
||||
LIBINPUT_MODEL_APPLE_TOUCHPAD=1
|
||||
LIBINPUT_ATTR_SIZE_HINT=104x75
|
||||
|
||||
##########################################
|
||||
# Google
|
||||
|
|
|
|||
|
|
@ -11,6 +11,20 @@
|
|||
ACTION!="add|change", GOTO="libinput_model_quirks_end"
|
||||
KERNEL!="event*", GOTO="libinput_model_quirks_end"
|
||||
|
||||
# Touchpad firmware detection, two-stage process.
|
||||
# First, run the program and import the LIBINPUT_MODEL_FIRMWARE_VERSION
|
||||
# environment (if any)
|
||||
KERNELS=="*input*", \
|
||||
ENV{ID_INPUT_TOUCHPAD}=="1", \
|
||||
IMPORT{program}="@UDEV_TEST_PATH@libinput-model-quirks %S%p"
|
||||
|
||||
# Second, match on anything with that env set and import from the hwdb
|
||||
KERNELS=="*input*", \
|
||||
ENV{ID_INPUT_TOUCHPAD}=="1", \
|
||||
ENV{LIBINPUT_MODEL_FIRMWARE_VERSION}!="", \
|
||||
IMPORT{builtin}="hwdb 'libinput:name:$attr{name}:fwversion:$env{LIBINPUT_MODEL_FIRMWARE_VERSION}'"
|
||||
# End of touchpad firmware detection
|
||||
|
||||
# Matches below are exclusive, if one matches we skip the rest
|
||||
# hwdb matches:
|
||||
#
|
||||
|
|
@ -1,10 +1,22 @@
|
|||
udevdir=$(UDEV_DIR)
|
||||
udev_PROGRAMS = libinput-device-group
|
||||
udev_PROGRAMS = libinput-device-group \
|
||||
libinput-model-quirks
|
||||
|
||||
litest_rules = 80-libinput-device-groups-litest.rules \
|
||||
90-libinput-model-quirks-litest.rules
|
||||
udev_SCRIPTS = $(litest_rules)
|
||||
|
||||
libinput_device_group_SOURCES = libinput-device-group.c
|
||||
libinput_device_group_CFLAGS = $(LIBUDEV_CFLAGS) $(GCC_CFLAGS)
|
||||
libinput_device_group_LDADD = $(LIBUDEV_LIBS)
|
||||
|
||||
libinput_model_quirks_SOURCES = libinput-model-quirks.c
|
||||
libinput_model_quirks_CFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
$(LIBUDEV_CFLAGS) \
|
||||
$(GCC_CFLAGS)
|
||||
libinput_model_quirks_LDADD = $(LIBUDEV_LIBS)
|
||||
|
||||
udev_rulesdir=$(UDEV_DIR)/rules.d
|
||||
dist_udev_rules_DATA = \
|
||||
80-libinput-device-groups.rules \
|
||||
|
|
@ -13,3 +25,11 @@ dist_udev_rules_DATA = \
|
|||
udev_hwdbdir=$(UDEV_DIR)/hwdb.d
|
||||
dist_udev_hwdb_DATA = \
|
||||
90-libinput-model-quirks.hwdb
|
||||
|
||||
%-litest.rules: %.rules.in
|
||||
$(SED) -e "s|\@UDEV_TEST_PATH\@|$(abs_builddir)/|" < $^ > $@
|
||||
|
||||
CLEANFILES = $(litest_rules)
|
||||
DISTCLEANFILES = \
|
||||
80-libinput-device-groups.rules \
|
||||
90-libinput-model-quirks.rules
|
||||
|
|
|
|||
116
udev/libinput-model-quirks.c
Normal file
116
udev/libinput-model-quirks.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright © 2015 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 <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libudev.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "libinput-util.h"
|
||||
|
||||
static inline const char *
|
||||
prop_value(struct udev_device *device,
|
||||
const char *prop_name)
|
||||
{
|
||||
struct udev_device *parent;
|
||||
const char *prop_value = NULL;
|
||||
|
||||
parent = device;
|
||||
while (parent && !prop_value) {
|
||||
prop_value = udev_device_get_property_value(parent, prop_name);
|
||||
parent = udev_device_get_parent(parent);
|
||||
}
|
||||
|
||||
return prop_value;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_touchpad_alps(struct udev_device *device)
|
||||
{
|
||||
const char *product;
|
||||
int bus, vid, pid, version;
|
||||
|
||||
product = prop_value(device, "PRODUCT");
|
||||
if (!product)
|
||||
return;
|
||||
|
||||
if (sscanf(product, "%x/%x/%x/%x", &bus, &vid, &pid, &version) != 4)
|
||||
return;
|
||||
|
||||
/* ALPS' firmware version is the PID */
|
||||
if (pid)
|
||||
printf("LIBINPUT_MODEL_FIRMWARE_VERSION=%d\n", pid);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_touchpad(struct udev_device *device)
|
||||
{
|
||||
const char *name = NULL;
|
||||
|
||||
name = prop_value(device, "NAME");
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
if (strstr(name, "AlpsPS/2 ALPS") != NULL)
|
||||
handle_touchpad_alps(device);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc = 1;
|
||||
struct udev *udev = NULL;
|
||||
struct udev_device *device = NULL;
|
||||
const char *syspath;
|
||||
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
syspath = argv[1];
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev)
|
||||
goto out;
|
||||
|
||||
device = udev_device_new_from_syspath(udev, syspath);
|
||||
if (!device)
|
||||
goto out;
|
||||
|
||||
if (udev_device_get_property_value(device, "ID_INPUT_TOUCHPAD"))
|
||||
handle_touchpad(device);
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (device)
|
||||
udev_device_unref(device);
|
||||
if (udev)
|
||||
udev_unref(udev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue