device_input 0.0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6bc11d4d1313889df6c9b9ff7289bfe1dcd8fff6
4
+ data.tar.gz: 1e13f0c7104ad27775e606e4a7a50184a53bef97
5
+ SHA512:
6
+ metadata.gz: 3c4ad7cf1172d6483e53604b4f94dfc1d490a1364994264acfc8691c72c044170f64d8a8fcb2a8d7518d3f41c91f97c87d4b9be24a344f67a4b3867953969f41
7
+ data.tar.gz: e2e275a1bcb94b0cdaeb620fc3d290d88d0f2aca5f4a082ad04d973c0a29c8d98bddd86285e5ff240261dcea60617fbb01387b577aac78acc0edc619756f4e70
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # Background
2
+
3
+ We want to read events from e.g. `/dev/input/event0` in Ruby.
4
+
5
+ ## Kernel docs
6
+
7
+ * https://www.kernel.org/doc/Documentation/input/input.txt
8
+ * https://www.kernel.org/doc/Documentation/input/event-codes.txt
9
+
10
+ These events are defined as C structs with a fixed size in bytes.
11
+
12
+ ## Kernel structs
13
+
14
+ from https://www.kernel.org/doc/Documentation/input/input.txt
15
+
16
+ ```
17
+ struct input_event {
18
+ struct timeval time;
19
+ unsigned short type;
20
+ unsigned short code;
21
+ unsigned int value;
22
+ };
23
+ ```
24
+
25
+ from
26
+ https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input.h#n25
27
+
28
+ ```
29
+ struct input_event {
30
+ struct timeval time;
31
+ __u16 type;
32
+ __u16 code;
33
+ __s32 value;
34
+ };
35
+ ```
36
+
37
+ What's a `timeval`?
38
+ https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/time.h#n15
39
+
40
+ ```
41
+ struct timeval {
42
+ __kernel_time_t tv_sec; /* seconds */
43
+ __kernel_suseconds_t tv_usec; /* microseconds */
44
+ };
45
+ ```
46
+
47
+ What's a `__kernel_time_t`?
48
+ https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/posix_types.h#n88
49
+
50
+ ```
51
+ typedef long __kernel_long_t;
52
+ # ...
53
+ typedef __kernel_long_t __kernel_suseconds_t;
54
+ # ...
55
+ typedef __kernel_long_t __kernel_time_t;
56
+ ```
57
+
58
+ What's a `__u16`? We're pretty sure it's an unsigned 16 bit integer.
59
+ Likewise `__s32` should be a signed 32-bit integer:
60
+
61
+ https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/int-l64.h#n23
62
+
63
+ ```
64
+ typedef unsigned short __u16;
65
+
66
+ typedef __signed__ int __s32;
67
+ ```
68
+
69
+ Why is the value signed? It's meant to be able to communicate an "analog"
70
+ range, say -127 to +127 as determined by the position of a joystick.
71
+
72
+ Let's review:
73
+
74
+ `input_event`
75
+
76
+ * time (timeval)
77
+ - tv_sec (long)
78
+ - tv_usec (long)
79
+ * type (__u16)
80
+ * code (__u16)
81
+ * value (__s32)
82
+
83
+ Flattened: `SEC` `USEC` `TYPE` `CODE` `VALUE`
84
+
85
+ How many bytes is a `long`? Well, it's platform-dependent. On a 32-bit
86
+ platform, you get 32 bits (4 bytes). On a 64-bit platform you get 64 bits
87
+ (8 bytes).
88
+
89
+ This means that the event is 16 bytes on a 32-bit machine and 24 bytes on a
90
+ 64-bit machine. Software will need to accommodate.
91
+
92
+ We can use `RbConfig` and `Array#pack` to help us read these binary structs:
93
+
94
+ ```
95
+ FIELD C RbConfig Pack
96
+ tv_usec long long l!
97
+ tv_usec long long l!
98
+ type __u16 uint16_t S
99
+ code __u16 uint16_t S
100
+ value __s32 int32_t l
101
+ ```
data/bin/devsniff ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'device_input'
4
+
5
+ device = ARGV.shift || '/dev/input/event0'
6
+
7
+ DeviceInput.read_from(device) { |event|
8
+ puts event
9
+ }
@@ -0,0 +1,82 @@
1
+ module DeviceInput
2
+ class Event
3
+ DEFINITION = {
4
+ :tv_sec => 'long',
5
+ :tv_usec => 'long',
6
+ :type => 'uint16_t',
7
+ :code => 'uint16_t',
8
+ :value => 'int32_t',
9
+ }
10
+ PACK_MAP = {
11
+ 'long' => 'l!',
12
+ 'uint16_t' => 'S',
13
+ 'int32_t' => 'l',
14
+ }
15
+ PACK = DEFINITION.values.map { |v| PACK_MAP.fetch(v) }.join
16
+
17
+ Data = Struct.new(*DEFINITION.keys)
18
+
19
+ # convert Event::Data to a string
20
+ def self.encode(data)
21
+ data.values.pack(PACK)
22
+ end
23
+
24
+ # convert string to Event::Data
25
+ def self.decode(binstr)
26
+ Data.new *binstr.unpack(PACK)
27
+ end
28
+
29
+ def self.type_str(type_code)
30
+ TYPES[type_code] || "UNK-#{type_code}"
31
+ end
32
+
33
+ def self.code_str(type_code, code_code)
34
+ require 'device_input/events'
35
+ DeviceInput::EVENTS.dig(type_code, code_code) ||
36
+ "UNK-#{type_code}-#{code_code}"
37
+ end
38
+
39
+ NULL_DATA = Data.new(0, 0, 0, 0, 0)
40
+ NULL_MSG = self.encode(NULL_DATA)
41
+
42
+ attr_reader :data, :time, :type, :code, :length
43
+
44
+ def initialize(data)
45
+ @data = data
46
+ @time = Time.at(data.tv_sec, data.tv_usec)
47
+ @type = self.class.type_str(data.type)
48
+ @code = self.class.code_str(data.type, data.code)
49
+ @value = data.value
50
+ end
51
+
52
+ def to_s
53
+ [@type, @code, @value].join(':')
54
+ end
55
+
56
+ TYPES = {
57
+ 0 => 'Sync',
58
+ 1 => 'Key',
59
+ 2 => 'Relative',
60
+ 3 => 'Absolute',
61
+ 4 => 'Misc',
62
+ 17 => 'LED',
63
+ 18 => 'Sound',
64
+ 20 => 'Repeat',
65
+ 21 => 'ForceFeedback',
66
+ 22 => 'Power',
67
+ 23 => 'ForceFeedbackStatus',
68
+ }
69
+
70
+ BYTE_LENGTH = NULL_MSG.length
71
+ end
72
+
73
+ def self.read_from(filename)
74
+ File.open(filename, 'r') { |f|
75
+ loop {
76
+ bytes = f.read(Event::BYTE_LENGTH)
77
+ msg = Event.decode(bytes)
78
+ yield Event.new(msg)
79
+ }
80
+ }
81
+ end
82
+ end
@@ -0,0 +1,435 @@
1
+ module DeviceInput
2
+ EVENTS = {}
3
+
4
+ # type = Sync
5
+ EVENTS[0] = {
6
+ 0 => 'Sync',
7
+ }
8
+
9
+ # type = Key
10
+ EVENTS[1] = {
11
+ 0 => 'Reserved',
12
+ 1 => 'Esc',
13
+ 2 => '1',
14
+ 3 => '2',
15
+ 4 => '3',
16
+ 5 => '4',
17
+ 6 => '5',
18
+ 7 => '6',
19
+ 8 => '7',
20
+ 9 => '8',
21
+ 10 => '9',
22
+ 11 => '0',
23
+ 12 => 'Minus',
24
+ 13 => 'Equal',
25
+ 14 => 'Backspace',
26
+ 15 => 'Tab',
27
+ 16 => 'Q',
28
+ 17 => 'W',
29
+ 18 => 'E',
30
+ 19 => 'R',
31
+ 20 => 'T',
32
+ 21 => 'Y',
33
+ 22 => 'U',
34
+ 23 => 'I',
35
+ 24 => 'O',
36
+ 25 => 'P',
37
+ 26 => 'LeftBrace',
38
+ 27 => 'RightBrace',
39
+ 28 => 'Enter',
40
+ 29 => 'LeftControl',
41
+ 30 => 'A',
42
+ 31 => 'S',
43
+ 32 => 'D',
44
+ 33 => 'F',
45
+ 34 => 'G',
46
+ 35 => 'H',
47
+ 36 => 'J',
48
+ 37 => 'K',
49
+ 38 => 'L',
50
+ 39 => 'Semicolon',
51
+ 40 => 'Apostrophe',
52
+ 41 => 'Grave',
53
+ 42 => 'LeftShift',
54
+ 43 => 'BackSlash',
55
+ 44 => 'Z',
56
+ 45 => 'X',
57
+ 46 => 'C',
58
+ 47 => 'V',
59
+ 48 => 'B',
60
+ 49 => 'N',
61
+ 50 => 'M',
62
+ 51 => 'Comma',
63
+ 52 => 'Dot',
64
+ 53 => 'Slash',
65
+ 54 => 'RightShift',
66
+ 55 => 'KPAsterisk',
67
+ 56 => 'LeftAlt',
68
+ 57 => 'Space',
69
+ 58 => 'CapsLock',
70
+ 59 => 'F1',
71
+ 60 => 'F2',
72
+ 61 => 'F3',
73
+ 62 => 'F4',
74
+ 63 => 'F5',
75
+ 64 => 'F6',
76
+ 65 => 'F7',
77
+ 66 => 'F8',
78
+ 67 => 'F9',
79
+ 68 => 'F10',
80
+ 69 => 'NumLock',
81
+ 70 => 'ScrollLock',
82
+ 71 => 'KP7',
83
+ 72 => 'KP8',
84
+ 73 => 'KP9',
85
+ 74 => 'KPMinus',
86
+ 75 => 'KP4',
87
+ 76 => 'KP5',
88
+ 77 => 'KP6',
89
+ 78 => 'KPPlus',
90
+ 79 => 'KP1',
91
+ 80 => 'KP2',
92
+ 81 => 'KP3',
93
+ 82 => 'KP0',
94
+ 83 => 'KPDot',
95
+ 85 => 'Zenkaku/Hankaku',
96
+ 86 => '102nd',
97
+ 87 => 'F11',
98
+ 88 => 'F12',
99
+ 89 => 'RO',
100
+ 90 => 'Katakana',
101
+ 91 => 'HIRAGANA',
102
+ 92 => 'Henkan',
103
+ 93 => 'Katakana/Hiragana',
104
+ 94 => 'Muhenkan',
105
+ 95 => 'KPJpComma',
106
+ 96 => 'KPEnter',
107
+ 97 => 'RightCtrl',
108
+ 98 => 'KPSlash',
109
+ 99 => 'SysRq',
110
+ 100 => 'RightAlt',
111
+ 101 => 'LineFeed',
112
+ 102 => 'Home',
113
+ 103 => 'Up',
114
+ 104 => 'PageUp',
115
+ 105 => 'Left',
116
+ 106 => 'Right',
117
+ 107 => 'End',
118
+ 108 => 'Down',
119
+ 109 => 'PageDown',
120
+ 110 => 'Insert',
121
+ 111 => 'Delete',
122
+ 112 => 'Macro',
123
+ 113 => 'Mute',
124
+ 114 => 'VolumeDown',
125
+ 115 => 'VolumeUp',
126
+ 116 => 'Power',
127
+ 117 => 'KPEqual',
128
+ 118 => 'KPPlusMinus',
129
+ 119 => 'Pause',
130
+ 121 => 'KPComma',
131
+ 122 => 'Hanguel',
132
+ 123 => 'Hanja',
133
+ 124 => 'Yen',
134
+ 125 => 'LeftMeta',
135
+ 126 => 'RightMeta',
136
+ 127 => 'Compose',
137
+ 128 => 'Stop',
138
+ 129 => 'Again',
139
+ 130 => 'Props',
140
+ 131 => 'Undo',
141
+ 132 => 'Front',
142
+ 133 => 'Copy',
143
+ 134 => 'Open',
144
+ 135 => 'Paste',
145
+ 136 => 'Find',
146
+ 137 => 'Cut',
147
+ 138 => 'Help',
148
+ 139 => 'Menu',
149
+ 140 => 'Calc',
150
+ 141 => 'Setup',
151
+ 142 => 'Sleep',
152
+ 143 => 'WakeUp',
153
+ 144 => 'File',
154
+ 145 => 'SendFile',
155
+ 146 => 'DeleteFile',
156
+ 147 => 'X-fer',
157
+ 148 => 'Prog1',
158
+ 149 => 'Prog2',
159
+ 150 => 'WWW',
160
+ 151 => 'MSDOS',
161
+ 152 => 'Coffee',
162
+ 153 => 'Direction',
163
+ 154 => 'CycleWindows',
164
+ 155 => 'Mail',
165
+ 156 => 'Bookmarks',
166
+ 157 => 'Computer',
167
+ 158 => 'Back',
168
+ 159 => 'Forward',
169
+ 160 => 'CloseCD',
170
+ 161 => 'EjectCD',
171
+ 162 => 'EjectCloseCD',
172
+ 163 => 'NextSong',
173
+ 164 => 'PlayPause',
174
+ 165 => 'PreviousSong',
175
+ 166 => 'StopCD',
176
+ 167 => 'Record',
177
+ 168 => 'Rewind',
178
+ 169 => 'Phone',
179
+ 170 => 'ISOKey',
180
+ 171 => 'Config',
181
+ 172 => 'HomePage',
182
+ 173 => 'Refresh',
183
+ 174 => 'Exit',
184
+ 175 => 'Move',
185
+ 176 => 'Edit',
186
+ 177 => 'ScrollUp',
187
+ 178 => 'ScrollDown',
188
+ 179 => 'KPLeftParenthesis',
189
+ 180 => 'KPRightParenthesis',
190
+ 183 => 'F13',
191
+ 184 => 'F14',
192
+ 185 => 'F15',
193
+ 186 => 'F16',
194
+ 187 => 'F17',
195
+ 188 => 'F18',
196
+ 189 => 'F19',
197
+ 190 => 'F20',
198
+ 191 => 'F21',
199
+ 192 => 'F22',
200
+ 193 => 'F23',
201
+ 194 => 'F24',
202
+ 200 => 'PlayCD',
203
+ 201 => 'PauseCD',
204
+ 202 => 'Prog3',
205
+ 203 => 'Prog4',
206
+ 205 => 'Suspend',
207
+ 206 => 'Close',
208
+ 207 => 'Play',
209
+ 208 => 'Fast Forward',
210
+ 209 => 'Bass Boost',
211
+ 210 => 'Print',
212
+ 211 => 'HP',
213
+ 212 => 'Camera',
214
+ 213 => 'Sound',
215
+ 214 => 'Question',
216
+ 215 => 'Email',
217
+ 216 => 'Chat',
218
+ 217 => 'Search',
219
+ 218 => 'Connect',
220
+ 219 => 'Finance',
221
+ 220 => 'Sport',
222
+ 221 => 'Shop',
223
+ 222 => 'Alternate Erase',
224
+ 223 => 'Cancel',
225
+ 224 => 'Brightness down',
226
+ 225 => 'Brightness up',
227
+ 226 => 'Media',
228
+ 240 => 'Unknown',
229
+ 256 => 'Btn0',
230
+ 257 => 'Btn1',
231
+ 258 => 'Btn2',
232
+ 259 => 'Btn3',
233
+ 260 => 'Btn4',
234
+ 261 => 'Btn5',
235
+ 262 => 'Btn6',
236
+ 263 => 'Btn7',
237
+ 264 => 'Btn8',
238
+ 265 => 'Btn9',
239
+ 272 => 'LeftBtn',
240
+ 273 => 'RightBtn',
241
+ 274 => 'MiddleBtn',
242
+ 275 => 'SideBtn',
243
+ 276 => 'ExtraBtn',
244
+ 277 => 'ForwardBtn',
245
+ 278 => 'BackBtn',
246
+ 279 => 'TaskBtn',
247
+ 288 => 'Trigger',
248
+ 289 => 'ThumbBtn',
249
+ 290 => 'ThumbBtn2',
250
+ 291 => 'TopBtn',
251
+ 292 => 'TopBtn2',
252
+ 293 => 'PinkieBtn',
253
+ 294 => 'BaseBtn',
254
+ 295 => 'BaseBtn2',
255
+ 296 => 'BaseBtn3',
256
+ 297 => 'BaseBtn4',
257
+ 298 => 'BaseBtn5',
258
+ 299 => 'BaseBtn6',
259
+ 303 => 'BtnDead',
260
+ 304 => 'BtnA',
261
+ 305 => 'BtnB',
262
+ 306 => 'BtnC',
263
+ 307 => 'BtnX',
264
+ 308 => 'BtnY',
265
+ 309 => 'BtnZ',
266
+ 310 => 'BtnTL',
267
+ 311 => 'BtnTR',
268
+ 312 => 'BtnTL2',
269
+ 313 => 'BtnTR2',
270
+ 314 => 'BtnSelect',
271
+ 315 => 'BtnStart',
272
+ 316 => 'BtnMode',
273
+ 317 => 'BtnThumbL',
274
+ 318 => 'BtnThumbR',
275
+ 320 => 'ToolPen',
276
+ 321 => 'ToolRubber',
277
+ 322 => 'ToolBrush',
278
+ 323 => 'ToolPencil',
279
+ 324 => 'ToolAirbrush',
280
+ 325 => 'ToolFinger',
281
+ 326 => 'ToolMouse',
282
+ 327 => 'ToolLens',
283
+ 330 => 'Touch',
284
+ 331 => 'Stylus',
285
+ 332 => 'Stylus2',
286
+ 333 => 'Tool Doubletap',
287
+ 334 => 'Tool Tripletap',
288
+ 336 => 'WheelBtn',
289
+ 337 => 'Gear up',
290
+ 352 => 'Ok',
291
+ 353 => 'Select',
292
+ 354 => 'Goto',
293
+ 355 => 'Clear',
294
+ 356 => 'Power2',
295
+ 357 => 'Option',
296
+ 358 => 'Info',
297
+ 359 => 'Time',
298
+ 360 => 'Vendor',
299
+ 361 => 'Archive',
300
+ 362 => 'Program',
301
+ 363 => 'Channel',
302
+ 364 => 'Favorites',
303
+ 365 => 'EPG',
304
+ 366 => 'PVR',
305
+ 367 => 'MHP',
306
+ 368 => 'Language',
307
+ 369 => 'Title',
308
+ 370 => 'Subtitle',
309
+ 371 => 'Angle',
310
+ 372 => 'Zoom',
311
+ 373 => 'Mode',
312
+ 374 => 'Keyboard',
313
+ 375 => 'Screen',
314
+ 376 => 'PC',
315
+ 377 => 'TV',
316
+ 378 => 'TV2',
317
+ 379 => 'VCR',
318
+ 380 => 'VCR2',
319
+ 381 => 'Sat',
320
+ 382 => 'Sat2',
321
+ 383 => 'CD',
322
+ 384 => 'Tape',
323
+ 385 => 'Radio',
324
+ 386 => 'Tuner',
325
+ 387 => 'Player',
326
+ 388 => 'Text',
327
+ 389 => 'DVD',
328
+ 390 => 'Aux',
329
+ 391 => 'MP3',
330
+ 392 => 'Audio',
331
+ 393 => 'Video',
332
+ 394 => 'Directory',
333
+ 395 => 'List',
334
+ 396 => 'Memo',
335
+ 397 => 'Calendar',
336
+ 398 => 'Red',
337
+ 399 => 'Green',
338
+ 400 => 'Yellow',
339
+ 401 => 'Blue',
340
+ 402 => 'ChannelUp',
341
+ 403 => 'ChannelDown',
342
+ 404 => 'First',
343
+ 405 => 'Last',
344
+ 406 => 'AB',
345
+ 407 => 'Next',
346
+ 408 => 'Restart',
347
+ 409 => 'Slow',
348
+ 410 => 'Shuffle',
349
+ 411 => 'Break',
350
+ 412 => 'Previous',
351
+ 413 => 'Digits',
352
+ 414 => 'TEEN',
353
+ 415 => 'TWEN',
354
+ 448 => 'Delete EOL',
355
+ 449 => 'Delete EOS',
356
+ 450 => 'Insert line',
357
+ 451 => 'Delete line',
358
+ }
359
+
360
+ # type = Relative
361
+ EVENTS[2] = {
362
+ 0 => 'X',
363
+ 1 => 'Y',
364
+ 2 => 'Z',
365
+ 6 => 'HWheel',
366
+ 7 => 'Dial',
367
+ 8 => 'Wheel',
368
+ 9 => 'Misc',
369
+ }
370
+
371
+ # type = Absolute
372
+ EVENTS[3] = {
373
+ 0 => 'X',
374
+ 1 => 'Y',
375
+ 2 => 'Z',
376
+ 3 => 'Rx',
377
+ 4 => 'Ry',
378
+ 5 => 'Rz',
379
+ 6 => 'Throttle',
380
+ 7 => 'Rudder',
381
+ 8 => 'Wheel',
382
+ 9 => 'Gas',
383
+ 10 => 'Brake',
384
+ 16 => 'Hat0X',
385
+ 17 => 'Hat0Y',
386
+ 18 => 'Hat1X',
387
+ 19 => 'Hat1Y',
388
+ 20 => 'Hat2X',
389
+ 21 => 'Hat2Y',
390
+ 22 => 'Hat3X',
391
+ 23 => 'Hat 3Y',
392
+ 24 => 'Pressure',
393
+ 25 => 'Distance',
394
+ 26 => 'XTilt',
395
+ 27 => 'YTilt',
396
+ 28 => 'Tool Width',
397
+ 32 => 'Volume',
398
+ 40 => 'Misc',
399
+ }
400
+
401
+ # type = Misc
402
+ EVENTS[4] = {
403
+ 0 => 'Serial',
404
+ 1 => 'Pulseled',
405
+ 2 => 'Gesture',
406
+ 3 => 'RawData',
407
+ 4 => 'ScanCode',
408
+ }
409
+
410
+ # type = LED
411
+ EVENTS[17] = {
412
+ 0 => 'NumLock',
413
+ 1 => 'CapsLock',
414
+ 2 => 'ScrollLock',
415
+ 3 => 'Compose',
416
+ 4 => 'Kana',
417
+ 5 => 'Sleep',
418
+ 6 => 'Suspend',
419
+ 7 => 'Mute',
420
+ 8 => 'Misc',
421
+ }
422
+
423
+ # type = Sound
424
+ EVENTS[18] = {
425
+ 0 => 'Click',
426
+ 1 => 'Bell',
427
+ 2 => 'Tone',
428
+ }
429
+
430
+ # type = Repeat
431
+ EVENTS[20] = {
432
+ 0 => 'Delay',
433
+ 1 => 'Period',
434
+ }
435
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: device_input
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Rick Hull
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: buildar
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ description: |
28
+ Pure ruby to read input events from the Linux kernel input device subsystem.
29
+ No dependencies. Ruby 2+ required
30
+ email:
31
+ executables:
32
+ - devsniff
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - README.md
37
+ - bin/devsniff
38
+ - lib/device_input.rb
39
+ - lib/device_input/events.rb
40
+ homepage: https://github.com/rickhull/device_input
41
+ licenses:
42
+ - GPL-3.0
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - "~>"
51
+ - !ruby/object:Gem::Version
52
+ version: '2'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.6.8
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Read input events from e.g. /dev/input/event0
64
+ test_files: []