← Documents Documentation/input/uinput.rst GitHub 원문 ↗

Linux 6.18.37 · Input

uinput module

사용자 공간에서 가상 input device를 만들고 keyboard·mouse event를 보내는 현대 및 구형 uinput interface를 설명합니다.

Source pathDocumentation/input/uinput.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

uinput.rst:1-245

uinput은 사용자 공간 process가 capability와 identity를 정한 가상 input device를 만들고 event를 kernel input subsystem에 주입하는 interface입니다. 새 code는 `UI_DEV_SETUP` 또는 `libevdev`를 사용해야 하며 v5 이전의 `uinput_user_dev` 기록 방식은 호환 목적으로만 필요합니다.

uinput 핵심 경로
영역핵심
Keyboard`EV_KEY`, `KEY_SPACE`, `SYN_REPORT`
Mouse`EV_REL`, `REL_X`, `REL_Y`
설정`UI_DEV_SETUP` 후 `UI_DEV_CREATE`
정리`UI_DEV_DESTROY` 후 `close()`
구형 호환`UI_GET_VERSION`, `uinput_user_dev`

문서의 세 예제와 권장 interface를 요약합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 =============
2 uinput module
3 =============
4
5 Introduction
6 ============
7
8 uinput is a kernel module that makes it possible to emulate input devices
9 from userspace. By writing to /dev/uinput (or /dev/input/uinput) device, a
10 process can create a virtual input device with specific capabilities. Once
11 this virtual device is created, the process can send events through it,
12 that will be delivered to userspace and in-kernel consumers.
13
14 Interface
15 =========
16
17 ::
18
19 linux/uinput.h
20
21 The uinput header defines ioctls to create, set up, and destroy virtual
22 devices.
23
24 libevdev
25 ========
26
27 libevdev is a wrapper library for evdev devices that provides interfaces to
28 create uinput devices and send events. libevdev is less error-prone than
29 accessing uinput directly, and should be considered for new software.
30
31 For examples and more information about libevdev:
32 https://www.freedesktop.org/software/libevdev/doc/latest/
33
34 Examples
35 ========
36
37 Keyboard events
38 ---------------
39
40 This first example shows how to create a new virtual device, and how to
41 send a key event. All default imports and error handlers were removed for
42 the sake of simplicity.
43
44 .. code-block:: c
45
46 #include <linux/uinput.h>
47
48 void emit(int fd, int type, int code, int val)
49 {
50 struct input_event ie;
51
52 ie.type = type;
53 ie.code = code;
54 ie.value = val;
55 /* timestamp values below are ignored */
56 ie.time.tv_sec = 0;
57 ie.time.tv_usec = 0;
58
59 write(fd, &ie, sizeof(ie));
60 }
61
62 int main(void)
63 {
64 struct uinput_setup usetup;
65
66 int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
67
68
69 /*
70 * The ioctls below will enable the device that is about to be
71 * created, to pass key events, in this case the space key.
72 */
73 ioctl(fd, UI_SET_EVBIT, EV_KEY);
74 ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);
75
76 memset(&usetup, 0, sizeof(usetup));
77 usetup.id.bustype = BUS_USB;
78 usetup.id.vendor = 0x1234; /* sample vendor */
79 usetup.id.product = 0x5678; /* sample product */
80 strcpy(usetup.name, "Example device");
81
82 ioctl(fd, UI_DEV_SETUP, &usetup);
83 ioctl(fd, UI_DEV_CREATE);
84
85 /*
86 * On UI_DEV_CREATE the kernel will create the device node for this
87 * device. We are inserting a pause here so that userspace has time
88 * to detect, initialize the new device, and can start listening to
89 * the event, otherwise it will not notice the event we are about
90 * to send. This pause is only needed in our example code!
91 */
92 sleep(1);
93
94 /* Key press, report the event, send key release, and report again */
95 emit(fd, EV_KEY, KEY_SPACE, 1);
96 emit(fd, EV_SYN, SYN_REPORT, 0);
97 emit(fd, EV_KEY, KEY_SPACE, 0);
98 emit(fd, EV_SYN, SYN_REPORT, 0);
99
100 /*
101 * Give userspace some time to read the events before we destroy the
102 * device with UI_DEV_DESTROY.
103 */
104 sleep(1);
105
106 ioctl(fd, UI_DEV_DESTROY);
107 close(fd);
108
109 return 0;
110 }
111
112 Mouse movements
113 ---------------
114
115 This example shows how to create a virtual device that behaves like a physical
116 mouse.
117
118 .. code-block:: c
119
120 #include <linux/uinput.h>
121
122 /* emit function is identical to of the first example */
123
124 int main(void)
125 {
126 struct uinput_setup usetup;
127 int i = 50;
128
129 int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
130
131 /* enable mouse button left and relative events */
132 ioctl(fd, UI_SET_EVBIT, EV_KEY);
133 ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
134
135 ioctl(fd, UI_SET_EVBIT, EV_REL);
136 ioctl(fd, UI_SET_RELBIT, REL_X);
137 ioctl(fd, UI_SET_RELBIT, REL_Y);
138
139 memset(&usetup, 0, sizeof(usetup));
140 usetup.id.bustype = BUS_USB;
141 usetup.id.vendor = 0x1234; /* sample vendor */
142 usetup.id.product = 0x5678; /* sample product */
143 strcpy(usetup.name, "Example device");
144
145 ioctl(fd, UI_DEV_SETUP, &usetup);
146 ioctl(fd, UI_DEV_CREATE);
147
148 /*
149 * On UI_DEV_CREATE the kernel will create the device node for this
150 * device. We are inserting a pause here so that userspace has time
151 * to detect, initialize the new device, and can start listening to
152 * the event, otherwise it will not notice the event we are about
153 * to send. This pause is only needed in our example code!
154 */
155 sleep(1);
156
157 /* Move the mouse diagonally, 5 units per axis */
158 while (i--) {
159 emit(fd, EV_REL, REL_X, 5);
160 emit(fd, EV_REL, REL_Y, 5);
161 emit(fd, EV_SYN, SYN_REPORT, 0);
162 usleep(15000);
163 }
164
165 /*
166 * Give userspace some time to read the events before we destroy the
167 * device with UI_DEV_DESTROY.
168 */
169 sleep(1);
170
171 ioctl(fd, UI_DEV_DESTROY);
172 close(fd);
173
174 return 0;
175 }
176
177
178 uinput old interface
179 --------------------
180
181 Before uinput version 5, there wasn't a dedicated ioctl to set up a virtual
182 device. Programs supporting older versions of uinput interface need to fill
183 a uinput_user_dev structure and write it to the uinput file descriptor to
184 configure the new uinput device. New code should not use the old interface
185 but interact with uinput via ioctl calls, or use libevdev.
186
187 .. code-block:: c
188
189 #include <linux/uinput.h>
190
191 /* emit function is identical to of the first example */
192
193 int main(void)
194 {
195 struct uinput_user_dev uud;
196 int version, rc, fd;
197
198 fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
199 rc = ioctl(fd, UI_GET_VERSION, &version);
200
201 if (rc == 0 && version >= 5) {
202 /* use UI_DEV_SETUP */
203 return 0;
204 }
205
206 /*
207 * The ioctls below will enable the device that is about to be
208 * created, to pass key events, in this case the space key.
209 */
210 ioctl(fd, UI_SET_EVBIT, EV_KEY);
211 ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);
212
213 memset(&uud, 0, sizeof(uud));
214 snprintf(uud.name, UINPUT_MAX_NAME_SIZE, "uinput old interface");
215 write(fd, &uud, sizeof(uud));
216
217 ioctl(fd, UI_DEV_CREATE);
218
219 /*
220 * On UI_DEV_CREATE the kernel will create the device node for this
221 * device. We are inserting a pause here so that userspace has time
222 * to detect, initialize the new device, and can start listening to
223 * the event, otherwise it will not notice the event we are about
224 * to send. This pause is only needed in our example code!
225 */
226 sleep(1);
227
228 /* Key press, report the event, send key release, and report again */
229 emit(fd, EV_KEY, KEY_SPACE, 1);
230 emit(fd, EV_SYN, SYN_REPORT, 0);
231 emit(fd, EV_KEY, KEY_SPACE, 0);
232 emit(fd, EV_SYN, SYN_REPORT, 0);
233
234 /*
235 * Give userspace some time to read the events before we destroy the
236 * device with UI_DEV_DESTROY.
237 */
238 sleep(1);
239
240 ioctl(fd, UI_DEV_DESTROY);
241
242 close(fd);
243 return 0;
244 }
245
246

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

