mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-29 15:44:02 +00:00
lx_emul: improve motion-device handling in evdev
The key element of the improvement is differentiated processing of events of the following device types. Mouse: relative motion Pointer: absolute motion (Qemu usb-tablet and IP-KVM devices) Touchpad: relative motion via absolute touchpad coordinates Touchtool: absolute motion (e.g., stylus) Touchscreen: absolute motion and finger (multi-) touch Processing is done in two stages for one "input packet". First, all events of the packet are recorded into the current evdev state with device-type specific operations. Then, appropriate Genode input events are generated from the accumulated evdev state in the submission stage (again by device-type specific functions). A simple version of tap-to-click was added to the touchpad support. Fixes #5105
This commit is contained in:
parent
a0e0000108
commit
1dcc6fda6b
@ -232,8 +232,8 @@ trim_lines
|
||||
compare_output_to {
|
||||
[init -> event_dump] Input event #0 PRESS KEY_X 65534 key count: 1
|
||||
[init -> event_dump] Input event #1 RELEASE KEY_X key count: 0
|
||||
[init -> event_dump] Input event #2 PRESS BTN_LEFT 65534 key count: 1
|
||||
[init -> event_dump] Input event #3 REL_MOTION -1+1 key count: 1
|
||||
[init -> event_dump] Input event #2 REL_MOTION -1+1 key count: 0
|
||||
[init -> event_dump] Input event #3 PRESS BTN_LEFT 65534 key count: 1
|
||||
[init -> event_dump] Input event #4 RELEASE BTN_LEFT key count: 0
|
||||
[init -> usb_hid_drv] usb usb-X-X: USB disconnect, device number X
|
||||
[init -> usb_hid_drv] Disconnected device: inputX
|
||||
@ -242,11 +242,11 @@ compare_output_to {
|
||||
[init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d)
|
||||
[init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Keyboard [HID 03eb:204d]
|
||||
[init -> usb_hid_drv] input: HID 03eb:204d
|
||||
[init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d)
|
||||
[init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d) MOUSE
|
||||
[init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Mouse [HID 03eb:204d]
|
||||
[init -> event_dump] Input event #5 PRESS KEY_X 65534 key count: 1
|
||||
[init -> event_dump] Input event #6 RELEASE KEY_X key count: 0
|
||||
[init -> event_dump] Input event #7 PRESS BTN_LEFT 65534 key count: 1
|
||||
[init -> event_dump] Input event #8 REL_MOTION -1+1 key count: 1
|
||||
[init -> event_dump] Input event #7 REL_MOTION -1+1 key count: 0
|
||||
[init -> event_dump] Input event #8 PRESS BTN_LEFT 65534 key count: 1
|
||||
[init -> event_dump] Input event #9 RELEASE BTN_LEFT key count: 0
|
||||
}
|
||||
|
@ -26,57 +26,609 @@
|
||||
#include <linux/device.h>
|
||||
|
||||
/*
|
||||
* TODO differentiate touchpads, trackpads, touchscreen, etc.
|
||||
* Input devices with motion events
|
||||
*
|
||||
* (from Documentation/input/event-codes.rst)
|
||||
*
|
||||
* INPUT_PROP_DIRECT + INPUT_PROP_POINTER
|
||||
* --------------------------------------
|
||||
* (from Documentation/input/event-codes.rst and multi-touch-protocol.rst)
|
||||
*
|
||||
* The INPUT_PROP_DIRECT property indicates that device coordinates should be
|
||||
* directly mapped to screen coordinates (not taking into account trivial
|
||||
* transformations, such as scaling, flipping and rotating). Non-direct input
|
||||
* devices require non-trivial transformation, such as absolute to relative
|
||||
* transformation for touchpads. Typical direct input devices: touchscreens,
|
||||
* drawing tablets; non-direct devices: touchpads, mice.
|
||||
* transformations, such as scaling, flipping and rotating).
|
||||
* -> touchscreen, tablet (stylus/pen)
|
||||
*
|
||||
* The INPUT_PROP_POINTER property indicates that the device is not transposed
|
||||
* on the screen and thus requires use of an on-screen pointer to trace user's
|
||||
* movements. Typical pointer devices: touchpads, tablets, mice; non-pointer
|
||||
* device: touchscreen.
|
||||
* Non-direct input devices may require non-trivial transformation, such as
|
||||
* absolute to relative transformation.
|
||||
* -> mouse, touchpad
|
||||
*
|
||||
* If neither INPUT_PROP_DIRECT or INPUT_PROP_POINTER are set, the property is
|
||||
* considered undefined and the device type should be deduced in the
|
||||
* traditional way, using emitted event types.
|
||||
* Historically a touch device with BTN_TOOL_FINGER and BTN_TOUCH was
|
||||
* interpreted as a touchpad by userspace, while a similar device without
|
||||
* BTN_TOOL_FINGER was interpreted as a touchscreen. For backwards
|
||||
* compatibility with current userspace it is recommended to follow this
|
||||
* distinction.
|
||||
*
|
||||
* In Linux, stylus/pen tool proximity is reported by BTN_TOOL_PEN/RUBBER plus
|
||||
* ABS_DISTANCE events. The actual contact to the surface emits an additional
|
||||
* BTN_TOUCH event. For multi-touch devices, the "tool" is also reported via
|
||||
* BTN_TOOL_FINGER/DOUBLETAP etc.
|
||||
*
|
||||
* Thus, these devices must be differentiated.
|
||||
*
|
||||
* Mouse: relative motion
|
||||
* Pointer: absolute motion (Qemu usb-tablet and IP-KVM devices)
|
||||
* Touchpad: relative motion via absolute touchpad coordinates
|
||||
* Touchtool: absolute motion (e.g., stylus)
|
||||
* Touchscreen: absolute motion and finger (multi-) touch
|
||||
*/
|
||||
|
||||
static bool is_rel_dev(struct input_dev *dev)
|
||||
{
|
||||
return test_bit(EV_REL, dev->evbit) && test_bit(REL_X, dev->relbit);
|
||||
}
|
||||
|
||||
static bool is_abs_dev(struct input_dev *dev)
|
||||
{
|
||||
return test_bit(EV_ABS, dev->evbit) && test_bit(ABS_X, dev->absbit);
|
||||
}
|
||||
|
||||
static bool is_touch_dev(struct input_dev *dev)
|
||||
{
|
||||
return test_bit(BTN_TOUCH, dev->keybit);
|
||||
}
|
||||
|
||||
static bool is_tool_dev(struct input_dev *dev)
|
||||
{
|
||||
return test_bit(BTN_TOOL_PEN, dev->keybit)
|
||||
|| test_bit(BTN_TOOL_RUBBER, dev->keybit)
|
||||
|| test_bit(BTN_TOOL_BRUSH, dev->keybit)
|
||||
|| test_bit(BTN_TOOL_PENCIL, dev->keybit)
|
||||
|| test_bit(BTN_TOOL_AIRBRUSH, dev->keybit)
|
||||
|| test_bit(BTN_TOOL_MOUSE, dev->keybit)
|
||||
|| test_bit(BTN_TOOL_LENS, dev->keybit);
|
||||
}
|
||||
|
||||
enum evdev_motion {
|
||||
MOTION_NONE,
|
||||
MOTION_MOUSE, /* relative motion */
|
||||
MOTION_POINTER, /* absolute motion */
|
||||
MOTION_TOUCHPAD, /* relative motion based on absolute axes */
|
||||
MOTION_TOUCHTOOL, /* absolute motion */
|
||||
MOTION_TOUCHSCREEN, /* absolute motion */
|
||||
};
|
||||
|
||||
enum evdev_motion evdev_motion(struct input_dev const *dev)
|
||||
{
|
||||
if (is_rel_dev(dev))
|
||||
return MOTION_MOUSE;
|
||||
|
||||
if (!is_abs_dev(dev))
|
||||
return MOTION_NONE;
|
||||
|
||||
if (!is_touch_dev(dev))
|
||||
return MOTION_POINTER;
|
||||
|
||||
if (test_bit(BTN_TOOL_FINGER, dev->keybit))
|
||||
return MOTION_TOUCHPAD;
|
||||
|
||||
if (is_tool_dev(dev))
|
||||
return MOTION_TOUCHTOOL;
|
||||
|
||||
return MOTION_TOUCHSCREEN;
|
||||
}
|
||||
|
||||
|
||||
struct evdev_mt_slot
|
||||
{
|
||||
int tracking_id; /* -1 means unused */
|
||||
int id; /* -1 means unused */
|
||||
int x, y, ox, oy;
|
||||
};
|
||||
#define INIT_MT_SLOT (struct evdev_mt_slot){ -1, -1, -1, -1, -1 }
|
||||
|
||||
/* just stay with primary and secondary touch for now */
|
||||
enum { MAX_MT_SLOTS = 2, PRIMARY = 0, SECONDARY = 1, };
|
||||
|
||||
/*
|
||||
* Maximum number of touch slots supported.
|
||||
*
|
||||
* Many Linux drivers report 2 to 10 slots, the Magic Trackpad reports 16. The
|
||||
* Surface driver reports 64, which we just ignore.
|
||||
*/
|
||||
enum { MAX_MT_SLOTS = 16 };
|
||||
|
||||
struct evdev_mt
|
||||
{
|
||||
bool pending;
|
||||
unsigned num_slots;
|
||||
unsigned cur_slot;
|
||||
struct evdev_mt_slot slots[MAX_MT_SLOTS];
|
||||
};
|
||||
|
||||
#define array_for_each_element(element, array) \
|
||||
for ((element) = (array); \
|
||||
(element) < ((array) + ARRAY_SIZE((array))); \
|
||||
(element)++)
|
||||
|
||||
#define for_each_mt_slot(slot, mt) \
|
||||
array_for_each_element(slot, (mt)->slots)
|
||||
|
||||
|
||||
struct evdev_key
|
||||
{
|
||||
bool pending;
|
||||
unsigned code;
|
||||
bool press;
|
||||
|
||||
typeof(jiffies) jiffies;
|
||||
};
|
||||
#define INIT_KEY (struct evdev_key){ false, 0, false }
|
||||
#define EVDEV_KEY(code, press) (struct evdev_key){ true, code, press, jiffies }
|
||||
|
||||
struct evdev_keys
|
||||
{
|
||||
unsigned pending; /* pending keys counter */
|
||||
struct evdev_key key[16]; /* max 16 keys per packet */
|
||||
};
|
||||
|
||||
#define for_each_key(key, keys, pending_only) \
|
||||
array_for_each_element(key, (keys)->key) \
|
||||
if (!(pending_only) || (key)->pending)
|
||||
|
||||
#define for_each_pending_key(key, keys) \
|
||||
if ((keys)->pending) \
|
||||
for_each_key(key, keys, true)
|
||||
|
||||
|
||||
struct evdev_xy
|
||||
{
|
||||
bool pending;
|
||||
int x, y;
|
||||
};
|
||||
#define INIT_XY (struct evdev_xy){ false, 0, 0 }
|
||||
|
||||
|
||||
struct evdev_touchpad
|
||||
{
|
||||
typeof(jiffies) touch_time;
|
||||
bool btn_left_pressed; /* state of (physical) BTN_LEFT */
|
||||
};
|
||||
|
||||
|
||||
struct evdev
|
||||
{
|
||||
struct genode_event *event;
|
||||
struct input_handle handle;
|
||||
unsigned pending;
|
||||
int rel_x, rel_y, rel_wx, rel_wy;
|
||||
struct evdev_mt mt;
|
||||
enum evdev_motion motion;
|
||||
|
||||
/* record of all events in one packet - submitted on SYN */
|
||||
unsigned tool; /* BTN_TOOL_* or 0 */
|
||||
struct evdev_keys keys;
|
||||
struct evdev_xy rel;
|
||||
struct evdev_xy wheel;
|
||||
struct evdev_xy abs;
|
||||
struct evdev_mt mt;
|
||||
|
||||
/* device-specific state machine */
|
||||
union {
|
||||
struct evdev_touchpad touchpad;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/* helper functions (require declarations above) */
|
||||
#include "evdev.h"
|
||||
|
||||
|
||||
static bool record_mouse(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
if (v->type != EV_REL || evdev->motion != MOTION_MOUSE)
|
||||
return false;
|
||||
|
||||
switch (v->code) {
|
||||
case REL_X: evdev->rel.pending = true; evdev->rel.x += v->value; break;
|
||||
case REL_Y: evdev->rel.pending = true; evdev->rel.y += v->value; break;
|
||||
case REL_HWHEEL: evdev->wheel.pending = true; evdev->wheel.x += v->value; break;
|
||||
case REL_WHEEL: evdev->wheel.pending = true; evdev->wheel.y += v->value; break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool record_abs(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
if (v->type != EV_ABS)
|
||||
return false;
|
||||
|
||||
switch (v->code) {
|
||||
case ABS_X: evdev->abs.pending = true; evdev->abs.x = v->value; break;
|
||||
case ABS_Y: evdev->abs.pending = true; evdev->abs.y = v->value; break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool record_wheel(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
if (v->type != EV_REL)
|
||||
return false;
|
||||
|
||||
switch (v->code) {
|
||||
case REL_HWHEEL: evdev->wheel.pending = true; evdev->wheel.x += v->value; break;
|
||||
case REL_WHEEL: evdev->wheel.pending = true; evdev->wheel.y += v->value; break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool record_pointer(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
if (evdev->motion != MOTION_POINTER)
|
||||
return false;
|
||||
|
||||
return record_abs(evdev, v) || record_wheel(evdev, v);
|
||||
}
|
||||
|
||||
|
||||
static bool record_touchtool(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
if (evdev->motion != MOTION_TOUCHTOOL)
|
||||
return false;
|
||||
|
||||
return record_abs(evdev, v) || record_wheel(evdev, v);
|
||||
}
|
||||
|
||||
|
||||
static bool record_mt(struct evdev_mt *mt, struct input_value const *v)
|
||||
{
|
||||
if (v->type != EV_ABS || !mt->num_slots)
|
||||
return false;
|
||||
|
||||
switch (v->code) {
|
||||
case ABS_MT_SLOT:
|
||||
mt->cur_slot = (v->value >= 0 ? v->value : 0);
|
||||
/* nothing pending yet */
|
||||
break;
|
||||
|
||||
case ABS_MT_TRACKING_ID:
|
||||
if (mt->cur_slot < mt->num_slots) {
|
||||
mt->slots[mt->cur_slot].id = v->value >= 0 ? mt->cur_slot : -1;
|
||||
mt->pending = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ABS_MT_POSITION_X:
|
||||
if (mt->cur_slot < mt->num_slots) {
|
||||
mt->slots[mt->cur_slot].x = v->value;
|
||||
mt->pending = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case ABS_MT_POSITION_Y:
|
||||
if (mt->cur_slot < mt->num_slots) {
|
||||
mt->slots[mt->cur_slot].y = v->value;
|
||||
mt->pending = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool record_touchpad(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
if (evdev->motion != MOTION_TOUCHPAD)
|
||||
return false;
|
||||
|
||||
/* monitor (physical) button state clashing with tap-to-click */
|
||||
if (v->type == EV_KEY && v->code == BTN_LEFT)
|
||||
evdev->touchpad.btn_left_pressed = !!v->value;
|
||||
|
||||
/* only multi-touch pads supported currently */
|
||||
return record_mt(&evdev->mt, v);
|
||||
}
|
||||
|
||||
|
||||
static bool record_touchscreen(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
if (evdev->motion != MOTION_TOUCHSCREEN)
|
||||
return false;
|
||||
|
||||
/* only multi-touch screens supported currently */
|
||||
return record_mt(&evdev->mt, v);
|
||||
}
|
||||
|
||||
|
||||
static bool is_tool_key(unsigned code)
|
||||
{
|
||||
switch (code) {
|
||||
case BTN_TOOL_PEN:
|
||||
case BTN_TOOL_RUBBER:
|
||||
case BTN_TOOL_BRUSH:
|
||||
case BTN_TOOL_PENCIL:
|
||||
case BTN_TOOL_AIRBRUSH:
|
||||
case BTN_TOOL_FINGER:
|
||||
case BTN_TOOL_MOUSE:
|
||||
case BTN_TOOL_LENS:
|
||||
case BTN_TOOL_QUINTTAP:
|
||||
case BTN_TOOL_DOUBLETAP:
|
||||
case BTN_TOOL_TRIPLETAP:
|
||||
case BTN_TOOL_QUADTAP:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool record_key(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
struct evdev_keys * const keys = &evdev->keys;
|
||||
|
||||
if (v->type != EV_KEY)
|
||||
return false;
|
||||
|
||||
if (is_tool_key(v->code)) {
|
||||
evdev->tool = v->value ? v->code : 0;
|
||||
} else {
|
||||
struct evdev_key *key;
|
||||
for_each_key(key, keys, false) {
|
||||
if (key->pending)
|
||||
continue;
|
||||
|
||||
*key = EVDEV_KEY(v->code, !!v->value);
|
||||
keys->pending++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void submit_press_release(struct evdev_key *key, struct evdev_keys *keys,
|
||||
struct genode_event_submit *submit)
|
||||
{
|
||||
if (!key->pending)
|
||||
return;
|
||||
|
||||
if (key->press)
|
||||
submit->press(submit, lx_emul_event_keycode(key->code));
|
||||
else
|
||||
submit->release(submit, lx_emul_event_keycode(key->code));
|
||||
|
||||
*key = INIT_KEY;
|
||||
keys->pending--;
|
||||
}
|
||||
|
||||
|
||||
static void submit_keys(struct evdev_keys *keys, struct genode_event_submit *submit)
|
||||
{
|
||||
struct evdev_key *key;
|
||||
|
||||
if (!keys->pending)
|
||||
return;
|
||||
|
||||
for_each_pending_key(key, keys)
|
||||
submit_press_release(key, keys, submit);
|
||||
}
|
||||
|
||||
|
||||
static void submit_mouse(struct evdev *evdev, struct genode_event_submit *submit)
|
||||
{
|
||||
if (evdev->motion != MOTION_MOUSE)
|
||||
return;
|
||||
|
||||
if (evdev->rel.pending) {
|
||||
submit->rel_motion(submit, evdev->rel.x, evdev->rel.y);
|
||||
evdev->rel = INIT_XY;
|
||||
}
|
||||
|
||||
if (evdev->wheel.pending) {
|
||||
submit->wheel(submit, evdev->wheel.x, evdev->wheel.y);
|
||||
evdev->wheel = INIT_XY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void submit_pointer(struct evdev *evdev, struct genode_event_submit *submit)
|
||||
{
|
||||
if (evdev->motion != MOTION_POINTER)
|
||||
return;
|
||||
|
||||
if (evdev->abs.pending) {
|
||||
submit->abs_motion(submit, evdev->abs.x, evdev->abs.y);
|
||||
evdev->abs.pending = false;
|
||||
}
|
||||
|
||||
if (evdev->wheel.pending) {
|
||||
submit->wheel(submit, evdev->wheel.x, evdev->wheel.y);
|
||||
evdev->wheel = INIT_XY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void submit_touchtool(struct evdev *evdev, struct genode_event_submit *submit)
|
||||
{
|
||||
struct evdev_keys * const keys = &evdev->keys;
|
||||
|
||||
struct evdev_key *key;
|
||||
|
||||
if (evdev->motion != MOTION_TOUCHTOOL)
|
||||
return;
|
||||
|
||||
if (evdev->abs.pending) {
|
||||
submit->abs_motion(submit, evdev->abs.x, evdev->abs.y);
|
||||
evdev->abs.pending = false;
|
||||
}
|
||||
|
||||
/* submit recorded tool on BTN_TOUCH */
|
||||
for_each_pending_key(key, keys) {
|
||||
if (key->code != BTN_TOUCH)
|
||||
continue;
|
||||
|
||||
key->code = evdev->tool;
|
||||
submit_press_release(key, keys, submit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void touchpad_tap_to_click(struct evdev_keys *keys, struct evdev_touchpad *tp,
|
||||
struct genode_event_submit *submit)
|
||||
{
|
||||
enum { TAP_TIME = 130 /* max touch duration in ms */ };
|
||||
|
||||
struct evdev_key *key;
|
||||
|
||||
if (!keys->pending)
|
||||
return;
|
||||
|
||||
for_each_pending_key(key, keys) {
|
||||
if (key->code != BTN_TOUCH)
|
||||
continue;
|
||||
|
||||
if (key->press && !tp->btn_left_pressed) {
|
||||
tp->touch_time = key->jiffies;
|
||||
} else {
|
||||
if (time_before(key->jiffies, tp->touch_time + msecs_to_jiffies(TAP_TIME))) {
|
||||
submit->press(submit, lx_emul_event_keycode(BTN_LEFT));
|
||||
submit->release(submit, lx_emul_event_keycode(BTN_LEFT));
|
||||
}
|
||||
tp->touch_time = 0;
|
||||
}
|
||||
|
||||
*key = INIT_KEY;
|
||||
keys->pending--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void submit_touchpad(struct evdev *evdev, struct genode_event_submit *submit)
|
||||
{
|
||||
struct evdev_mt * const mt = &evdev->mt;
|
||||
|
||||
struct evdev_mt_slot *slot;
|
||||
|
||||
if (evdev->motion != MOTION_TOUCHPAD)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO device state model
|
||||
*
|
||||
* - click without small motion (if pad is pressable button)
|
||||
* - two-finger scrolling
|
||||
* - edge scrolling
|
||||
* - virtual-button regions
|
||||
*
|
||||
* https://wayland.freedesktop.org/libinput/doc/latest/tapping.html
|
||||
*/
|
||||
|
||||
if (mt->pending) {
|
||||
for_each_mt_slot(slot, mt) {
|
||||
if (slot->id == -1) {
|
||||
*slot = INIT_MT_SLOT;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slot->ox != -1 && slot->oy != -1)
|
||||
submit->rel_motion(submit, slot->x - slot->ox, slot->y - slot->oy);
|
||||
|
||||
slot->ox = slot->x;
|
||||
slot->oy = slot->y;
|
||||
}
|
||||
|
||||
mt->pending = false;
|
||||
}
|
||||
|
||||
touchpad_tap_to_click(&evdev->keys, &evdev->touchpad, submit);
|
||||
}
|
||||
|
||||
|
||||
static void submit_touchscreen(struct evdev *evdev, struct genode_event_submit *submit)
|
||||
{
|
||||
struct evdev_mt * const mt = &evdev->mt;
|
||||
struct evdev_keys * const keys = &evdev->keys;
|
||||
|
||||
struct evdev_key *key;
|
||||
struct evdev_mt_slot *slot;
|
||||
|
||||
if (evdev->motion != MOTION_TOUCHSCREEN)
|
||||
return;
|
||||
|
||||
if (mt->pending) {
|
||||
for_each_mt_slot(slot, mt) {
|
||||
if (slot->id == -1 && slot->ox != -1 && slot->oy != -1) {
|
||||
submit->touch_release(submit, slot->id);
|
||||
|
||||
*slot = INIT_MT_SLOT;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip unchanged slots */
|
||||
if (slot->ox == slot->x && slot->oy == slot->y)
|
||||
continue;
|
||||
|
||||
if (slot->x != -1 && slot->y != -1) {
|
||||
struct genode_event_touch_args args = {
|
||||
.finger = slot->id,
|
||||
.xpos = slot->x,
|
||||
.ypos = slot->y,
|
||||
.width = 1
|
||||
};
|
||||
submit->touch(submit, &args);
|
||||
}
|
||||
|
||||
slot->ox = slot->x;
|
||||
slot->oy = slot->y;
|
||||
}
|
||||
|
||||
mt->pending = false;
|
||||
}
|
||||
|
||||
/* filter BTN_TOUCH */
|
||||
for_each_pending_key(key, keys) {
|
||||
if (key->code != BTN_TOUCH)
|
||||
continue;
|
||||
|
||||
*key = INIT_KEY;
|
||||
keys->pending--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool submit_on_syn(struct evdev *evdev, struct input_value const *v,
|
||||
struct genode_event_submit *submit)
|
||||
{
|
||||
if (v->type != EV_SYN || v->code != SYN_REPORT)
|
||||
return false;
|
||||
|
||||
/* motion devices */
|
||||
submit_mouse(evdev, submit);
|
||||
submit_pointer(evdev, submit);
|
||||
submit_touchpad(evdev, submit);
|
||||
submit_touchtool(evdev, submit);
|
||||
submit_touchscreen(evdev, submit);
|
||||
|
||||
/* submit keys not handled above */
|
||||
submit_keys(&evdev->keys, submit);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct genode_event_generator_ctx
|
||||
{
|
||||
struct evdev *evdev;
|
||||
@ -85,222 +637,6 @@ struct genode_event_generator_ctx
|
||||
};
|
||||
|
||||
|
||||
struct name { char s[32]; };
|
||||
#define NAME_INIT(name, fmt, ...) snprintf(name.s, sizeof(name.s), fmt, ## __VA_ARGS__)
|
||||
|
||||
|
||||
static struct name name_of_type(unsigned type)
|
||||
{
|
||||
struct name result = { { 0 } };
|
||||
|
||||
switch (type) {
|
||||
case EV_SYN: NAME_INIT(result, "SYN"); break;
|
||||
case EV_KEY: NAME_INIT(result, "KEY"); break;
|
||||
case EV_REL: NAME_INIT(result, "REL"); break;
|
||||
case EV_ABS: NAME_INIT(result, "ABS"); break;
|
||||
case EV_MSC: NAME_INIT(result, "MSC"); break;
|
||||
default: NAME_INIT(result, "%3u", type);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#define NAME_OF_TYPE(type) name_of_type(type).s
|
||||
|
||||
|
||||
static struct name name_of_code(unsigned type, unsigned code)
|
||||
{
|
||||
struct name result = { { 0 } };
|
||||
|
||||
switch (type) {
|
||||
case EV_SYN:
|
||||
switch (code) {
|
||||
case SYN_REPORT: NAME_INIT(result, "REPORT"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
case EV_KEY:
|
||||
switch (code) {
|
||||
case BTN_LEFT: NAME_INIT(result, "BTN_LEFT"); break;
|
||||
case BTN_RIGHT: NAME_INIT(result, "BTN_RIGHT"); break;
|
||||
case BTN_TOOL_FINGER: NAME_INIT(result, "BTN_TOOL_FINGER"); break;
|
||||
case BTN_TOUCH: NAME_INIT(result, "BTN_TOUCH"); break;
|
||||
case BTN_TOOL_DOUBLETAP: NAME_INIT(result, "BTN_TOOL_DOUBLETAP"); break;
|
||||
case BTN_TOOL_TRIPLETAP: NAME_INIT(result, "BTN_TOOL_TRIPLETAP"); break;
|
||||
case BTN_TOOL_QUADTAP: NAME_INIT(result, "BTN_TOOL_QUADTAP"); break;
|
||||
case BTN_TOOL_QUINTTAP: NAME_INIT(result, "BTN_TOOL_QUINTTAP"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
case EV_REL:
|
||||
switch (code) {
|
||||
case REL_X: NAME_INIT(result, "X"); break;
|
||||
case REL_Y: NAME_INIT(result, "Y"); break;
|
||||
case REL_HWHEEL: NAME_INIT(result, "HWHEEL"); break;
|
||||
case REL_WHEEL: NAME_INIT(result, "WHEEL"); break;
|
||||
case REL_MISC: NAME_INIT(result, "MISC"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
case EV_ABS:
|
||||
switch (code) {
|
||||
case ABS_X: NAME_INIT(result, "X"); break;
|
||||
case ABS_Y: NAME_INIT(result, "Y"); break;
|
||||
case ABS_MISC: NAME_INIT(result, "MISC"); break;
|
||||
case ABS_MT_SLOT: NAME_INIT(result, "MT_SLOT"); break;
|
||||
case ABS_MT_POSITION_X: NAME_INIT(result, "MT_POSITION_X"); break;
|
||||
case ABS_MT_POSITION_Y: NAME_INIT(result, "MT_POSITION_Y"); break;
|
||||
case ABS_MT_TOOL_TYPE: NAME_INIT(result, "MT_TOOL_TYPE"); break;
|
||||
case ABS_MT_TRACKING_ID: NAME_INIT(result, "MT_TRACKING_ID"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
case EV_MSC:
|
||||
switch (code) {
|
||||
case MSC_SCAN: NAME_INIT(result, "SCAN"); break;
|
||||
case MSC_TIMESTAMP: NAME_INIT(result, "TIMESTAMP"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#define NAME_OF_CODE(type, code) name_of_code(type, code).s
|
||||
|
||||
|
||||
static bool handle_key(struct evdev *evdev, struct input_value const *v,
|
||||
struct genode_event_submit *submit)
|
||||
{
|
||||
unsigned code = v->code;
|
||||
|
||||
if (v->type != EV_KEY)
|
||||
return false;
|
||||
|
||||
/* map BTN_TOUCH to BTN_LEFT */
|
||||
if (code == BTN_TOUCH) code = BTN_LEFT;
|
||||
|
||||
if (v->value)
|
||||
submit->press(submit, lx_emul_event_keycode(code));
|
||||
else
|
||||
submit->release(submit, lx_emul_event_keycode(code));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool record_rel(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
if (v->type != EV_REL)
|
||||
return false;
|
||||
|
||||
switch (v->code) {
|
||||
case REL_X: evdev->rel_x += v->value; break;
|
||||
case REL_Y: evdev->rel_y += v->value; break;
|
||||
case REL_HWHEEL: evdev->rel_wx += v->value; break;
|
||||
case REL_WHEEL: evdev->rel_wy += v->value; break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
evdev->pending++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool record_abs(struct evdev *evdev, struct input_value const *v)
|
||||
{
|
||||
struct evdev_mt * const mt = &evdev->mt;
|
||||
|
||||
if (v->type != EV_ABS)
|
||||
return false;
|
||||
|
||||
if (mt->num_slots) {
|
||||
switch (v->code) {
|
||||
case ABS_MT_SLOT:
|
||||
mt->cur_slot = (v->value >= 0 ? v->value : 0);
|
||||
break;
|
||||
|
||||
case ABS_MT_TRACKING_ID:
|
||||
if (mt->cur_slot < mt->num_slots) {
|
||||
mt->slots[mt->cur_slot] = INIT_MT_SLOT;
|
||||
evdev->pending++;
|
||||
}
|
||||
break;
|
||||
|
||||
case ABS_MT_POSITION_X:
|
||||
if (mt->cur_slot < mt->num_slots) {
|
||||
mt->slots[mt->cur_slot].x = v->value;
|
||||
evdev->pending++;
|
||||
}
|
||||
break;
|
||||
|
||||
case ABS_MT_POSITION_Y:
|
||||
if (mt->cur_slot < mt->num_slots) {
|
||||
mt->slots[mt->cur_slot].y = v->value;
|
||||
evdev->pending++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
/* XXX absolute events not supported currently */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static void submit_mt_motion(struct evdev_mt_slot *slot,
|
||||
struct genode_event_submit *submit)
|
||||
{
|
||||
if (slot->ox != -1 && slot->oy != -1)
|
||||
submit->rel_motion(submit, slot->x - slot->ox, slot->y - slot->oy);
|
||||
|
||||
slot->ox = slot->x;
|
||||
slot->oy = slot->y;
|
||||
}
|
||||
|
||||
|
||||
static bool submit_on_syn(struct evdev *evdev, struct input_value const *v,
|
||||
struct genode_event_submit *submit)
|
||||
{
|
||||
struct evdev_mt * const mt = &evdev->mt;
|
||||
|
||||
if (v->type != EV_SYN || v->code != SYN_REPORT)
|
||||
return false;
|
||||
if (!evdev->pending)
|
||||
return true;
|
||||
|
||||
if (mt->num_slots) {
|
||||
submit_mt_motion(&mt->slots[PRIMARY], submit);
|
||||
submit_mt_motion(&mt->slots[SECONDARY], submit);
|
||||
} else {
|
||||
if (evdev->rel_x || evdev->rel_y) {
|
||||
submit->rel_motion(submit, evdev->rel_x, evdev->rel_y);
|
||||
evdev->rel_x = evdev->rel_y = 0;
|
||||
}
|
||||
if (evdev->rel_wx || evdev->rel_wy) {
|
||||
submit->wheel(submit, evdev->rel_wx, evdev->rel_wy);
|
||||
evdev->rel_wx = evdev->rel_wy = 0;
|
||||
}
|
||||
/* XXX absolute events not supported currently */
|
||||
}
|
||||
|
||||
evdev->pending = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void evdev_event_generator(struct genode_event_generator_ctx *ctx,
|
||||
struct genode_event_submit *submit)
|
||||
{
|
||||
@ -317,9 +653,12 @@ static void evdev_event_generator(struct genode_event_generator_ctx *ctx,
|
||||
/* filter input_repeat_key() */
|
||||
if ((v->type == EV_KEY) && (v->value > 1)) continue;
|
||||
|
||||
processed |= handle_key(evdev, v, submit);
|
||||
processed |= record_abs(evdev, v);
|
||||
processed |= record_rel(evdev, v);
|
||||
processed |= record_mouse(evdev, v);
|
||||
processed |= record_pointer(evdev, v);
|
||||
processed |= record_touchpad(evdev, v);
|
||||
processed |= record_touchtool(evdev, v);
|
||||
processed |= record_touchscreen(evdev, v);
|
||||
processed |= record_key(evdev, v);
|
||||
processed |= submit_on_syn(evdev, v, submit);
|
||||
|
||||
if (!processed)
|
||||
@ -351,6 +690,55 @@ static void evdev_event(struct input_handle *handle,
|
||||
}
|
||||
|
||||
|
||||
static void init_motion(struct evdev *evdev)
|
||||
{
|
||||
struct input_dev *dev = evdev->handle.dev;
|
||||
|
||||
evdev->motion = evdev_motion(dev);
|
||||
|
||||
switch (evdev->motion) {
|
||||
case MOTION_NONE:
|
||||
case MOTION_MOUSE:
|
||||
case MOTION_POINTER:
|
||||
/* nothing to do */
|
||||
break;
|
||||
|
||||
case MOTION_TOUCHPAD:
|
||||
case MOTION_TOUCHTOOL:
|
||||
case MOTION_TOUCHSCREEN:
|
||||
if (dev->mt) {
|
||||
struct evdev_mt *mt = &evdev->mt;
|
||||
|
||||
struct evdev_mt_slot *slot;
|
||||
|
||||
mt->num_slots = min(dev->mt->num_slots, MAX_MT_SLOTS);
|
||||
mt->cur_slot = 0;
|
||||
for_each_mt_slot(slot, mt)
|
||||
*slot = INIT_MT_SLOT;
|
||||
|
||||
/* disable undesired events */
|
||||
clear_bit(ABS_X, dev->absbit);
|
||||
clear_bit(ABS_Y, dev->absbit);
|
||||
clear_bit(ABS_PRESSURE, dev->absbit);
|
||||
clear_bit(ABS_MT_TOUCH_MAJOR, dev->absbit);
|
||||
clear_bit(ABS_MT_TOUCH_MINOR, dev->absbit);
|
||||
clear_bit(ABS_MT_WIDTH_MAJOR, dev->absbit);
|
||||
clear_bit(ABS_MT_WIDTH_MINOR, dev->absbit);
|
||||
clear_bit(ABS_MT_ORIENTATION, dev->absbit);
|
||||
clear_bit(ABS_MT_TOOL_TYPE, dev->absbit);
|
||||
clear_bit(ABS_MT_PRESSURE, dev->absbit);
|
||||
clear_bit(ABS_MT_TOOL_X, dev->absbit);
|
||||
clear_bit(ABS_MT_TOOL_Y, dev->absbit);
|
||||
} else {
|
||||
/* disable undesired events */
|
||||
clear_bit(ABS_PRESSURE, dev->absbit);
|
||||
clear_bit(ABS_DISTANCE, dev->absbit);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
const struct input_device_id *id)
|
||||
{
|
||||
@ -369,25 +757,7 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
evdev->handle.handler = handler;
|
||||
evdev->handle.name = dev->name;
|
||||
|
||||
if (dev->mt) {
|
||||
struct evdev_mt *mt = &evdev->mt;
|
||||
|
||||
mt->num_slots = min(dev->mt->num_slots, MAX_MT_SLOTS);
|
||||
mt->cur_slot = 0;
|
||||
for (int i = 0; i < sizeof(mt->slots)/sizeof(*mt->slots); i++)
|
||||
mt->slots[i] = INIT_MT_SLOT;
|
||||
|
||||
/* disable undesired events */
|
||||
clear_bit(ABS_MT_TOOL_TYPE, dev->absbit);
|
||||
clear_bit(ABS_X, dev->absbit);
|
||||
clear_bit(ABS_Y, dev->absbit);
|
||||
clear_bit(BTN_TOOL_FINGER, dev->keybit);
|
||||
clear_bit(BTN_TOOL_DOUBLETAP, dev->keybit);
|
||||
clear_bit(BTN_TOOL_TRIPLETAP, dev->keybit);
|
||||
clear_bit(BTN_TOOL_QUADTAP, dev->keybit);
|
||||
clear_bit(BTN_TOOL_QUINTTAP, dev->keybit);
|
||||
clear_bit(BTN_TOUCH, dev->keybit);
|
||||
}
|
||||
init_motion(evdev);
|
||||
|
||||
/* disable undesired events */
|
||||
clear_bit(EV_MSC, dev->evbit);
|
||||
@ -402,10 +772,12 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
|
||||
if (error)
|
||||
goto err_unregister_handle;
|
||||
|
||||
printk("Connected device: %s (%s at %s)\n",
|
||||
printk("Connected device: %s (%s at %s) %s%s\n",
|
||||
dev_name(&dev->dev),
|
||||
dev->name ?: "unknown",
|
||||
dev->phys ?: "unknown");
|
||||
dev->phys ?: "unknown",
|
||||
dev->mt ? "MULTITOUCH " : "",
|
||||
evdev->motion != MOTION_NONE ? NAME_OF_MOTION(evdev->motion) : "");
|
||||
|
||||
return 0;
|
||||
|
||||
|
223
repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/evdev.h
Normal file
223
repos/dde_linux/src/lib/lx_emul/shadow/drivers/input/evdev.h
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* \brief Linux emulation environment: evdev helpers
|
||||
* \author Christian Helmuth
|
||||
* \date 2024-01-29
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2024 Genode Labs GmbH
|
||||
*
|
||||
* This file is distributed under the terms of the GNU General Public License
|
||||
* version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SHADOW__DRIVERS__INPUT__EVDEV_H_
|
||||
#define _SHADOW__DRIVERS__INPUT__EVDEV_H_
|
||||
|
||||
|
||||
struct name { char s[32]; };
|
||||
#define NAME_INIT(name, fmt, ...) snprintf(name.s, sizeof(name.s), fmt, ## __VA_ARGS__)
|
||||
|
||||
static struct name name_of_motion(enum evdev_motion motion)
|
||||
{
|
||||
struct name result = { { 0 } };
|
||||
|
||||
switch (motion) {
|
||||
case MOTION_NONE: NAME_INIT(result, "NONE"); break;
|
||||
case MOTION_MOUSE: NAME_INIT(result, "MOUSE"); break;
|
||||
case MOTION_POINTER: NAME_INIT(result, "POINTER"); break;
|
||||
case MOTION_TOUCHPAD: NAME_INIT(result, "TOUCHPAD"); break;
|
||||
case MOTION_TOUCHTOOL: NAME_INIT(result, "TOUCHTOOL"); break;
|
||||
case MOTION_TOUCHSCREEN: NAME_INIT(result, "TOUCHSCREEN"); break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#define NAME_OF_MOTION(type) name_of_motion(type).s
|
||||
|
||||
static struct name name_of_prop(unsigned prop)
|
||||
{
|
||||
struct name result = { { 0 } };
|
||||
|
||||
switch (prop) {
|
||||
case INPUT_PROP_POINTER: NAME_INIT(result, "POINTER"); break;
|
||||
case INPUT_PROP_DIRECT: NAME_INIT(result, "DIRECT"); break;
|
||||
case INPUT_PROP_BUTTONPAD: NAME_INIT(result, "BUTTONPAD"); break;
|
||||
case INPUT_PROP_SEMI_MT: NAME_INIT(result, "SEMI_MT"); break;
|
||||
case INPUT_PROP_TOPBUTTONPAD: NAME_INIT(result, "TOPBUTTONPAD"); break;
|
||||
case INPUT_PROP_POINTING_STICK: NAME_INIT(result, "POINTING_STICK"); break;
|
||||
case INPUT_PROP_ACCELEROMETER: NAME_INIT(result, "ACCELEROMETER"); break;
|
||||
default: NAME_INIT(result, "%2u", prop);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#define NAME_OF_PROP(type) name_of_prop(type).s
|
||||
|
||||
static struct name name_of_type(unsigned type)
|
||||
{
|
||||
struct name result = { { 0 } };
|
||||
|
||||
switch (type) {
|
||||
case EV_SYN: NAME_INIT(result, "SYN"); break;
|
||||
case EV_KEY: NAME_INIT(result, "KEY"); break;
|
||||
case EV_REL: NAME_INIT(result, "REL"); break;
|
||||
case EV_ABS: NAME_INIT(result, "ABS"); break;
|
||||
case EV_MSC: NAME_INIT(result, "MSC"); break;
|
||||
case EV_SW: NAME_INIT(result, "SW "); break;
|
||||
case EV_LED: NAME_INIT(result, "LED"); break;
|
||||
case EV_REP: NAME_INIT(result, "REP"); break;
|
||||
default: NAME_INIT(result, "%3u", type);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#define NAME_OF_TYPE(type) name_of_type(type).s
|
||||
|
||||
static struct name name_of_code(unsigned type, unsigned code)
|
||||
{
|
||||
struct name result = { { 0 } };
|
||||
|
||||
switch (type) {
|
||||
case EV_SYN:
|
||||
switch (code) {
|
||||
case SYN_REPORT: NAME_INIT(result, "REPORT"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
case EV_KEY:
|
||||
switch (code) {
|
||||
case BTN_LEFT: NAME_INIT(result, "BTN_LEFT"); break;
|
||||
case BTN_RIGHT: NAME_INIT(result, "BTN_RIGHT"); break;
|
||||
case BTN_MIDDLE: NAME_INIT(result, "BTN_MIDDLE"); break;
|
||||
case BTN_SIDE: NAME_INIT(result, "BTN_SIDE"); break;
|
||||
case BTN_EXTRA: NAME_INIT(result, "BTN_EXTRA"); break;
|
||||
case BTN_FORWARD: NAME_INIT(result, "BTN_FORWARD"); break;
|
||||
case BTN_BACK: NAME_INIT(result, "BTN_BACK"); break;
|
||||
case BTN_TASK: NAME_INIT(result, "BTN_TASK"); break;
|
||||
case BTN_TOOL_PEN: NAME_INIT(result, "BTN_TOOL_PEN"); break;
|
||||
case BTN_TOOL_RUBBER: NAME_INIT(result, "BTN_TOOL_RUBBER"); break;
|
||||
case BTN_TOOL_FINGER: NAME_INIT(result, "BTN_TOOL_FINGER"); break;
|
||||
case BTN_TOUCH: NAME_INIT(result, "BTN_TOUCH"); break;
|
||||
case BTN_STYLUS: NAME_INIT(result, "BTN_STYLUS"); break;
|
||||
case BTN_STYLUS2: NAME_INIT(result, "BTN_STYLUS2"); break;
|
||||
case BTN_TOOL_DOUBLETAP: NAME_INIT(result, "BTN_TOOL_DOUBLETAP"); break;
|
||||
case BTN_TOOL_TRIPLETAP: NAME_INIT(result, "BTN_TOOL_TRIPLETAP"); break;
|
||||
case BTN_TOOL_QUADTAP: NAME_INIT(result, "BTN_TOOL_QUADTAP"); break;
|
||||
case BTN_TOOL_QUINTTAP: NAME_INIT(result, "BTN_TOOL_QUINTTAP"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
case EV_REL:
|
||||
switch (code) {
|
||||
case REL_X: NAME_INIT(result, "X"); break;
|
||||
case REL_Y: NAME_INIT(result, "Y"); break;
|
||||
case REL_HWHEEL: NAME_INIT(result, "HWHEEL"); break;
|
||||
case REL_WHEEL: NAME_INIT(result, "WHEEL"); break;
|
||||
case REL_MISC: NAME_INIT(result, "MISC"); break;
|
||||
case REL_WHEEL_HI_RES: NAME_INIT(result, "WHEEL_HI_RES"); break;
|
||||
case REL_HWHEEL_HI_RES: NAME_INIT(result, "HWHEEL_HI_RES"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
case EV_ABS:
|
||||
switch (code) {
|
||||
case ABS_X: NAME_INIT(result, "X"); break;
|
||||
case ABS_Y: NAME_INIT(result, "Y"); break;
|
||||
case ABS_PRESSURE: NAME_INIT(result, "PRESSURE"); break;
|
||||
case ABS_DISTANCE: NAME_INIT(result, "DISTANCE"); break;
|
||||
case ABS_MISC: NAME_INIT(result, "MISC"); break;
|
||||
case ABS_MT_SLOT: NAME_INIT(result, "MT_SLOT"); break;
|
||||
case ABS_MT_TOUCH_MAJOR: NAME_INIT(result, "MT_TOUCH_MAJOR"); break;
|
||||
case ABS_MT_TOUCH_MINOR: NAME_INIT(result, "MT_TOUCH_MINOR"); break;
|
||||
case ABS_MT_WIDTH_MAJOR: NAME_INIT(result, "MT_WIDTH_MAJOR"); break;
|
||||
case ABS_MT_WIDTH_MINOR: NAME_INIT(result, "MT_WIDTH_MINOR"); break;
|
||||
case ABS_MT_ORIENTATION: NAME_INIT(result, "MT_ORIENTATION"); break;
|
||||
case ABS_MT_POSITION_X: NAME_INIT(result, "MT_POSITION_X"); break;
|
||||
case ABS_MT_POSITION_Y: NAME_INIT(result, "MT_POSITION_Y"); break;
|
||||
case ABS_MT_TOOL_TYPE: NAME_INIT(result, "MT_TOOL_TYPE"); break;
|
||||
case ABS_MT_TRACKING_ID: NAME_INIT(result, "MT_TRACKING_ID"); break;
|
||||
case ABS_MT_PRESSURE: NAME_INIT(result, "MT_PRESSURE"); break;
|
||||
case ABS_MT_DISTANCE: NAME_INIT(result, "MT_DISTANCE"); break;
|
||||
case ABS_MT_TOOL_X: NAME_INIT(result, "MT_TOOL_X"); break;
|
||||
case ABS_MT_TOOL_Y: NAME_INIT(result, "MT_TOOL_Y"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
case EV_MSC:
|
||||
switch (code) {
|
||||
case MSC_SCAN: NAME_INIT(result, "SCAN"); break;
|
||||
case MSC_TIMESTAMP: NAME_INIT(result, "TIMESTAMP"); break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
} break;
|
||||
|
||||
default: NAME_INIT(result, "%u", code);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#define NAME_OF_CODE(type, code) name_of_code(type, code).s
|
||||
|
||||
static void log_event_in_packet(unsigned cur, unsigned max,
|
||||
struct input_value const *v,
|
||||
struct evdev const *evdev)
|
||||
{
|
||||
printk("--- Event[%u/%u] %s '%s' %s type=%s code=%s value=%d\n", cur, max,
|
||||
dev_name(&evdev->handle.dev->dev), evdev->handle.dev->name, NAME_OF_MOTION(evdev->motion),
|
||||
NAME_OF_TYPE(v->type), NAME_OF_CODE(v->type, v->code), v->value);
|
||||
}
|
||||
|
||||
static void log_device_info(struct input_dev *dev)
|
||||
{
|
||||
unsigned bit;
|
||||
|
||||
printk("device: %s (%s at %s)\n", dev_name(&dev->dev), dev->name ?: "unknown", dev->phys ?: "unknown");
|
||||
printk(" propbit:");
|
||||
for_each_set_bit(bit, dev->propbit, INPUT_PROP_CNT)
|
||||
printk(" %s", NAME_OF_PROP(bit));
|
||||
printk("\n");
|
||||
printk(" evbit: ");
|
||||
for_each_set_bit(bit, dev->evbit, EV_CNT)
|
||||
printk(" %s", NAME_OF_TYPE(bit));
|
||||
printk("\n");
|
||||
|
||||
if (test_bit(EV_REL, dev->evbit)) {
|
||||
printk(" relbit: ");
|
||||
for_each_set_bit(bit, dev->relbit, REL_CNT)
|
||||
printk(" %s", NAME_OF_CODE(EV_REL, bit));
|
||||
printk("\n");
|
||||
}
|
||||
if (test_bit(EV_ABS, dev->evbit)) {
|
||||
printk(" absbit: ");
|
||||
for_each_set_bit(bit, dev->absbit, ABS_CNT)
|
||||
printk(" %s", NAME_OF_CODE(EV_ABS, bit));
|
||||
printk("\n");
|
||||
}
|
||||
if (test_bit(EV_ABS, dev->evbit) || test_bit(EV_REL, dev->evbit)) {
|
||||
printk(" keybit: ");
|
||||
for_each_set_bit(bit, dev->keybit, KEY_CNT)
|
||||
printk(" %s", NAME_OF_CODE(EV_KEY, bit));
|
||||
printk("\n");
|
||||
}
|
||||
if (test_bit(EV_LED, dev->evbit)) {
|
||||
unsigned count = 0;
|
||||
for_each_set_bit(bit, dev->ledbit, LED_CNT)
|
||||
count++;
|
||||
printk(" leds: %u\n", count);
|
||||
}
|
||||
printk(" hint_events_per_packet: %u max_vals: %u\n", dev->hint_events_per_packet, dev->max_vals);
|
||||
if (dev->mt) {
|
||||
printk(" dev->mt->flags=%x\n", dev->mt->flags);
|
||||
printk(" dev->mt->num_slots=%u\n", dev->mt->num_slots);
|
||||
}
|
||||
if (dev->absinfo) {
|
||||
printk(" absinfo: %px\n", dev->absinfo);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _SHADOW__DRIVERS__INPUT__EVDEV_H_ */
|
@ -307,8 +307,8 @@ trim_lines
|
||||
compare_output_to {
|
||||
[init -> log_terminal] [init -> event_dump] Input event #0 PRESS KEY_X 65534 key count: 1
|
||||
[init -> log_terminal] [init -> event_dump] Input event #1 RELEASE KEY_X key count: 0
|
||||
[init -> log_terminal] [init -> event_dump] Input event #2 PRESS BTN_LEFT 65534 key count: 1
|
||||
[init -> log_terminal] [init -> event_dump] Input event #3 REL_MOTION -1+1 key count: 1
|
||||
[init -> log_terminal] [init -> event_dump] Input event #2 REL_MOTION -1+1 key count: 0
|
||||
[init -> log_terminal] [init -> event_dump] Input event #3 PRESS BTN_LEFT 65534 key count: 1
|
||||
[init -> log_terminal] [init -> event_dump] Input event #4 RELEASE BTN_LEFT key count: 0
|
||||
[init -> log_terminal] [init -> usb_hid_drv] usb usb-X-X: USB disconnect, device number X
|
||||
[init -> log_terminal] [init -> usb_hid_drv] Disconnected device: inputX
|
||||
@ -318,11 +318,11 @@ compare_output_to {
|
||||
[init -> log_terminal] [init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d)
|
||||
[init -> log_terminal] [init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Keyboard [HID 03eb:204d]
|
||||
[init -> log_terminal] [init -> usb_hid_drv] input: HID 03eb:204d
|
||||
[init -> log_terminal] [init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d)
|
||||
[init -> log_terminal] [init -> usb_hid_drv] Connected device: inputX (HID 03eb:204d) MOUSE
|
||||
[init -> log_terminal] [init -> usb_hid_drv] hid-generic: input: USB HID v1.11 Mouse [HID 03eb:204d]
|
||||
[init -> log_terminal] [init -> event_dump] Input event #5 PRESS KEY_X 65534 key count: 1
|
||||
[init -> log_terminal] [init -> event_dump] Input event #6 RELEASE KEY_X key count: 0
|
||||
[init -> log_terminal] [init -> event_dump] Input event #7 PRESS BTN_LEFT 65534 key count: 1
|
||||
[init -> log_terminal] [init -> event_dump] Input event #8 REL_MOTION -1+1 key count: 1
|
||||
[init -> log_terminal] [init -> event_dump] Input event #7 REL_MOTION -1+1 key count: 0
|
||||
[init -> log_terminal] [init -> event_dump] Input event #8 PRESS BTN_LEFT 65534 key count: 1
|
||||
[init -> log_terminal] [init -> event_dump] Input event #9 RELEASE BTN_LEFT key count: 0
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user