device_input 0.0.3.1 → 0.1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 42e1a1dde8d9b9884e97bef833d8890d9aaa3a23
4
- data.tar.gz: 5076d4580ee666d8c82a0f9b924ed94c2890b041
3
+ metadata.gz: 803a063ac3069383c1d2f3cff0dc5ff5c7caf43a
4
+ data.tar.gz: 97282e042e693fda103f18ccaf10d19eee397308
5
5
  SHA512:
6
- metadata.gz: 3ae5856b3d005ea2b268e931d5c1ac3c73cc8fd1a31ce0e4264b16adc4f70841b3858e8fd5aa771df47631da111eba823ef0ca1f3089c6a6f602a866eb759f58
7
- data.tar.gz: 5f4c0defc1877124d209cc424f312cd099493f84a1feab65f651210b08475f2d56f4fdfd827b172a8b6ce3527f0e4bc5a7e1ba1301f0dcf8158ec59da1d302a6
6
+ metadata.gz: 970a6aab1d8d674cb3b8db5c2509c313ed195600dca3aefd4ed80ae826cc140ab20d86b7d50e166f10b7b7a5b37136c8ab8fd94b30406768df53892498e5fe50
7
+ data.tar.gz: a83de5605ceec1982206ab8f9f072e40e65b0fd84eb00e1b28edbfc8a1b2beb8768972839c83dc7ec67783192f4cbaa557a65bc1e368b00e5008524e071a52a9
data/README.md CHANGED
@@ -28,14 +28,14 @@ To determine the message size, we need to know the data structure. For a
28
28
  long time, it was pretty simple: events are 16 bytes:
29
29
 
30
30
  * timestamp - 8 bytes
31
- * type - 1 byte
32
- * code - 1 byte
33
- * value - 2 bytes
31
+ * type - 2 bytes
32
+ * code - 2 bytes
33
+ * value - 4 bytes
34
34
 
35
35
  However, this is only true for 32-bit platforms. On 64-bit platforms, event
36
- timestamps became 16 bytes, increasing events from 16 to 24 bytes. This is
37
- because a timestamp is defined as two `long`s, and `long`s are bigger on
38
- 64-bit platforms. It's easy to remember:
36
+ timestamps became 16 bytes, increasing the size of events from 16 to 24 bytes.
37
+ This is because a timestamp is defined (ultimately) as two `long`s, and
38
+ `long`s are bigger on 64-bit platforms. It's easy to remember:
39
39
 
40
40
  * 32-bit platform: 32-bit `long` (4 bytes)
41
41
  * 64-bit platform: 64-bit `long` (8 bytes)
@@ -50,14 +50,16 @@ executable code to assist in examining kernel input events.
50
50
 
51
51
  # Installation
52
52
 
53
- Install the gem:
53
+ Requirements: Ruby >= 2.0
54
+
55
+ Dependencies: none
54
56
 
57
+ Install the gem:
55
58
  ```
56
59
  $ gem install device_input # sudo as necessary
57
60
  ```
58
61
 
