Merge lp:~peter-hutterer/evemu/evemu-event-v2 into lp:evemu

Proposed by Peter Hutterer
Status: Rejected
Rejected by: Chase Douglas
Proposed branch: lp:~peter-hutterer/evemu/evemu-event-v2
Merge into: lp:evemu
Diff against target: 300 lines (+192/-3)
7 files modified
.bzrignore (+2/-0)
include/evemu.h (+17/-0)
src/evemu.c (+17/-0)
src/libutouch-evemu.ver (+2/-0)
tools/Makefile.am (+2/-1)
tools/evemu-device.txt (+7/-2)
tools/evemu-event.c (+145/-0)
To merge this branch: bzr merge lp:~peter-hutterer/evemu/evemu-event-v2
Reviewer Review Type Date Requested Status
Chase Douglas (community) Needs Fixing
Review via email: mp+108866@code.launchpad.net

Description of the change

Updated branch for evemu-event. Changes to v1:
- evemu_play_one_event fixed, used wrong return code before
- use getopt parsing (changes the user interface, but this is a new tool anyways)
- check for strtol failures
- check input ranges
- check EV_SYN event sending, use EV_SYN/SYN_REPORT as type/code instead of 0/0

To post a comment you must log in.
Revision history for this message
Chase Douglas (chasedouglas) wrote :

* This comment doesn't make sense:

if (c == -1) /* we only do long options */

I would rather be able to support both short and long options, and the code does seem to support both if I am reading the getopt_long manpage correctly. I suggest we just remove the comment.

* The getopt switch needs a default: clause to catch bad options. Right now it looks like it would just skip over bad options. I suggest adding:

default:
    usage();
    goto out;

* I had never heard of program_invocation_short_name before. I learned something new today! It looks like we should be defining _GNU_SOURCE above the include of error.h.

* If the device is specified as an option, and then one non-option string is provided at the end, the non-option string will overwrite the device path. We need to add a check for if the device path has already been specified before assuming the last argument is the path.

* The usage string and man pages need to be updated so they note that you either provide the device path as an option or you provide the path as the last argument. I don't think the code will work otherwise.

review: Needs Fixing
Revision history for this message
Peter Hutterer (peter-hutterer) wrote :

> * This comment doesn't make sense:
>
> if (c == -1) /* we only do long options */
>
> I would rather be able to support both short and long options, and the code
> does seem to support both if I am reading the getopt_long manpage correctly. I
> suggest we just remove the comment.

The comment is a leftover from a earlier revision that had a more complex condition. It's not needed but it's still valid, we only do long options. the third arg to getopt_long specifies the short options and that's an empty string here. Intentionally, I want to leave short options for common ones if we ever need them. e.g. --value should not be -v, that is reserved for a future "verbose".

 > * The getopt switch needs a default: clause to catch bad options. Right now it
> looks like it would just skip over bad options. I suggest adding:
>
> default:
> usage();
> goto out;

Added, thanks.

> * I had never heard of program_invocation_short_name before. I learned
> something new today! It looks like we should be defining _GNU_SOURCE above the
> include of error.h.

it's hardcoded in configure.ac already (fwiw, _GNU_SOURCE is needed for getopt_long too)

> * If the device is specified as an option, and then one non-option string is
> provided at the end, the non-option string will overwrite the device path. We
> need to add a check for if the device path has already been specified before
> assuming the last argument is the path.

good catch, fixed. together with not actually checking if a path has been specified.

> * The usage string and man pages need to be updated so they note that you
> either provide the device path as an option or you provide the path as the
> last argument. I don't think the code will work otherwise.

getopt_long takes care of that, it doesn't matter where non-option arguments are given. I was testing with evemu-event /dev/input/event0 --value ... the whole time.

Unmerged revisions

60. By Peter Hutterer

Use getopt for option parsing

This is a change in the user interface, the arguments must now be specified
instead of just listed in the correct order.

59. By Peter Hutterer

Range-check argument values for evemu-event

type must be less than EV_MAX
code's maximum is effectively KEY_MAX but let's use USHRT_MAX to be safe for
future key additions
value is int value range

58. By Peter Hutterer

Don't open the device until we've parsed all arguments successfully

57. By Peter Hutterer

Check arguments' strtol conversion for errors

56. By Peter Hutterer

Always close the fd, even on errors.

55. By Peter Hutterer

Print errors if SYN event creation/playback failed

54. By Peter Hutterer

Use EV_SYN and SYN_REPORT instead of 0/0

53. By Peter Hutterer

Add evemu-event to play a single event from the commandline

Some testing scenarios require specific events to be generated that are hard
to create from a physical device (e.g. touchpad motion purely on the
positive X axis with no Y axis). For those scenarios, recording a device and
hacking the evemu event files is time consuming.

evemu-event simply allows this scenario to be scripted.

52. By Thomas Voß

Fixed failing tests for device creation.

51. By Stephen M. Webb

