device_input 0.0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: []