[ANNOUNCE] libinputmapper - Linux input-event mapping library

Benjamin Tissoires benjamin.tissoires at gmail.com
Sun Sep 1 11:13:20 PDT 2013


On Sun, Sep 1, 2013 at 6:36 PM, David Herrmann <dh.herrmann at gmail.com> wrote:
> Hi
>
> On Tue, Aug 27, 2013 at 11:47 PM, Peter Hutterer
> <peter.hutterer at who-t.net> wrote:
>> On Tue, Aug 27, 2013 at 12:36:33PM +0200, David Herrmann wrote:
>>> Hi
>>>
>>> On Thu, Aug 22, 2013 at 8:53 AM, Peter Hutterer
>>> <peter.hutterer at who-t.net> wrote:
>>> > On Thu, Aug 15, 2013 at 07:07:01PM +0200, David Herrmann wrote:
>>> >> Hi
>>> >>
>>> >> Following previous discussions, I pushed some initial work for the
>>> >> libinputmapper library to github. You can find the repository at:
>>> >>   https://github.com/dvdhrm/libinputmapper
>>> >>
>>> >> At the library's core, there is one important function:
>>> >>   void inmap_mapping_map(struct inmap_mapping *mapping,
>>> >>                                      const struct input_event *in,
>>> >>                                      struct input_event *out,
>>> >>                                      enum inmap_mapping_map_flags flags);
>>> >> As one might guess, this function takes a linux "struct input_event",
>>> >> performs some conversions/translations/.. and outputs it again. The
>>> >> supported operations are currently limited to simple "ev->code" to
>>> >> "ev->code" conversions. So for instance KEY_UNKNOWN can be remapped to
>>> >> KEY_BACKSPACE. But this is not limited to keys, you can also remap
>>> >> ABS_X to ABS_Y.
>>> >
>>> > I strongly recommend to do this as a N:M mapping, to allow for a set of
>>> > events in and a set of events out. this would allow more complex conversion
>>> > of events than just a simple 1:1 mapping. The real use-case I can see here
>>> > is hiding mtdev behind libinputmapper, a theoretical use-case is a known
>>> > broken device that requires adding e.g. BTN_TOOL_FINGER before the actual
>>> > converted event.
>>>
>>> How do you think N:M mappings work? A 1:N mapping is possible, but if
>>> I have more than one source value, which value do I copy to the
>>> destination? Note that libinputmapper is really just a trivial mapper
>>> so far. It just maps input_event "code" entries from one to another.
>>>
>>> I am open for suggestions, I can change the mapping function to:
>>>
>>> unsigned int inmap_mapping_map(struct inmap_mapping *mapping,
>>>                                       const struct input_event *in,
>>>                                       size_t in_num,
>>>                                       struct input_event *out,
>>>                                       size_t out_num,
>>>                                       enum inmap_mapping_map_flags flags);
>>>
>>> This allows a caller to collect input_events until the next
>>> SYN_REPORT. These are then passed to inmap_mapping_map() with "in_num"
>>> set to the number of events. It then writes the corresponding events
>>> to @out and returns the number of events written. Obviously, there
>>> must be a way for the caller to calculate a sane @out_num value so we
>>> don't need any dynamic allocation here.
>>> I want the standard event-path to work without any allocations or
>>> error-codes. It should be fail-safe and fast.
>>
>> look at mtdev-plumbing.h. the lower layer of mtdev has an api in the form
>> of:
>>
>>     struct input_event ev;
>>     read(fd, &ev, sizeof(ev));
>>
>>     mtdev_put_event(mtdev, &ev);
>>
>>     /* do we have converted events to process? */
>>     if (!mtdev_empty(mtdev)) {
>>         struct input_event converted;
>>         while (mtdev_get_event(mtdev, &converted))
>>              process(&converted);
>>     }
>>
>> the main gripe I have with this API is that mtdev_put_event should return a
>> status code whether events are pending to save the mtdev_empty() call, and
>> the number of events pending.
>>
>> both could take more than one event at a time, though the current libevdev
>> API would make this rather pointless for mtdev_put_event, and in the end
>> callers still need to process events one-by-one anyway, so I'm not sure
>> that's much of a benefit here.
>>
>> obviously that requires two event buffers inside mtdev, same would be true
>> for libinputmapper.
>
> Yeah, that's what I wanted to avoid. We would have one queue in the
> kernel, one queue in libevdev, one in libinputmapper and one in mtdev.
> On the other hand, the queues would be allocated once and then stay
> available so the malloc() overhead is negligible. A way to calculate
> the maximum output events would still have been nice. I guess a "num"
> parameter for *_get_event() functions at least allows the application
> to gather as much events as possible and avoid the deep function call
> into all the libraries. If it doesn't turn out as a bottle-neck, we
> can just pass 1. Otherwise, we at least have the chance to optimize
> the whole call-chain by providing big-enough buffers.

For the size of the output event buffer, in the kernel, there is an
heuristic which does its job quite well (based on the amount of
different event types, protocol, etc...).
So then, you just need to multiply this number by the total number of
frames (between 2 EV_SYN events) that you want to have.

>
>>> Note that I don't think passing more events than until the next
>>> SYN_REPORT makes sense. I guess we agree here?
>>
>> yes, I agree.
>>
>>> Furthermore, I can imagine 1:N mappings which just generates N events
>>> out of 1. Though, I currently lack any proper use-case for that.
>>
>> there are a few devices that provide us with ABS_MT_POSITION_X/Y, but not
>> ABS_X/Y. the xorg evdev driver can't handle these atm and technically
>> they're against the spec. however, that's a use-case where 1:N would be
>> possible, and completely transparent to the user process. these devices
>> could be fixed in the hwdb until the kernel is fixed properly and even that
>> transition would be transparent.
>
> Sounds reasonable. I will try to hook up some patches to call mtdev
> from within inputmapper. What I am still looking for is a function
> that tells me whether a given device actually _requires_ mtdev. weston
> uses "TEST_BIT(..., ABS_MT_SLOT)", I guess that's fine, isn't it? Or I
> just call mtdev unconditionally for every device I see.
>

Please do not call mtdev unconditionally. mtdev transforms protocol A
into protocol B devices only. The difference between the 2 protocol is
the presence of ABS_MT_SLOT, so the weston approach is now good.

Cheers,
Benjamin

PS: I'll be offline until next Friday :)


More information about the Input-tools mailing list