release 1.0.9

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2011-11-24 03:24:15 +0000
3+++ .bzrignore 2012-06-06 03:28:21 +0000
4@@ -19,6 +19,8 @@
5 tools/evemu-device
6 tools/evemu-device.1
7 tools/evemu-echo
8+tools/evemu-event
9+tools/evemu-event.1
10 tools/evemu-play
11 tools/evemu-play.1
12 tools/evemu-record
13
14=== modified file 'include/evemu.h'
15--- include/evemu.h 2012-06-05 16:09:52 +0000
16+++ include/evemu.h 2012-06-06 03:28:21 +0000
17@@ -328,6 +328,15 @@
18 int evemu_write_event(FILE *fp, const struct input_event *ev);
19
20 /**
21+ * evemu_create_event() - Create a single event
22+ * @ev: pointer to the kernel event to be filled
23+ * @type: the event type to set
24+ * @code: the event code to set
25+ * @value: the event value to set
26+ */
27+int evemu_create_event(struct input_event *ev, int type, int code, int value);
28+
29+/**
30 * evemu_read_event() - read kernel event from file
31 * @fp: file pointer to read the event from
32 * @ev: pointer to the kernel event to be filled
33@@ -370,6 +379,14 @@
34 */
35 int evemu_record(FILE *fp, int fd, int ms);
36
37+
38+/**
39+ * evemu_play_one() - play one event to kernel device
40+ * @fd: file descriptor of kernel device to write to
41+ * @ev: pointer to the kernel event to be played
42+ */
43+int evemu_play_one(int fd, const struct input_event *ev);
44+
45 /**
46 * evemu_play() - replay events from file to kernel device in realtime
47 * @fp: file pointer to read the events from
48
49=== modified file 'src/evemu.c'
50--- src/evemu.c 2012-06-05 16:13:31 +0000
51+++ src/evemu.c 2012-06-06 03:28:21 +0000
52@@ -425,6 +425,16 @@
53 return ret;
54 }
55
56+int evemu_create_event(struct input_event *ev, int type, int code, int value)
57+{
58+ ev->time.tv_sec = 0;
59+ ev->time.tv_usec = 0;
60+ ev->type = type;
61+ ev->code = code;
62+ ev->value = value;
63+ return 0;
64+}
65+
66 int evemu_read_event_realtime(FILE *fp, struct input_event *ev,
67 struct timeval *evtime)
68 {
69@@ -449,6 +459,13 @@
70 return ret;
71 }
72
73+int evemu_play_one(int fd, const struct input_event *ev)
74+{
75+ int ret;
76+ SYSCALL(ret = write(fd, ev, sizeof(*ev)));
77+ return (ret < sizeof(*ev));
78+}
79+
80 int evemu_play(FILE *fp, int fd)
81 {
82 struct input_event ev;
83
84=== modified file 'src/libutouch-evemu.ver'
85--- src/libutouch-evemu.ver 2012-06-05 16:09:52 +0000
86+++ src/libutouch-evemu.ver 2012-06-06 03:28:21 +0000
87@@ -1,6 +1,7 @@
88 UTOUCH_EVEMU_1.0 {
89 global:
90 evemu_create;
91+ evemu_create_event;
92 evemu_delete;
93 evemu_destroy;
94 evemu_extract;
95@@ -19,6 +20,7 @@
96 evemu_has_prop;
97 evemu_new;
98 evemu_play;
99+ evemu_play_one;
100 evemu_read;
101 evemu_read_event;
102 evemu_read_event_realtime;
103
104=== modified file 'tools/Makefile.am'
105--- tools/Makefile.am 2011-01-05 10:19:44 +0000
106+++ tools/Makefile.am 2012-06-06 03:28:21 +0000
107@@ -5,7 +5,8 @@
108 evemu-describe \
109 evemu-device \
110 evemu-record \
111- evemu-play
112+ evemu-play \
113+ evemu-event
114
115 INCLUDES=-I$(top_srcdir)/include/
116
117
118=== modified file 'tools/evemu-device.txt'
119--- tools/evemu-device.txt 2011-01-05 10:19:44 +0000
120+++ tools/evemu-device.txt 2012-06-06 03:28:21 +0000
121@@ -4,8 +4,8 @@
122 NAME
123 ----
124
125- evemu-device, evemu-play - create a virtual input device and replay an
126- event sequence
127+ evemu-device, evemu-play, evemu-event - create a virtual input device
128+ and replay an event sequence
129
130 SYNOPSIS
131 --------
132@@ -13,6 +13,8 @@
133
134 evemu-play /dev/input/eventX < event-sequence
135
136+ evemu-event /dev/input/eventX [--sync] --type <type> --code <code> --value <value>
137+
138 DESCRIPTION
139 -----------
140 evemu-device creates a virtual input device based on the description-file.
141@@ -24,6 +26,9 @@
142 evemu-play replays the event sequence given on stdin through the input
143 device. The event sequence must be in the form created by evemu-record(1).
144
145+evemu-event plays exactly one event with the current time. If *--sync* is
146+given, evemu-event generates an *EV_SYN* event after the event.
147+
148 evemu-device must be able to write to the uinput device node, and evemu-play
149 must be able to write to the device node specified; in most cases this means
150 it must be run as root.
151
152=== added file 'tools/evemu-event.c'
153--- tools/evemu-event.c 1970-01-01 00:00:00 +0000
154+++ tools/evemu-event.c 2012-06-06 03:28:21 +0000
155@@ -0,0 +1,145 @@
156+/*****************************************************************************
157+ *
158+ * evemu - Kernel device emulation
159+ *
160+ * Copyright (C) 2011 Red Hat, Inc.
161+ *
162+ * This program is free software: you can redistribute it and/or modify it
163+ * under the terms of the GNU General Public License as published by the
164+ * Free Software Foundation, either version 3 of the License, or (at your
165+ * option) any later version.
166+ *
167+ * This program is distributed in the hope that it will be useful, but
168+ * WITHOUT ANY WARRANTY; without even the implied warranty of
169+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
170+ * General Public License for more details.
171+ *
172+ * You should have received a copy of the GNU General Public License along
173+ * with this program. If not, see <http://www.gnu.org/licenses/>.
174+ *
175+ ****************************************************************************/
176+#include "evemu.h"
177+#include <getopt.h>
178+#include <limits.h>
179+#include <stdio.h>
180+#include <fcntl.h>
181+#include <string.h>
182+#include <unistd.h>
183+#include <stdlib.h>
184+#include <linux/input.h>
185+
186+static struct option opts[] = {
187+ { "type", required_argument, 0, 't'},
188+ { "code", required_argument, 0, 'c'},
189+ { "value", required_argument, 0, 'v'},
190+ { "sync", no_argument, 0, 's'},
191+ { "device", required_argument, 0, 'd'}
192+};
193+
194+int parse_arg(const char *arg, long int *value)
195+{
196+ char *endp;
197+
198+ *value = strtol(arg, &endp, 0);
199+ if (*arg == '\0' || *endp != '\0')
200+ return 1;
201+ return 0;
202+}
203+
204+void usage(void)
205+{
206+ fprintf(stderr, "Usage: %s [--sync] <device> --type <type> --code <code> --value <value>\n", program_invocation_short_name);
207+}
208+
209+int main(int argc, char *argv[])
210+{
211+ int rc = -1;
212+ int fd = -1;
213+ long int type, code, value;
214+ struct input_event ev;
215+ int sync = 0;
216+ const char *path;
217+
218+ if (argc < 5) {
219+ usage();
220+ goto out;
221+ }
222+
223+ while(1) {
224+ int option_index = 0;
225+ int c;
226+
227+ c = getopt_long(argc, argv, "", opts, &option_index);
228+ if (c == -1) /* we only do long options */
229+ break;
230+
231+ switch(c) {
232+ case 't': /* type */
233+ if (parse_arg(optarg, &type) || type < 0 || type > EV_MAX) {
234+ fprintf(stderr, "error: invalid type argument '%s'\n", optarg);
235+ goto out;
236+ }
237+ break;
238+ case 'c': /* code */
239+ if (parse_arg(optarg, &code) || code < 0 || code > USHRT_MAX) {
240+ fprintf(stderr, "error: invalid code argument '%s'\n", optarg);
241+ goto out;
242+ }
243+ break;
244+ case 'v': /* value */
245+ if (parse_arg(optarg, &value) || value < INT_MIN || value > INT_MAX) {
246+ fprintf(stderr, "error: invalid value argument '%s'\n", optarg);
247+ goto out;
248+ }
249+ break;
250+ case 'd': /* device */
251+ path = optarg;
252+ break;
253+ case 's': /* sync */
254+ sync = 1;
255+ break;
256+ }
257+ }
258+
259+ /* if device wasn't specified as option, take the remaining arg */
260+ if (optind < argc) {
261+ if (argc - optind != 1) {
262+ usage();
263+ goto out;
264+ }
265+ path = argv[optind];
266+ }
267+
268+ fd = open(path, O_WRONLY);
269+ if (fd < 0) {
270+ fprintf(stderr, "error: could not open device\n");
271+ goto out;
272+ }
273+
274+ if (evemu_create_event(&ev, type, code, value)) {
275+ fprintf(stderr, "error: failed to create event\n");
276+ goto out;
277+ }
278+
279+ if (evemu_play_one(fd, &ev)) {
280+ fprintf(stderr, "error: could not play event\n");
281+ goto out;
282+ }
283+
284+ if (sync) {
285+ if (evemu_create_event(&ev, EV_SYN, SYN_REPORT, 0)) {
286+ fprintf(stderr, "error: could not create SYN event\n");
287+ goto out;
288+ }
289+ if (evemu_play_one(fd, &ev)) {
290+ fprintf(stderr, "error: could not play SYN event\n");
291+ goto out;
292+ }
293+ }
294+
295+ rc = 0;
296+out:
297+ if (fd > -1)
298+ close(fd);
299+ return rc;
300+}

Subscribers

People subscribed via source and target branches