소개, 인터페이스와 libevdev

1-33

`uinput`은 사용자 공간에서 입력 장치를 흉내 낼 수 있게 하는 커널 모듈입니다. 프로세스가 `/dev/uinput` 또는 `/dev/input/uinput`에 기록하면 원하는 capability를 가진 가상 입력 장치를 만들 수 있습니다. 장치가 만들어진 뒤 프로세스가 보내는 event는 사용자 공간 소비자와 커널 내부 소비자 모두에게 전달됩니다.

인터페이스 선언은 `linux/uinput.h`에 있습니다. 이 header는 가상 장치를 만들고 설정하고 제거하는 ioctl을 정의합니다.

`libevdev`는 evdev 장치를 감싸는 library이며 uinput 장치 생성과 event 전송 인터페이스를 제공합니다. uinput을 직접 다루는 것보다 오류 가능성이 낮으므로 새 software에서는 `libevdev` 사용을 고려해야 합니다. 예제와 최신 정보는 `https://www.freedesktop.org/software/libevdev/doc/latest/`에서 확인할 수 있습니다.

uinput 구성 요소
구성 요소역할
`/dev/uinput`사용자 공간 process가 가상 장치를 구성하고 event를 기록하는 character device
`/dev/input/uinput`같은 uinput 장치의 대체 경로
`linux/uinput.h`생성·설정·제거 ioctl과 자료 구조 정의
`libevdev`장치 생성과 event 전송을 더 안전하게 감싼 library