59
62
  Or, if using [Bundler](http://bundler.io/), add to your `Gemfile`:
60
-
61
63
  ```
62
64
  gem 'device_input', '~> 0.0'
63
65
  ```
@@ -71,7 +73,6 @@ $ sudo devsniff /dev/input/event0
71
73
  ```
72
74
 
73
75
  When the `f` key is pressed:
74
-
75
76
  ```
76
77
  Misc:ScanCode:33
77
78
  Key:F:1
@@ -81,6 +82,9 @@ Sync:Sync:0
81
82
  And released:
82
83
  ```
83
84
  Misc:ScanCode:33
85
+ Key:F:1
86
+ Sync:Sync:0
87
+ Misc:ScanCode:33
84
88
  Key:F:0
85
89
  Sync:Sync:0
86
90
  ```
@@ -90,18 +94,25 @@ Sync:Sync:0
90
94
  ```
91
95
  require 'device_input'
92
96
 
97
+ # this loops forever and blocks waiting for input
93
98
  DeviceInput.read_from('/dev/input/event0') do |event|
94
99
  puts event
100
+ # break if event.time > start + 30
95
101
  end
96
102
  ```
97
103
 
98
104
  An event has:
99
105
 
100
- * `#data` - a Struct of ints (class name Data)
101
- * `#time` - a Time, accurate to usecs
102
- * `#type` - a String, possibly UNK-X where X is the integer from `#data`
103
- * `#code` - a String, possibly UNK-X-Y where X and Y are from `#data`
104
- * `#value` - a Fixnum (signed)
106
+ * `#data`: Struct of ints (class name Data)
107
+ * `#time`: Time, accurate to usecs
108
+ * `#type`: String label, possibly `UNK-X` where X is the integer from `#data`
109
+ * `#code`: String label, possibly `UNK-X-Y` where X and Y are from `#data`
110
+ * `#value`: Fixnum (signed) from `#data`
111
+
112
+ You will probably want to write your own read loop for your own project.
113
+ [`DeviceInput.read_from`](lib/device_input.rb#L111) is very simple and can
114
+ easily be rewritten outside of this project's namespace and adapted for your
115
+ needs.
105
116
 
106
117
  # Research
107
118
 
@@ -116,7 +127,6 @@ about these structs towards the end of this document.
116
127
  ## Kernel structs
117
128
 
118
129
  from https://www.kernel.org/doc/Documentation/input/input.txt
119
-
120
130
  ```
121
131
  struct input_event {
122
132
  struct timeval time;
@@ -128,7 +138,6 @@ struct input_event {
128
138
 
129
139
  from
130
140
  https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input.h#n25
131
-
132
141
  ```
133
142
  struct input_event {
134
143
  struct timeval time;
@@ -139,7 +148,6 @@ struct input_event {
139
148
  ```
140
149
 
141
150
  What's a [`timeval`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/time.h#n15)?
142
-
143
151
  ```
144
152
  struct timeval {
145
153
  __kernel_time_t tv_sec; /* seconds */
@@ -148,7 +156,6 @@ struct timeval {
148
156
  ```
149
157
 
150
158
  What's a [`__kernel_time_t`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/posix_types.h#n88)?
151
-
152
159
  ```
153
160
  typedef long __kernel_long_t;
154
161
  # ...
@@ -160,7 +167,6 @@ typedef __kernel_long_t __kernel_time_t;
160
167
  What's a [`__u16`](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/int-l64.h#n23)?
161
168
  We're pretty sure it's an unsigned 16 bit integer. Likewise `__s32` should
162
169
  be a signed 32-bit integer:
163
-
164
170
  ```
165
171
  typedef unsigned short __u16;
166
172
 
@@ -190,9 +196,9 @@ platform, you get 32 bits (4 bytes). On a 64-bit platform you get 64 bits
190
196
 
191
197
  ## Ruby tools
192
198
 
193
- We can use `RbConfig` and `Array#pack`/`String#unpack` to help us read these
194
- binary structs:
195
-
199
+ We can use
200
+ [`RbConfig::SIZEOF`](http://idiosyncratic-ruby.com/42-ruby-config.html#rbconfigsizeof)
201
+ and `Array#pack`/`String#unpack` to help us read these binary structs:
196
202
  ```
197
203
  FIELD C RbConfig Pack
198
204
  --- --- --- ---
@@ -206,5 +212,6 @@ value __s32 int32_t l
206
212
  # Acknowledgments
207
213
 
208
214
  * Inspired by https://github.com/prullmann/libdevinput (don't use it)
209
- - also the source of the [event code labels](lib/device_input/codes.rb)
215
+ - also the source of an early version of the
216
+ [event code labels](lib/device_input/codes.rb)
210
217
  * Thanks to al2o3-cr from #ruby on Freenode for feedback
data/bin/devsniff CHANGED
@@ -3,7 +3,22 @@
3
3
  require 'device_input'
4
4
 
5
5
  device = ARGV.shift || '/dev/input/event0'
6
+ mode = (ARGV.shift || 'normal').downcase
7
+
8
+ if !File.readable?(device)
9
+ puts "#{device} cannot be read. Perhaps you need to sudo?"
10
+ exit 1
11
+ end
12
+
13
+ case mode
14
+ when 'normal'
15
+ mode = 'to_s'
16
+ when 'pretty', 'raw', 'bytes'
17
+ # ok
18
+ else
19
+ raise "unsupported mode: #{mode}"
20
+ end
6
21
 
7
22
  DeviceInput.read_from(device) { |event|
8
- puts event
23
+ puts event.send(mode)
9
24
  }
@@ -3,7 +3,10 @@ module DeviceInput
3
3
 
4
4
  # type = Sync
5
5
  CODES[0] = {
6
- 0 => 'Sync',
6
+ 0 => ['SYN_REPORT', 'Report'],
7
+ 1 => ['SYN_CONFIG', 'Config'],
8
+ 2 => ['SYN_MT_REPORT', 'Multitouch'],
9
+ 3 => ['SYN_DROPPED', 'Desync'],
7
10
  }
8
11
 
9
12
  # type = Key
data/lib/device_input.rb CHANGED
@@ -19,17 +19,18 @@ module DeviceInput
19
19
 
20
20
  # these are just labels, not used internally
21
21
  TYPES = {
22
- 0 => 'Sync',
23
- 1 => 'Key',
24
- 2 => 'Relative',
25
- 3 => 'Absolute',
26
- 4 => 'Misc',
27
- 17 => 'LED',
28
- 18 => 'Sound',
29
- 20 => 'Repeat',
30
- 21 => 'ForceFeedback',
31
- 22 => 'Power',
32
- 23 => 'ForceFeedbackStatus',
22
+ 0x00 => ['EV_SYN', 'Sync'],
23
+ 0x01 => ['EV_KEY', 'Key'],
24
+ 0x02 => ['EV_REL', 'Relative'],
25
+ 0x03 => ['EV_ABS', 'Absolute'],
26
+ 0x04 => ['EV_MSC', 'Misc'],
27
+ 0x05 => ['EV_SW', 'ToggleSwitch'],
28
+ 0x17 => ['EV_LED', 'LED'],
29
+ 0x18 => ['EV_SND', 'Sound'],
30
+ 0x20 => ['EV_REP', 'Repeat'],
31
+ 0x21 => ['EV_FF', 'ForceFeedback'],
32
+ 0x22 => ['EV_PWR', 'Power'],
33
+ 0x23 => ['EV_FF_STATUS', 'ForceFeedbackStatus'],
33
34
  }
34
35
 
35
36
  # convert Event::Data to a string
@@ -42,14 +43,21 @@ module DeviceInput
42
43
  Data.new *binstr.unpack(PACK)
43
44
  end
44
45
 
45
- def self.type_str(type_code)
46
- TYPES[type_code] || "UNK-#{type_code}"
46
+ # return an array from [raw ... pretty]
47
+ def self.type_labels(type_code)
48
+ TYPES[type_code] || ["UNK-#{type_code}"]
47
49
  end
48
50
 
49
- def self.code_str(type_code, code_code)
51
+ # return an array from [raw ... pretty]
52
+ def self.code_labels(type_code, code_code)
50
53
  require 'device_input/codes'
51
- DeviceInput::CODES.dig(type_code, code_code) ||
52
- "UNK-#{type_code}-#{code_code}"
54
+ labels = DeviceInput::CODES.dig(type_code, code_code)
55
+ if labels
56
+ # not all labels have been converted to arrays yet
57
+ labels.kind_of?(Enumerable) ? labels : [labels]
58
+ else
59
+ ["UNK-#{type_code}-#{code_code}"]
60
+ end
53
61
  end
54
62
 
55
63
  NULL_DATA = Data.new(0, 0, 0, 0, 0)
@@ -61,8 +69,9 @@ module DeviceInput
61
69
  def initialize(data)
62
70
  @data = data
63
71
  @time = Time.at(data.tv_sec, data.tv_usec)
64
- @type = self.class.type_str(data.type)
65
- @code = self.class.code_str(data.type, data.code)
72
+ # take the raw label, closest to the metal
73
+ @type = self.class.type_labels(data.type).first
74
+ @code = self.class.code_labels(data.type, data.code).first
66
75
  end
67
76
 
68
77
  def value
@@ -72,8 +81,34 @@ module DeviceInput
72
81
  def to_s
73
82
  [@type, @code, @data.value].join(':')
74
83
  end
84
+
85
+ # show timestamp and use the last of the labels
86
+ def pretty
87
+ [@time.strftime("%Y-%m-%d %H:%M:%S.%L"),
88
+ [self.class.type_labels(@data.type).last,
89
+ self.class.code_labels(@data.type, @data.code).last,
90
+ @data.value].join(':'),
91
+ ].join(" ")
92
+ end
93
+
94
+ # don't use any labels
95
+ def raw
96
+ [@data.type, @data.code, @data.value].join(':')
97
+ end
98
+
99
+ # display fields in hex
100
+ def bytes
101
+ require 'rbconfig/sizeof'
102
+ DEFINITION.inject('') { |memo, (field, type)|
103
+ int = @data.send(field)
104
+ width = RbConfig::SIZEOF.fetch(type)
105
+ # memo + ("%#0.#{width * 2}x" % int) + " "
106
+ memo + ("%0.#{width * 2}x" % int) + " "
107
+ }
108
+ end
75
109
  end
76
110
 
111
+ # never gonna give you up
77
112
  def self.read_from(filename)
78
113
  File.open(filename, 'r') { |f|
79
114
  loop {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: device_input
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3.1
4
+ version: 0.1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Hull