From: Peter Hutterer Date: Tue, 12 Dec 2017 23:20:55 +0000 (+1000) Subject: When changing the fd, reset our grab state to ungrabbed X-Git-Tag: libevdev-1.5.8~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0637d0237a36828f02ad096a08e644a77ad68541;p=platform%2Fupstream%2Flibevdev.git When changing the fd, reset our grab state to ungrabbed Previously, calling grabbing a device after changing the fd was a no-op because libevdev's grab state didn't match the fd: libevdev_grab(LIBEVDEV_GRAB); .. fd is grabbed .. internal state is 'grabbed' libevdev_change_fd(); .. new fd is ungrabbed .. internal state is 'grabbed' libevdev_grab(LIBEVDEV_GRAB); .. argument matches internal state and we exit without grabbing the device Signed-off-by: Peter Hutterer --- diff --git a/libevdev/libevdev.c b/libevdev/libevdev.c index 41bfd25..de0c476 100644 --- a/libevdev/libevdev.c +++ b/libevdev/libevdev.c @@ -311,6 +311,7 @@ libevdev_change_fd(struct libevdev *dev, int fd) return -1; } dev->fd = fd; + dev->grabbed = LIBEVDEV_UNGRAB; return 0; } diff --git a/libevdev/libevdev.h b/libevdev/libevdev.h index 3871bad..b36d3b4 100644 --- a/libevdev/libevdev.h +++ b/libevdev/libevdev.h @@ -966,6 +966,10 @@ enum libevdev_grab_mode { * Grabbing an already grabbed device, or ungrabbing an ungrabbed device is * a noop and always succeeds. * + * A grab is an operation tied to a file descriptor, not a device. If a + * client changes the file descriptor with libevdev_change_fd(), it must + * also re-issue a grab with libevdev_grab(). + * * @param dev The evdev device, already initialized with libevdev_set_fd() * @param grab If true, grab the device. Otherwise ungrab the device. * @@ -1034,6 +1038,9 @@ int libevdev_set_fd(struct libevdev* dev, int fd); * * The fd may be open in O_RDONLY or O_RDWR. * + * After changing the fd, the device is assumed ungrabbed and a caller must + * call libevdev_grab() again. + * * It is an error to call this function before calling libevdev_set_fd(). * * @param dev The evdev device, already initialized with libevdev_set_fd() diff --git a/test/test-libevdev-init.c b/test/test-libevdev-init.c index f673a58..5600441 100644 --- a/test/test-libevdev-init.c +++ b/test/test-libevdev-init.c @@ -468,6 +468,93 @@ START_TEST(test_device_grab_invalid_fd) } END_TEST +START_TEST(test_device_grab_change_fd) +{ + struct libevdev_uinput *uidev; + struct libevdev *dev, *other; + struct input_event e; + int rc; + int other_fd; + int dev_fd; + + dev = libevdev_new(); + libevdev_set_name(dev, "libevdev test device"); + libevdev_enable_event_code(dev, EV_REL, REL_X, NULL); + libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL); + libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL); + + rc = libevdev_uinput_create_from_device(dev, + LIBEVDEV_UINPUT_OPEN_MANAGED, + &uidev); + ck_assert_int_eq(rc, 0); + libevdev_free(dev); + + dev_fd = open(libevdev_uinput_get_devnode(uidev), + O_RDONLY|O_NONBLOCK); + ck_assert_int_ne(dev_fd, -1); + rc = libevdev_new_from_fd(dev_fd, &dev); + ck_assert_int_eq(rc, 0); + + other_fd = open(libevdev_uinput_get_devnode(uidev), + O_RDONLY|O_NONBLOCK); + ck_assert_int_ne(other_fd, -1); + rc = libevdev_new_from_fd(other_fd, &other); + ck_assert_int_eq(rc, 0); + + /* check we're getting the events before the grab */ + libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1); + libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0); + rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e); + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS); + rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e); + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS); + rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e); + ck_assert_int_eq(rc, -EAGAIN); + + /* no events after the grab */ + rc = libevdev_grab(dev, LIBEVDEV_GRAB); + ck_assert_int_eq(rc, 0); + libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1); + libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0); + rc = libevdev_grab(dev, LIBEVDEV_GRAB); + ck_assert_int_eq(rc, 0); + rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e); + ck_assert_int_eq(rc, -EAGAIN); + + /* swapping the fd removes the grab */ + close(dev_fd); + dev_fd = open(libevdev_uinput_get_devnode(uidev), + O_RDONLY|O_NONBLOCK); + ck_assert_int_ne(dev_fd, -1); + rc = libevdev_change_fd(dev, dev_fd); + ck_assert_int_eq(rc, 0); + + /* check we're getting the events again */ + libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1); + libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0); + rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e); + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS); + rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e); + ck_assert_int_eq(rc, LIBEVDEV_READ_STATUS_SUCCESS); + rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e); + ck_assert_int_eq(rc, -EAGAIN); + + /* no events after the grab */ + rc = libevdev_grab(dev, LIBEVDEV_GRAB); + ck_assert_int_eq(rc, 0); + libevdev_uinput_write_event(uidev, EV_REL, REL_X, -1); + libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0); + rc = libevdev_next_event(other, LIBEVDEV_READ_FLAG_NORMAL, &e); + ck_assert_int_eq(rc, -EAGAIN); + + libevdev_uinput_destroy(uidev); + libevdev_free(dev); + libevdev_free(other); + close(dev_fd); + close(other_fd); +} +END_TEST + START_TEST(test_set_clock_id) { struct uinput_device* uidev; @@ -625,6 +712,7 @@ libevdev_init_test(void) tc = tcase_create("device grab"); tcase_add_test(tc, test_device_grab); tcase_add_test(tc, test_device_grab_invalid_fd); + tcase_add_test(tc, test_device_grab_change_fd); suite_add_tcase(s, tc); tc = tcase_create("clock id");