가상 입력 장치가 사용자 공간과 input subsystem 사이에서 맡는 역할입니다.

가상 입력 장치 생명주기
uinput device 열기지원할 event capability 설정장치 identity와 이름 설정가상 장치 생성input event 전송가상 장치 제거와 descriptor 닫기

capability를 정한 뒤 장치를 공개하고 event를 전송합니다.

=============
uinput module
=============

Introduction
============

uinput is a kernel module that makes it possible to emulate input devices
from userspace. By writing to /dev/uinput (or /dev/input/uinput) device, a
process can create a virtual input device with specific capabilities. Once
this virtual device is created, the process can send events through it,
that will be delivered to userspace and in-kernel consumers.

Interface
=========

::

  linux/uinput.h

The uinput header defines ioctls to create, set up, and destroy virtual
devices.

libevdev
========

libevdev is a wrapper library for evdev devices that provides interfaces to
create uinput devices and send events. libevdev is less error-prone than
accessing uinput directly, and should be considered for new software.

For examples and more information about libevdev:
https://www.freedesktop.org/software/libevdev/doc/latest/

가상 keyboard와 key event 예제

34-111

첫 번째 예제는 새 가상 장치를 만들고 key event를 보내는 방법을 보여 줍니다. 흐름을 분명히 하기 위해 기본 include와 error handler는 생략되었습니다. 실제 program에서는 모든 system call과 ioctl의 반환값을 검사해야 합니다.

`emit()`은 `struct input_event`의 `type`, `code`, `value`를 채운 뒤 descriptor에 구조체 전체를 기록합니다. 아래 timestamp 값은 uinput에서 무시되므로 `tv_sec`과 `tv_usec`를 0으로 둡니다.

`emit()` field
Field예제의 의미
`ie.type``EV_KEY`, `EV_SYN` 같은 event 종류
`ie.code``KEY_SPACE`, `SYN_REPORT` 같은 세부 code
`ie.value`누름 1, 놓음 0 또는 event별 값
`ie.time`uinput에서 무시되므로 두 값을 0으로 설정
`write(fd, &ie, sizeof(ie))`완성된 event 하나를 kernel로 전달

한 input event를 구성하는 핵심 field입니다.

