device_input 0.0.3.1 → 0.1.0.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 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