1 #include <stdio.h>
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <stdbool.h>
5 #include <string.h>
6 #include <errno.h>
7 
8 #include <poll.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <getopt.h>
12 #include <pthread.h>
13 
14 #include <libudev.h>
15 #include <libinput.h>
16 #include <libevdev/libevdev.h>
17 
18 #include "config.h"
19 
20 #define MAX_BUFFER_LENGTH 512
21 
22 enum error_code { NO_ERROR, UDEV_FAILED, LIBINPUT_FAILED, SEAT_FAILED };
23 
24 struct input_handler_data {
25 	struct udev *udev;
26 	struct libinput *libinput;
27 };
28 
handle_input(void * user_data)29 static void *handle_input(void *user_data)
30 {
31 	struct input_handler_data *input_handler_data = user_data;
32 
33 	char line[MAX_BUFFER_LENGTH];
34 	while (fgets(line, MAX_BUFFER_LENGTH, stdin) != NULL) {
35 		if (strcmp(line, "stop\n") == 0) {
36 			libinput_unref(input_handler_data->libinput);
37 			udev_unref(input_handler_data->udev);
38 			exit(EXIT_SUCCESS);
39 		}
40 	}
41 
42 	return NULL;
43 }
44 
open_restricted(const char * path,int flags,void * user_data)45 static int open_restricted(const char *path, int flags, void *user_data)
46 {
47 	int fd = open(path, flags);
48 	if (fd < 0)
49 		fprintf(stderr, "Failed to open %s because of %s\n", path,
50 			strerror(errno));
51 	return fd < 0 ? -errno : fd;
52 }
53 
close_restricted(int fd,void * user_data)54 static void close_restricted(int fd, void *user_data)
55 {
56 	close(fd);
57 }
58 
59 static const struct libinput_interface interface = {
60 	.open_restricted = open_restricted,
61 	.close_restricted = close_restricted,
62 };
63 
print_key_event(struct libinput_event * event)64 static int print_key_event(struct libinput_event *event)
65 {
66 	struct libinput_device *device = libinput_event_get_device(event);
67 	struct libinput_event_keyboard *keyboard =
68 		libinput_event_get_keyboard_event(event);
69 
70 	enum libinput_event_type event_type = libinput_event_get_type(event);
71 	const char *device_name = libinput_device_get_name(device);
72 	uint32_t time_stamp = libinput_event_keyboard_get_time(keyboard);
73 	uint32_t key_code = libinput_event_keyboard_get_key(keyboard);
74 	const char *key_name = libevdev_event_code_get_name(EV_KEY, key_code);
75 	key_name = key_name ? key_name : "null";
76 	enum libinput_key_state state_code =
77 		libinput_event_keyboard_get_key_state(keyboard);
78 	const char *state_name = state_code == LIBINPUT_KEY_STATE_PRESSED ?
79 					 "PRESSED" :
80 					 "RELEASED";
81 
82 	return printf("{"
83 		      "\"event_name\": \"KEYBOARD_KEY\", "
84 		      "\"event_type\": %d, "
85 		      "\"device_name\": \"%s\", "
86 		      "\"time_stamp\": %d, "
87 		      "\"key_name\": \"%s\", "
88 		      "\"key_code\": %d, "
89 		      "\"state_name\": \"%s\", "
90 		      "\"state_code\": %d"
91 		      "}\n",
92 		      event_type, device_name, time_stamp, key_name, key_code,
93 		      state_name, state_code);
94 }
95 
print_button_event(struct libinput_event * event)96 static int print_button_event(struct libinput_event *event)
97 {
98 	struct libinput_device *device = libinput_event_get_device(event);
99 	struct libinput_event_pointer *pointer =
100 		libinput_event_get_pointer_event(event);
101 
102 	enum libinput_event_type event_type = libinput_event_get_type(event);
103 	const char *device_name = libinput_device_get_name(device);
104 	uint32_t time_stamp = libinput_event_pointer_get_time(pointer);
105 	uint32_t button_code = libinput_event_pointer_get_button(pointer);
106 	const char *button_name =
107 		libevdev_event_code_get_name(EV_KEY, button_code);
108 	enum libinput_button_state state_code =
109 		libinput_event_pointer_get_button_state(pointer);
110 	const char *state_name = state_code == LIBINPUT_BUTTON_STATE_PRESSED ?
111 					 "PRESSED" :
112 					 "RELEASED";
113 	return printf("{"
114 		      "\"event_name\": \"POINTER_BUTTON\", "
115 		      "\"event_type\": %d, "
116 		      "\"device_name\": \"%s\", "
117 		      "\"time_stamp\": %d, "
118 		      "\"key_name\": \"%s\", "
119 		      "\"key_code\": %d, "
120 		      "\"state_name\": \"%s\", "
121 		      "\"state_code\": %d"
122 		      "}\n",
123 		      event_type, device_name, time_stamp, button_name,
124 		      button_code, state_name, state_code);
125 }
126 
handle_events(struct libinput * libinput)127 static int handle_events(struct libinput *libinput)
128 {
129 	int result = -1;
130 	struct libinput_event *event;
131 
132 	libinput_dispatch(libinput);
133 	// Please keep printing a line per json.
134 	while ((event = libinput_get_event(libinput)) != 0) {
135 		switch (libinput_event_get_type(event)) {
136 		// This program only handle key event.
137 		case LIBINPUT_EVENT_KEYBOARD_KEY:
138 			print_key_event(event);
139 			break;
140 		// Sorry, mouse button is also a key.
141 		case LIBINPUT_EVENT_POINTER_BUTTON:
142 			print_button_event(event);
143 			break;
144 		default:
145 			break;
146 		}
147 		// Do a `fflush(stdout)` here, so when we write to pipes,
148 		// the other one can always get a latest result.
149 		// If we don't have `fflush(stdout)` here, pipe will save
150 		// some lines in buffer and pass them together.
151 		fflush(stdout);
152 		libinput_event_destroy(event);
153 		result = 0;
154 	}
155 
156 	return result;
157 }
158 
run_mainloop(struct libinput * libinput)159 static void run_mainloop(struct libinput *libinput)
160 {
161 	struct pollfd fd;
162 	fd.fd = libinput_get_fd(libinput);
163 	fd.events = POLLIN;
164 	fd.revents = 0;
165 
166 	if (handle_events(libinput) != 0)
167 		fprintf(stderr, "Failed to clear event queue on startup.\n");
168 	while (poll(&fd, 1, -1) > -1)
169 		handle_events(libinput);
170 }
171 
print_help(char * program_name)172 void print_help(char *program_name)
173 {
174 	printf("The backend of Show Me The Key.\n");
175 	printf("Version " PROJECT_VERSION ".\n");
176 	printf("Usage: %s [OPTION…]\n", program_name);
177 	printf("Options:\n");
178 	printf("\t-h, --help\tDisplay help then exit.\n");
179 	printf("\t-v, --version\tDisplay version then exit.\n");
180 	printf("Warning: This is the backend and is not designed to run "
181 	       "by users. You should run the frontend of Show Me The Key, "
182 	       "and the frontend will run this.\n");
183 }
184 
main(int argc,char * argv[])185 int main(int argc, char *argv[])
186 {
187 	const struct option long_options[] = { { "version", no_argument, 0,
188 						 'v' },
189 					       { "help", no_argument, 0, 'h' },
190 					       { NULL, 0, NULL, 0 } };
191 
192 	int option_index = 0;
193 	int opt = 0;
194 	while ((opt = getopt_long(argc, argv, "vh", long_options,
195 				  &option_index)) != -1) {
196 		switch (opt) {
197 		case 0:
198 			// We don't use this.
199 			break;
200 		case 'v':
201 			printf(PROJECT_VERSION "\n");
202 			return 0;
203 		case 'h':
204 			print_help(argv[0]);
205 			return 0;
206 		case '?':
207 			// getopt_long already printed an error message.
208 			break;
209 		default:
210 			fprintf(stderr, "%s: Invalid option `-%c`.\n", argv[0],
211 				opt);
212 			break;
213 		}
214 	}
215 
216 	struct udev *udev = udev_new();
217 	if (udev == NULL) {
218 		fprintf(stderr, "Failed to initialize udev.\n");
219 		return UDEV_FAILED;
220 	}
221 
222 	struct libinput *libinput =
223 		libinput_udev_create_context(&interface, NULL, udev);
224 	if (!libinput) {
225 		fprintf(stderr, "Failed to initialize libinput from udev.\n");
226 		return LIBINPUT_FAILED;
227 	}
228 
229 	// TODO: Support custom seat.
230 	if (libinput_udev_assign_seat(libinput, "seat0") != 0) {
231 		fprintf(stderr, "Failed to set seat.\n");
232 		libinput_unref(libinput);
233 		udev_unref(udev);
234 		return SEAT_FAILED;
235 	}
236 
237 	// Typically this will be run with pkexec as a subprocess,
238 	// and the parent cannot kill it because it is privileged,
239 	// so we use another thread to see if it gets "stop\n" from stdin,
240 	// it will exit by itself.
241 	pthread_t input_handler;
242 	struct input_handler_data input_handler_data = { udev, libinput };
243 	pthread_create(&input_handler, NULL, handle_input, &input_handler_data);
244 
245 	run_mainloop(libinput);
246 
247 	libinput_unref(libinput);
248 	udev_unref(udev);
249 
250 	return NO_ERROR;
251 }
252