`main()`은 `/dev/uinput`을 `O_WRONLY | O_NONBLOCK`으로 엽니다. `UI_SET_EVBIT`으로 `EV_KEY`를, `UI_SET_KEYBIT`으로 `KEY_SPACE`를 활성화하여 이 장치가 space key event를 전달할 수 있게 합니다.

`struct uinput_setup`을 0으로 초기화한 뒤 bus type은 `BUS_USB`, sample vendor와 product ID는 각각 `0x1234`, `0x5678`, 이름은 `Example device`로 설정합니다. `UI_DEV_SETUP`으로 이 정보를 적용하고 `UI_DEV_CREATE`로 장치를 만듭니다.

`UI_DEV_CREATE`가 반환되면 kernel은 장치 node를 만듭니다. 예제의 `sleep(1)`은 사용자 공간이 새 장치를 발견하고 초기화하여 event를 듣기 시작할 시간을 주기 위한 것입니다. 이 pause는 예제에만 필요하며 일반적인 protocol 요구 사항은 아닙니다.

Space key event sequence
`EV_KEY`, `KEY_SPACE`, 1로 key 누름`EV_SYN`, `SYN_REPORT`, 0으로 누름 frame 완료`EV_KEY`, `KEY_SPACE`, 0으로 key 놓음`EV_SYN`, `SYN_REPORT`, 0으로 놓음 frame 완료

누름과 놓음은 각각 `SYN_REPORT`로 끝나는 별도 frame입니다.

마지막 pause는 사용자 공간이 event를 읽을 시간을 주기 위한 것입니다. 그 뒤 `UI_DEV_DESTROY`로 가상 장치를 없애고 `close(fd)`로 descriptor를 닫습니다.

Keyboard 예제 ioctl 순서
순서호출효과
1`UI_SET_EVBIT, EV_KEY`key event 종류 활성화
2`UI_SET_KEYBIT, KEY_SPACE`space key code 활성화
3`UI_DEV_SETUP`bus·vendor·product·name 적용
4`UI_DEV_CREATE`가상 input device 생성
5`write()`key와 synchronization event 전송
6`UI_DEV_DESTROY`가상 input device 제거

capability 설정에서 장치 제거까지의 호출 목적입니다.

Examples
========

Keyboard events
---------------

This first example shows how to create a new virtual device, and how to
send a key event. All default imports and error handlers were removed for
the sake of simplicity.

.. code-block:: c

   #include <linux/uinput.h>

   void emit(int fd, int type, int code, int val)
   {
      struct input_event ie;

      ie.type = type;
      ie.code = code;
      ie.value = val;
      /* timestamp values below are ignored */
      ie.time.tv_sec = 0;
      ie.time.tv_usec = 0;

      write(fd, &ie, sizeof(ie));
   }

   int main(void)
   {
      struct uinput_setup usetup;

      int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);


      /*
       * The ioctls below will enable the device that is about to be
       * created, to pass key events, in this case the space key.
       */
      ioctl(fd, UI_SET_EVBIT, EV_KEY);
      ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);

      memset(&usetup, 0, sizeof(usetup));
      usetup.id.bustype = BUS_USB;
      usetup.id.vendor = 0x1234; /* sample vendor */
      usetup.id.product = 0x5678; /* sample product */
      strcpy(usetup.name, "Example device");

      ioctl(fd, UI_DEV_SETUP, &usetup);
      ioctl(fd, UI_DEV_CREATE);

      /*
       * On UI_DEV_CREATE the kernel will create the device node for this
       * device. We are inserting a pause here so that userspace has time
       * to detect, initialize the new device, and can start listening to
       * the event, otherwise it will not notice the event we are about
       * to send. This pause is only needed in our example code!
       */
      sleep(1);

      /* Key press, report the event, send key release, and report again */
      emit(fd, EV_KEY, KEY_SPACE, 1);
      emit(fd, EV_SYN, SYN_REPORT, 0);
      emit(fd, EV_KEY, KEY_SPACE, 0);
      emit(fd, EV_SYN, SYN_REPORT, 0);

      /*
       * Give userspace some time to read the events before we destroy the
       * device with UI_DEV_DESTROY.
       */
      sleep(1);

      ioctl(fd, UI_DEV_DESTROY);
      close(fd);

      return 0;
   }

