[PATCH libevdev v2 4/5] Add libevdev_event_type/code_from_name() resolvers

David Herrmann dh.herrmann at gmail.com
Tue Oct 29 11:28:17 CET 2013


Hi

On Tue, Oct 29, 2013 at 11:25 AM, Peter Hutterer
<peter.hutterer at who-t.net> wrote:
> On 29/10/13 16:37 , David Herrmann wrote:
>>
>> Hi Peter
>>
>> On Tue, Oct 29, 2013 at 2:06 AM, Peter Hutterer
>> <peter.hutterer at who-t.net> wrote:
>>>
>>> On Mon, Oct 28, 2013 at 05:16:46PM +0100, David Herrmann wrote:
>>>>
>>>> Three new helpers are added:
>>>> (1) libevdev_event_type_from_name() takes a string describing an EV_*
>>>> event type and returns the given event-type constant.
>>>> (2) libevdev_event_type_from_prefix() takes a string describing an event
>>>> code and returns the type given by the prefix of the event code.
>>>
>>>
>>> what's the use-case for this? Specifically returning a valid type for an
>>> invalid event code is what worries me a bit.
>>
>>
>> use-case is pretty simple. Say you have a config-option to map an ABS
>> value to another ABS value. You would do:
>>    if (libevdev_event_type_from_prefix(name, -1) != EV_ABS)
>>      return -EINVAL;
>>    r = libevdev_event_code_from_name(name, -1);
>>    if (r == -1)
>>      return -EINVAL;
>>    sth->code = r;
>>
>> So you need it to verify your code is really an EV_ABS value. I
>> explicitly called it "from_prefix" to note that it does nothing more
>> than prefix-matching. This is the simplest API I could come up with
>> and I like it now. If you have ideas how to make it better, lemme
>> know.
>> The only other idea I had is adding an "unsigned int type" argument to
>> libevdev_event_code_from_name() to limit it explicitly to a given
>> group of names. I'm fine with both ideas.
>
>
> I think that is my preferred option. I'd like to keep the API narrow and
> well defined, at least in the beginning. If having a type argument becomes
> too restricting and the workarounds too complicated we can add something
> later but for now let's keep it simple.

Ok, will send v3 later.
I will keep the current lookup-tables, ok? That means, we still have a
single merged table. But I will just modify the lookup-function to
verify the prefix is right. Basically making from_prefix() static and
calling it before doing the lookup.

Thanks
David

