From a28473cb62de5b207a87492cdbf7c61ec3ed9bc5 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 24 Jul 2013 13:37:53 +1000 Subject: [PATCH] Add libevdev_has_event_pending() Returns non-zero if there are events avialable to be read. Signed-off-by: Peter Hutterer Reviewed-by: Benjamin Tissoires Reviewed-by: Benjamin Tissoires --- libevdev/libevdev.c | 16 ++++++++++++++++ libevdev/libevdev.h | 24 ++++++++++++++++++++++++ test/test-libevdev-events.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c index c5bae3f..bb92529 100644 --- a/libevdev/libevdev.c +++ b/libevdev/libevdev.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -626,6 +627,21 @@ out: return rc; } +int libevdev_has_event_pending(struct libevdev *dev) +{ + struct pollfd fds = { dev->fd, POLLIN, 0 }; + int rc; + + if (dev->fd < 0) + return -EBADF; + + if (queue_num_elements(dev) != 0) + return 1; + + rc = poll(&fds, 1, 0); + return (rc >= 0) ? rc : -errno; +} + const char * libevdev_get_name(const struct libevdev *dev) { diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h index 606501b..d637c29 100644 --- a/libevdev/libevdev.h +++ b/libevdev/libevdev.h @@ -483,6 +483,30 @@ int libevdev_get_fd(const struct libevdev* dev); int libevdev_next_event(struct libevdev *dev, unsigned int flags, struct input_event *ev); /** + * @ingroup events + * + * Check if there are events waiting for us. This does not read an event off + * the fd and may not access the fd at all. If there are events queued + * internally this function will return non-zero. If the internal queue is empty, + * this function will poll the file descriptor for data. + * + * This is a convenience function for simple processes, most complex programs + * are expected to use select(2) or poll(2) on the file descriptor. The kernel + * guarantees that if data is available, it is a multiple of sizeof(struct + * input_event), and thus calling libevdev_next_event() when select(2) or + * poll(2) return is safe. You do not need libevdev_has_event_pending() if + * you're using select(2) or poll(2). + * + * @param dev The evdev device, already initialized with libevdev_set_fd() + * @return On failure, a negative errno is returned. + * @retval 0 No event is currently available + * @retval 1 One or more events are available on the fd + * + * @note This function is signal-safe. + */ +int libevdev_has_event_pending(struct libevdev *dev); + +/** * @ingroup bits * * @param dev The evdev device, already initialized with libevdev_set_fd() diff --git a/test/test-libevdev-events.c b/test/test-libevdev-events.c index 65eb1fa..40f94dd 100644 --- a/test/test-libevdev-events.c +++ b/test/test-libevdev-events.c @@ -199,6 +199,45 @@ START_TEST(test_event_code_filtered) } END_TEST +START_TEST(test_has_event_pending) +{ + struct uinput_device* uidev; + struct libevdev *dev; + int rc; + struct input_event ev; + + rc = test_create_device(&uidev, &dev, + EV_REL, REL_X, + EV_REL, REL_Y, + EV_KEY, BTN_LEFT, + -1); + ck_assert_msg(rc == 0, "Failed to create device: %s", strerror(-rc)); + + ck_assert_int_eq(libevdev_has_event_pending(dev), 0); + + uinput_device_event(uidev, EV_REL, REL_X, 1); + uinput_device_event(uidev, EV_REL, REL_Y, 1); + uinput_device_event(uidev, EV_SYN, SYN_REPORT, 0); + + ck_assert_int_eq(libevdev_has_event_pending(dev), 1); + + libevdev_next_event(dev, LIBEVDEV_READ_NORMAL, &ev); + + ck_assert_int_eq(libevdev_has_event_pending(dev), 1); + + while ((rc = libevdev_next_event(dev, LIBEVDEV_READ_NORMAL, &ev)) != -EAGAIN) + ; + + ck_assert_int_eq(libevdev_has_event_pending(dev), 0); + + libevdev_change_fd(dev, -1); + ck_assert_int_eq(libevdev_has_event_pending(dev), -EBADF); + + libevdev_free(dev); + uinput_device_free(uidev); + +} +END_TEST START_TEST(test_syn_delta_button) { struct uinput_device* uidev; @@ -777,6 +816,7 @@ libevdev_events(void) tcase_add_test(tc, test_syn_event); tcase_add_test(tc, test_event_type_filtered); tcase_add_test(tc, test_event_code_filtered); + tcase_add_test(tc, test_has_event_pending); suite_add_tcase(s, tc); tc = tcase_create("SYN_DROPPED deltas"); -- 2.7.4