가상 mouse와 상대 이동 예제

112-177

두 번째 예제는 물리 mouse처럼 동작하는 가상 장치를 만듭니다. `emit()` 함수는 첫 번째 예제와 같습니다.

왼쪽 button을 위해 `EV_KEY`와 `BTN_LEFT`를 활성화하고 상대 이동을 위해 `EV_REL`, `REL_X`, `REL_Y`를 활성화합니다. 장치 identity와 이름은 keyboard 예제와 같은 `struct uinput_setup` 절차로 설정한 뒤 `UI_DEV_CREATE`를 호출합니다.

가상 mouse capability
ioctl의미
`UI_SET_EVBIT``EV_KEY`button event 계열 허용
`UI_SET_KEYBIT``BTN_LEFT`왼쪽 mouse button 허용
`UI_SET_EVBIT``EV_REL`상대 이동 event 계열 허용
`UI_SET_RELBIT``REL_X`수평 상대 이동 허용
`UI_SET_RELBIT``REL_Y`수직 상대 이동 허용

button과 두 상대 좌표축을 함께 선언합니다.

장치 생성 뒤의 `sleep(1)`은 앞 예제와 마찬가지로 사용자 공간 listener가 장치를 발견할 시간을 주는 예제용 pause입니다.

반복문은 50회 실행됩니다. 각 회마다 `REL_X`와 `REL_Y`에 5를 보내고 `SYN_REPORT`로 한 frame을 완료하므로 pointer는 대각선으로 이동합니다. frame 사이에는 `usleep(15000)`으로 15 ms를 둡니다.

대각선 mouse 이동 frame
`EV_REL`, `REL_X`, 5`EV_REL`, `REL_Y`, 5`EV_SYN`, `SYN_REPORT`, 015 ms 대기총 50회 반복

각 반복은 X·Y delta를 하나의 동기화 frame으로 묶습니다.

event 소비 시간을 위한 마지막 pause 뒤 `UI_DEV_DESTROY`를 호출하고 descriptor를 닫아 장치를 정리합니다.

Mouse movements
---------------

This example shows how to create a virtual device that behaves like a physical
mouse.

.. code-block:: c

   #include <linux/uinput.h>

   /* emit function is identical to of the first example */

   int main(void)
   {
      struct uinput_setup usetup;
      int i = 50;

      int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);

      /* enable mouse button left and relative events */
      ioctl(fd, UI_SET_EVBIT, EV_KEY);
      ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);

      ioctl(fd, UI_SET_EVBIT, EV_REL);
      ioctl(fd, UI_SET_RELBIT, REL_X);
      ioctl(fd, UI_SET_RELBIT, REL_Y);

      memset(&usetup, 0, sizeof(usetup));
      usetup.id.bustype = BUS_USB;
      usetup.id.vendor = 0x1234; /* sample vendor */
      usetup.id.product = 0x5678; /* sample product */
      strcpy(usetup.name, "Example device");

      ioctl(fd, UI_DEV_SETUP, &usetup);
      ioctl(fd, UI_DEV_CREATE);

      /*
       * On UI_DEV_CREATE the kernel will create the device node for this
       * device. We are inserting a pause here so that userspace has time
       * to detect, initialize the new device, and can start listening to
       * the event, otherwise it will not notice the event we are about
       * to send. This pause is only needed in our example code!
       */
      sleep(1);

      /* Move the mouse diagonally, 5 units per axis */
      while (i--) {
         emit(fd, EV_REL, REL_X, 5);
         emit(fd, EV_REL, REL_Y, 5);
         emit(fd, EV_SYN, SYN_REPORT, 0);
         usleep(15000);
      }

      /*
       * Give userspace some time to read the events before we destroy the
       * device with UI_DEV_DESTROY.
       */
      sleep(1);

      ioctl(fd, UI_DEV_DESTROY);
      close(fd);

      return 0;
   }

uinput v5 이전의 구형 인터페이스

178-245