> Cheers,
>   Peter
>
>
>
>>
>>>> (2) libevdev_event_code_from_name() takes a string describing an event
>>>> code and returns the given event-code constant.
>>>>
>>>> Signed-off-by: David Herrmann <dh.herrmann at gmail.com>
>>>> ---
>>>>   libevdev/Makefile.am      |   3 +-
>>>>   libevdev/libevdev-names.c | 128
>>>> ++++++++++++++++++++++++++++++++++++++++++++++
>>>>   libevdev/libevdev.h       |  63 +++++++++++++++++++++++
>>>>   test/Makefile.am          |   1 +
>>>>   4 files changed, 194 insertions(+), 1 deletion(-)
>>>>   create mode 100644 libevdev/libevdev-names.c
>>>>
>>>> diff --git a/libevdev/Makefile.am b/libevdev/Makefile.am
>>>> index 3833d61..38c8de0 100644
>>>> --- a/libevdev/Makefile.am
>>>> +++ b/libevdev/Makefile.am
>>>> @@ -10,7 +10,8 @@ libevdev_la_SOURCES = \
>>>>                      libevdev-uinput.h \
>>>>                      libevdev-uinput-int.h \
>>>>                      libevdev.c \
>>>> -                ../include/linux/input.h
>>>> +                   ../include/linux/input.h \
>>>> +                   libevdev-names.c
>>>
>>>
>>> this is personal style, but I'd prefer to have the libevdev stuff grouped
>>> together, so that linux/input.h is always the last line (amplifies that
>>> it's
>>> a bit special). also, it'll mean the diff is only one line as opposed to
>>> two.
>>
>>
>> Will fix that once we agreed on the API above.
>>
>>> The rest of the patch looks good, thanks.
>>
>>
>> Thanks!
>> David
>>
>>> Cheers,
>>>     Peter
>>>
>>>
>>>>
>>>>   libevdev_la_LDFLAGS = \
>>>>        -version-info $(LIBEVDEV_LT_VERSION) \
>>>> diff --git a/libevdev/libevdev-names.c b/libevdev/libevdev-names.c
>>>> new file mode 100644
>>>> index 0000000..ee6c7f3
>>>> --- /dev/null
>>>> +++ b/libevdev/libevdev-names.c
>>>> @@ -0,0 +1,128 @@
>>>> +/*
>>>> + * Copyright © 2013 David Herrmann <dh.herrmann at gmail.com>
>>>> + *
>>>> + * Permission to use, copy, modify, distribute, and sell this software
>>>> and its
>>>> + * documentation for any purpose is hereby granted without fee,
>>>> provided that
>>>> + * the above copyright notice appear in all copies and that both that
>>>> copyright
>>>> + * notice and this permission notice appear in supporting
>>>> documentation, and
>>>> + * that the name of the copyright holders not be used in advertising or
>>>> + * publicity pertaining to distribution of the software without
>>>> specific,
>>>> + * written prior permission.  The copyright holders make no
>>>> representations
>>>> + * about the suitability of this software for any purpose.  It is
>>>> provided "as
>>>> + * is" without express or implied warranty.
>>>> + *
>>>> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
>>>> SOFTWARE,
>>>> + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
>>>> NO
>>>> + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL,
>>>> INDIRECT OR
>>>> + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
>>>> OF USE,
>>>> + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
>>>> OTHER
>>>> + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
>>>> PERFORMANCE
>>>> + * OF THIS SOFTWARE.
>>>> + */
>>>> +
>>>> +#include <config.h>
>>>> +#include <errno.h>
>>>> +#include <stdlib.h>
>>>> +#include <string.h>
>>>> +#include <strings.h>
>>>> +
>>>> +#include "libevdev.h"
>>>> +#include "libevdev-int.h"
>>>> +#include "libevdev-util.h"
>>>> +#include "event-names.h"
>>>> +
>>>> +struct name_lookup {
>>>> +     const char *name;
>>>> +     size_t len;
>>>> +};
>>>> +
>>>> +static int cmp_entry(const void *vlookup, const void *ventry)
>>>> +{
>>>> +     const struct name_lookup *lookup = vlookup;
>>>> +     const struct name_entry *entry = ventry;
>>>> +     int r;
>>>> +
>>>> +     r = strncmp(lookup->name, entry->name, lookup->len);
>>>> +     if (!r) {
>>>> +             if (entry->name[lookup->len])
>>>> +                     r = -1;
>>>> +             else
>>>> +                     r = 0;
>>>> +     }
>>>> +
>>>> +     return r;
>>>> +}
>>>> +
>>>> +static const struct name_entry*
>>>> +lookup_name(const struct name_entry *array, size_t asize,
>>>> +         struct name_lookup *lookup)
>>>> +{
>>>> +     const struct name_entry *entry;
>>>> +
>>>> +     entry = bsearch(lookup, array, asize, sizeof(*array), cmp_entry);
>>>> +     if (!entry)
>>>> +             return NULL;
>>>> +
>>>> +     return entry;
>>>> +}
>>>> +
>>>> +LIBEVDEV_EXPORT int
>>>> +libevdev_event_type_from_name(const char *name, ssize_t len)
>>>> +{
>>>> +     struct name_lookup lookup;
>>>> +     const struct name_entry *entry;
>>>> +
>>>> +     lookup.name = name;
>>>> +     lookup.len = (len < 0) ? strlen(name) : (size_t)len;
>>>> +
>>>> +     entry = lookup_name(ev_names, ARRAY_LENGTH(ev_names), &lookup);
>>>> +
>>>> +     return entry ? (int)entry->value : -1;
>>>> +}
>>>> +
>>>> +LIBEVDEV_EXPORT int
>>>> +libevdev_event_type_from_prefix(const char *name, ssize_t len)
>>>> +{
>>>> +     const char *e;
>>>> +     size_t i;
>>>> +     ssize_t l;
>>>> +
>>>> +     if (len < 0)
>>>> +             len = strlen(name);
>>>> +
>>>> +     /* MAX_ is not allowed, even though EV_MAX exists */
>>>> +     if (startswith(name, len, "MAX_", 4))
>>>> +             return -1;
>>>> +     /* BTN_ is special as there is no EV_BTN type */
>>>> +     if (startswith(name, len, "BTN_", 4))
>>>> +             return EV_KEY;
>>>> +     /* FF_STATUS_ is special as FF_ is a prefix of it, so test it
>>>> first */
>>>> +     if (startswith(name, len, "FF_STATUS_", 10))
>>>> +             return EV_FF_STATUS;
>>>> +
>>>> +     for (i = 0; i < ARRAY_LENGTH(ev_names); ++i) {
>>>> +             /* skip EV_ prefix */
>>>> +             e = &ev_names[i].name[3];
>>>> +             l = strlen(e);
>>>> +
>>>> +             /* @e is suffix of [EV_]XYZ, test it and trailing _ */
>>>> +             if (len > l && startswith(name, len, e, l) && name[l] ==
>>>> '_')
>>>> +                     return ev_names[i].value;
>>>> +     }
>>>> +
>>>> +     return -1;
>>>> +}
>>>> +
>>>> +LIBEVDEV_EXPORT int
>>>> +libevdev_event_code_from_name(const char *name, ssize_t len)
>>>> +{
>>>> +     struct name_lookup lookup;
>>>> +     const struct name_entry *entry;
>>>> +
>>>> +     lookup.name = name;
>>>> +     lookup.len = (len < 0) ? strlen(name) : (size_t)len;
>>>> +
>>>> +     entry = lookup_name(code_names, ARRAY_LENGTH(code_names),
>>>> &lookup);
>>>> +
>>>> +     return entry ? (int)entry->value : -1;
>>>> +}
>>>> diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h
>>>> index 426e9c8..b8d85e1 100644
>>>> --- a/libevdev/libevdev.h
>>>> +++ b/libevdev/libevdev.h
>>>> @@ -1416,6 +1416,7 @@ int libevdev_event_is_code(const struct
>>>> input_event *ev, unsigned int type, unsi
>>>>    * defines for new properties libevdev will not automatically pick
>>>> these up.
>>>>    */
>>>>   const char * libevdev_event_type_get_name(unsigned int type);
>>>> +
>>>>   /**
>>>>    * @ingroup misc
>>>>    *
>>>> @@ -1460,6 +1461,68 @@ const char* libevdev_property_get_name(unsigned
>>>> int prop);
>>>>   int libevdev_event_type_get_max(unsigned int type);
>>>>
>>>>   /**
>>>> + * @ingroup misc
>>>> + *
>>>> + * Look up an event-type by its name. Event-types start with "EV_"
>>>> followed by
>>>> + * the name (eg., "EV_ABS"). The "EV_" prefix must be included in the
>>>> name. It
>>>> + * returns the constant assigned to the event-type or -1 if not found.
>>>> + *
>>>> + * @param name A non-NULL string describing an input-event type
>>>> ("EV_KEY",
>>>> + * "EV_ABS", ...).
>>>> + * @param len The length of the passed string excluding any terminating
>>>> 0
>>>> + * character. If less than zero the string is assumed to be
>>>> zero-terminated.
>>>> + *
>>>> + * @return The given type constant for the passed name or -1 if not
>>>> found.
>>>> + *
>>>> + * @note EV_MAX is also recognized.
>>>> + */
>>>> +int libevdev_event_type_from_name(const char *name, ssize_t len);
>>>> +
>>>> +/**
>>>> + * @ingroup misc
>>>> + *
>>>> + * Look up an event-type by an event-code name. Event-codes start with
>>>> a fixed
>>>> + * prefix followed by their name (eg., "ABS_X"). It performs a
>>>> prefix-match on
>>>> + * the name and returns the constant assigned to the event-type of the
>>>> + * event-code or -1 if the prefix is unknown.
>>>> + *
>>>> + * For instance this returns the constant EV_ABS for the string
>>>> "ABS_X". Note
>>>> + * that the event-code must not necessarily exist. A lookup for
>>>> "ABS_XYZ" will
>>>> + * also return EV_ABS, even though ABS_XYZ is not a valid event-code.
>>>> This only
>>>> + * tests the prefix (for performance reasons).
>>>> + *
>>>> + * All EV_* codes are supported by this call and are returned if their
>>>> prefix
>>>> + * is used. For BTN_* codes, EV_KEY is returned.
>>>> + *
>>>> + * @param name A non-NULL string describing an input-event code (KEY_A,
>>>> + * ABS_X, BTN_Y, ...).
>>>> + * @param len The length of the passed string excluding any terminating
>>>> 0
>>>> + * character. If less than zero the string is assumed to be
>>>> zero-terminated.
>>>> + *
>>>> + * @return The given type constant for the passed name or -1 if not
>>>> found.
>>>> + */
>>>> +int libevdev_event_type_from_prefix(const char *name, ssize_t len);
>>>> +
>>>> +/**
>>>> + * @ingroup misc
>>>> + *
>>>> + * Look up an event-code by its name. Event-codes start with a fixed
>>>> prefix
>>>> + * followed by their name (eg., "ABS_X"). The prefix must be included
>>>> in the
>>>> + * name. It returns the constant assigned to the event-code or -1 if
>>>> not found.
>>>> + *
>>>> + * Supported event-codes are codes starting with SYN_, KEY_, BTN_,
>>>> REL_, ABS_,
>>>> + * MSC_, SND_, SW_, LED_, REP_, FF_.
>>>> + *
>>>> + * @param name A non-NULL string describing an input-event code (KEY_A,
>>>> + * ABS_X, BTN_Y, ...).
>>>> + * @param len The length of the passed string excluding any terminating
>>>> 0
>>>> + * character. If less than zero the string is assumed to be
>>>> zero-terminated.
>>>> + *
>>>> + * @return The given code constant for the passed name or -1 if not
>>>> found.
>>>> + */
>>>> +int libevdev_event_code_from_name(const char *name, ssize_t len);
>>>> +
>>>> +/**
>>>>    * @ingroup bits
>>>>    *
>>>>    * Get the repeat delay and repeat period values for this device.
>>>> diff --git a/test/Makefile.am b/test/Makefile.am
>>>> index 2baafb0..c18b277 100644
>>>> --- a/test/Makefile.am
>>>> +++ b/test/Makefile.am
>>>> @@ -5,6 +5,7 @@ TESTS = $(noinst_PROGRAMS)
>>>>
>>>>   libevdev_sources = $(top_srcdir)/libevdev/libevdev.c \
>>>>                   $(top_srcdir)/libevdev/libevdev.h \
>>>> +                $(top_srcdir)/libevdev/libevdev-names.c \
>>>>                   $(top_srcdir)/libevdev/libevdev-uinput.h \
>>>>                   $(top_srcdir)/libevdev/libevdev-uinput.c \
>>>>                   $(top_srcdir)/libevdev/libevdev-uinput-int.h \
>>>> --
>>>> 1.8.4.1
>>>>
>>
>


More information about the Input-tools mailing list