uinput version 5 이전에는 가상 장치를 설정하는 전용 ioctl이 없었습니다. 구형 interface까지 지원하는 program은 `struct uinput_user_dev`를 채운 뒤 uinput file descriptor에 직접 기록하여 새 장치를 구성해야 합니다. 새 code는 이 구형 interface를 사용하지 말고 ioctl 또는 `libevdev`를 사용해야 합니다.

예제는 `UI_GET_VERSION`으로 version을 읽습니다. 호출이 성공하고 version이 5 이상이면 `UI_DEV_SETUP` 경로를 사용할 수 있으므로 구형 설정을 수행하지 않습니다.

uinput 설정 방식 비교
조건설정 방법권장 여부
uinput version 5 이상`struct uinput_setup` + `UI_DEV_SETUP`현재 권장
uinput version 5 미만`struct uinput_user_dev`를 descriptor에 `write()`호환 목적만
새 software`libevdev` 또는 현대 ioctl권장

version 5를 경계로 장치 설정 방법이 달라집니다.

구형 경로에서도 `UI_SET_EVBIT`과 `UI_SET_KEYBIT`으로 `EV_KEY`와 `KEY_SPACE`를 활성화합니다. `struct uinput_user_dev`를 0으로 초기화하고 `UINPUT_MAX_NAME_SIZE` 한도 안에서 이름을 `uinput old interface`로 쓴 다음 구조체 전체를 descriptor에 기록합니다.

구형 interface 분기
`/dev/uinput` 열기`UI_GET_VERSION` 호출version >= 5이면 `UI_DEV_SETUP` 사용그보다 오래되었으면 capability 설정`uinput_user_dev`를 채워 `write()``UI_DEV_CREATE`로 장치 생성

`UI_GET_VERSION` 결과에 따라 현대 설정과 구조체 기록 방식을 나눕니다.

장치 생성 후에는 현대 예제와 같은 이유로 잠시 기다린 뒤 space key 누름과 놓음을 각각 `SYN_REPORT`로 보고합니다. 사용자 공간이 읽을 시간을 준 다음 `UI_DEV_DESTROY`를 호출하고 descriptor를 닫습니다.

uinput old interface
--------------------

Before uinput version 5, there wasn't a dedicated ioctl to set up a virtual
device. Programs supporting older versions of uinput interface need to fill
a uinput_user_dev structure and write it to the uinput file descriptor to
configure the new uinput device. New code should not use the old interface
but interact with uinput via ioctl calls, or use libevdev.

.. code-block:: c

   #include <linux/uinput.h>

   /* emit function is identical to of the first example */

   int main(void)
   {
      struct uinput_user_dev uud;
      int version, rc, fd;

      fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
      rc = ioctl(fd, UI_GET_VERSION, &version);

      if (rc == 0 && version >= 5) {
         /* use UI_DEV_SETUP */
         return 0;
      }

      /*
       * The ioctls below will enable the device that is about to be
       * created, to pass key events, in this case the space key.
       */
      ioctl(fd, UI_SET_EVBIT, EV_KEY);
      ioctl(fd, UI_SET_KEYBIT, KEY_SPACE);

      memset(&uud, 0, sizeof(uud));
      snprintf(uud.name, UINPUT_MAX_NAME_SIZE, "uinput old interface");
      write(fd, &uud, sizeof(uud));

      ioctl(fd, UI_DEV_CREATE);

      /*
       * On UI_DEV_CREATE the kernel will create the device node for this
       * device. We are inserting a pause here so that userspace has time
       * to detect, initialize the new device, and can start listening to
       * the event, otherwise it will not notice the event we are about
       * to send. This pause is only needed in our example code!
       */
      sleep(1);

      /* Key press, report the event, send key release, and report again */
      emit(fd, EV_KEY, KEY_SPACE, 1);
      emit(fd, EV_SYN, SYN_REPORT, 0);
      emit(fd, EV_KEY, KEY_SPACE, 0);
      emit(fd, EV_SYN, SYN_REPORT, 0);

      /*
       * Give userspace some time to read the events before we destroy the
       * device with UI_DEV_DESTROY.
       */
      sleep(1);

      ioctl(fd, UI_DEV_DESTROY);

      close(fd);
      return 0;
   }