device_input 0.3.1.1 → 1.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 +5 -5
- data/README.md +8 -13
- data/Rakefile +120 -0
- data/VERSION +1 -1
- data/device_input.gemspec +24 -0
- data/lib/device_input.rb +2 -7
- data/test/device_input.rb +98 -0
- data/test/helper.rb +51 -0
- metadata +16 -28
- data/lib/device_input/compat.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ad6579dcc34efa4420edde0db593da7023730451f37b805e98b438a271bfad36
|
4
|
+
data.tar.gz: d7dea2ee2567926f779fa0aca3bcccbbe6e84bce006dd51e275d8f3c163931b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa18a6a3d85040cc87a25be1556cf288bbe7b42154606fe1f17bd587d53236fab9bd11faa9491194067a515addea23b5514138f6e8c1a30dcf77b92592676858
|
7
|
+
data.tar.gz: 56c653f912cbdcb3a054f56e920066245c6859e4f9e51ed83bfe7c4afd3bcefb6dad91e14a39118797a0045529028428e659bb551df90ed628d824c94f5c62f4
|
data/README.md
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
[](https://github.com/rickhull/device_input/actions/workflows/ci.yaml)
|
2
2
|
[](http://badge.fury.io/rb/device_input)
|
3
|
-
[](https://gemnasium.com/rickhull/device_input)
|
4
|
-
[](https://hakiri.io/github/rickhull/device_input/master)
|
5
3
|
[](https://codeclimate.com/github/rickhull/device_input)
|
6
4
|
|
7
5
|
# Device Input
|
@@ -42,8 +40,7 @@ long time, it was pretty simple: events are 16 bytes:
|
|
42
40
|
|
43
41
|
However, this is only true for 32-bit platforms. On 64-bit platforms, event
|
44
42
|
timestamps became 16 bytes, increasing the size of events from 16 to 24 bytes.
|
45
|
-
This is because a timestamp is defined (ultimately) as two `long`s,
|
46
|
-
everyone knows, two longs don't make a light. No, wait -- it's that `long`s
|
43
|
+
This is because a timestamp is defined (ultimately) as two `long`s, which
|
47
44
|
are bigger on 64-bit platforms. It's easy to remember:
|
48
45
|
|
49
46
|
* 32-bit platform: 32-bit `long` (4 bytes)
|
@@ -61,7 +58,8 @@ executable code to assist in examining kernel input events.
|
|
61
58
|
|
62
59
|
**REQUIREMENTS**
|
63
60
|
|
64
|
-
* Ruby >= 2.
|
61
|
+
* Ruby >= 2.3
|
62
|
+
* Earlier rubies are supported on pre-1.0 versions
|
65
63
|
|
66
64
|
**DEPENDENCIES**
|
67
65
|
|
@@ -69,12 +67,12 @@ executable code to assist in examining kernel input events.
|
|
69
67
|
|
70
68
|
Install the gem:
|
71
69
|
```shell
|
72
|
-
$ gem install device_input
|
70
|
+
$ gem install device_input
|
73
71
|
```
|
74
72
|
|
75
73
|
Or, if using [Bundler](http://bundler.io/), add to your `Gemfile`:
|
76
74
|
```ruby
|
77
|
-
gem 'device_input', '~> 0
|
75
|
+
gem 'device_input', '~> 1.0'
|
78
76
|
```
|
79
77
|
|
80
78
|
# Usage
|
@@ -167,7 +165,7 @@ An event has:
|
|
167
165
|
* `#value`: Fixnum (signed) from `#data`
|
168
166
|
|
169
167
|
You will probably want to write your own read loop for your own project.
|
170
|
-
[`DeviceInput.read_loop`](lib/device_input.rb#
|
168
|
+
[`DeviceInput.read_loop`](lib/device_input.rb#L98) is very simple and can
|
171
169
|
easily be rewritten outside of this project's namespace and adapted for your
|
172
170
|
needs.
|
173
171
|
|
@@ -178,10 +176,7 @@ needs.
|
|
178
176
|
* https://www.kernel.org/doc/Documentation/input/input.txt
|
179
177
|
* https://www.kernel.org/doc/Documentation/input/event-codes.txt
|
180
178
|
|
181
|
-
|
182
|
-
about these structs towards the end of this document.
|
183
|
-
|
184
|
-
## Kernel structs
|
179
|
+
### Kernel structs
|
185
180
|
|
186
181
|
from https://www.kernel.org/doc/Documentation/input/input.txt
|
187
182
|
```
|
data/Rakefile
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
desc "Run tests"
|
3
|
+
Rake::TestTask.new :test do |t|
|
4
|
+
t.pattern = 'test/*.rb'
|
5
|
+
t.warning = true
|
6
|
+
end
|
7
|
+
|
8
|
+
task default: :test
|
9
|
+
|
10
|
+
|
11
|
+
#
|
12
|
+
# METRICS
|
13
|
+
#
|
14
|
+
|
15
|
+
metrics_tasks = []
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'flog_task'
|
19
|
+
|
20
|
+
# we want: flog --all --methods-only lib
|
21
|
+
# but: FlogTask doesn't support the equivalent of --all; oh well
|
22
|
+
methods_only = true
|
23
|
+
FlogTask.new(:flog, 200, ['lib'], nil, methods_only) do |t|
|
24
|
+
t.verbose = true
|
25
|
+
end
|
26
|
+
metrics_tasks << :flog
|
27
|
+
rescue LoadError
|
28
|
+
warn 'flog_task unavailable'
|
29
|
+
end
|
30
|
+
|
31
|
+
begin
|
32
|
+
require 'flay_task'
|
33
|
+
|
34
|
+
# we want: flay --liberal lib
|
35
|
+
# but: FlayTask doesn't support the equivalent of --liberal; oh well
|
36
|
+
FlayTask.new do |t|
|
37
|
+
t.dirs = ['lib']
|
38
|
+
t.verbose = true
|
39
|
+
end
|
40
|
+
metrics_tasks << :flay
|
41
|
+
rescue LoadError
|
42
|
+
warn 'flay_task unavailable'
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
require 'roodi_task'
|
47
|
+
RoodiTask.new patterns: ['lib/**/*.rb']
|
48
|
+
metrics_tasks << :roodi
|
49
|
+
rescue LoadError
|
50
|
+
warn 'roodi_task unavailable'
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Generate code metrics reports"
|
54
|
+
task :code_metrics => metrics_tasks
|
55
|
+
|
56
|
+
|
57
|
+
#
|
58
|
+
# PROFILING
|
59
|
+
#
|
60
|
+
|
61
|
+
desc "Show current system load"
|
62
|
+
task "loadavg" do
|
63
|
+
puts File.read "/proc/loadavg"
|
64
|
+
end
|
65
|
+
|
66
|
+
# make sure command is run against lib/ on the filesystem, not an installed gem
|
67
|
+
def lib_sh(cmd)
|
68
|
+
sh "RUBYLIB=lib #{cmd}"
|
69
|
+
end
|
70
|
+
|
71
|
+
# set up script, args, and rprof_args the way ruby-prof wants them
|
72
|
+
def rprof_sh(script, args, rprof_args = '')
|
73
|
+
lib_sh ['ruby-prof', rprof_args, script, '--', args].join(' ')
|
74
|
+
end
|
75
|
+
|
76
|
+
rprof_options = {
|
77
|
+
min_percent: 2,
|
78
|
+
printer: :graph,
|
79
|
+
mode: :process,
|
80
|
+
sort: :self,
|
81
|
+
}.inject('') { |memo, (flag,val)| memo + "--#{flag}=#{val} " }
|
82
|
+
|
83
|
+
evdump_options = {
|
84
|
+
count: 9999,
|
85
|
+
print: 'off',
|
86
|
+
}.inject('') { |memo, (flag,val)| memo + "--#{flag} #{val} " } + '/dev/zero'
|
87
|
+
|
88
|
+
desc "Run ruby-prof on bin/evdump (9999 events)"
|
89
|
+
task "ruby-prof" => "loadavg" do
|
90
|
+
puts
|
91
|
+
rprof_sh 'bin/evdump', evdump_options, rprof_options
|
92
|
+
end
|
93
|
+
|
94
|
+
desc "Run ruby-prof with --exclude-common-cycles"
|
95
|
+
task "ruby-prof-exclude" => "ruby-prof" do
|
96
|
+
puts
|
97
|
+
rprof_sh 'bin/evdump', evdump_options,
|
98
|
+
"#{rprof_options} --exclude-common-cycles"
|
99
|
+
end
|
100
|
+
|
101
|
+
task "no-prof" do
|
102
|
+
lib_sh "bin/evdump #{evdump_options}"
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
#
|
107
|
+
# GEM BUILD / PUBLISH
|
108
|
+
#
|
109
|
+
|
110
|
+
begin
|
111
|
+
require 'buildar'
|
112
|
+
|
113
|
+
Buildar.new do |b|
|
114
|
+
b.gemspec_file = 'device_input.gemspec'
|
115
|
+
b.version_file = 'VERSION'
|
116
|
+
b.use_git = true
|
117
|
+
end
|
118
|
+
rescue LoadError
|
119
|
+
# ok
|
120
|
+
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.1.1
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'device_input'
|
3
|
+
s.summary = 'Read input events from e.g. /dev/input/event0'
|
4
|
+
s.description = <<EOF
|
5
|
+
Pure ruby to read input events from the Linux kernel input device subsystem.
|
6
|
+
No dependencies. Ruby 2+ required
|
7
|
+
EOF
|
8
|
+
s.authors = ["Rick Hull"]
|
9
|
+
s.homepage = 'https://github.com/rickhull/device_input'
|
10
|
+
s.license = 'GPL-3.0'
|
11
|
+
|
12
|
+
s.required_ruby_version = ">= 2.3"
|
13
|
+
|
14
|
+
s.version = File.read(File.join(__dir__, 'VERSION')).chomp
|
15
|
+
|
16
|
+
s.files = %w[device_input.gemspec VERSION README.md Rakefile]
|
17
|
+
s.files += Dir['lib/**/*.rb']
|
18
|
+
s.files += Dir['test/**/*.rb']
|
19
|
+
s.files += Dir['bin/**/*.rb']
|
20
|
+
|
21
|
+
s.executables = ['evdump']
|
22
|
+
|
23
|
+
s.add_runtime_dependency 'slop', '~> 4.0'
|
24
|
+
end
|
data/lib/device_input.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'device_input/labels'
|
2
|
-
require '
|
2
|
+
require 'rbconfig/sizeof'
|
3
3
|
|
4
4
|
module DeviceInput
|
5
5
|
class Event
|
@@ -80,19 +80,14 @@ module DeviceInput
|
|
80
80
|
end
|
81
81
|
|
82
82
|
# display fields in hex
|
83
|
-
def
|
84
|
-
# :nocov:
|
85
|
-
require 'rbconfig/sizeof' # new in ruby 2.3
|
83
|
+
def hex
|
86
84
|
DEFINITION.inject('') { |memo, (field, type)|
|
87
85
|
int = @data.send(field)
|
88
86
|
width = RbConfig::SIZEOF.fetch(type)
|
89
87
|
# memo + ("%#0.#{width * 2}x" % int) + " "
|
90
88
|
memo + ("%0.#{width * 2}x" % int) + " "
|
91
89
|
}
|
92
|
-
# :nocov:
|
93
90
|
end
|
94
|
-
|
95
|
-
alias_method :hex, RUBY23 ? :ruby23_hex : :to_s
|
96
91
|
end
|
97
92
|
|
98
93
|
def self.read_loop(io)
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require_relative 'helper.rb'
|
2
|
+
|
3
|
+
require 'device_input'
|
4
|
+
|
5
|
+
describe DeviceInput::Event do
|
6
|
+
E = DeviceInput::Event
|
7
|
+
|
8
|
+
describe "type_labels" do
|
9
|
+
it "must return an array of strings" do
|
10
|
+
dne = E.type_labels(:does_not_exist)
|
11
|
+
expect(dne).must_be_instance_of(Array)
|
12
|
+
expect(dne.first).must_be_instance_of(String)
|
13
|
+
expect(dne.last).must_be_instance_of(String)
|
14
|
+
|
15
|
+
# 0 is EV_SYN
|
16
|
+
de = E.type_labels(0)
|
17
|
+
expect(de).must_be_instance_of(Array)
|
18
|
+
expect(de.first).must_be_instance_of(String)
|
19
|
+
expect(de.last).must_be_instance_of(String)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "code_labels" do
|
24
|
+
it "must return an array of strings" do
|
25
|
+
dne = E.code_labels(:does_not_exist, nil)
|
26
|
+
expect(dne).must_be_instance_of(Array)
|
27
|
+
expect(dne.first).must_be_instance_of(String)
|
28
|
+
expect(dne.last).must_be_instance_of(String)
|
29
|
+
|
30
|
+
# 0,0 = EV_SYN,SYN_REPORT
|
31
|
+
de = E.code_labels(0, 0)
|
32
|
+
expect(de).must_be_instance_of(Array)
|
33
|
+
expect(de.first).must_be_instance_of(String)
|
34
|
+
expect(de.last).must_be_instance_of(String)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "encode" do
|
39
|
+
it "must return a string" do
|
40
|
+
expect(E.encode(E::NULL_DATA)).must_be_instance_of(String)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "decode" do
|
45
|
+
it "must return a Data (struct)" do
|
46
|
+
expect(E.decode(E::NULL_MSG)).must_be_instance_of(E::Data)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "new instance" do
|
51
|
+
before do
|
52
|
+
@event = E.new(E::NULL_DATA)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "must have data" do
|
56
|
+
expect(@event.data).must_be_instance_of(E::Data)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "must have a timestamp" do
|
60
|
+
expect(@event.time).must_be_instance_of(Time)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "must have a type" do
|
64
|
+
expect(@event.type).must_be_instance_of(String)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "must have a code" do
|
68
|
+
expect(@event.code).must_be_instance_of(String)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "must have a value" do
|
72
|
+
expect(@event.value).must_be_kind_of(Integer)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "must have string representations" do
|
76
|
+
[:to_s, :pretty, :raw, :hex].each { |meth|
|
77
|
+
expect(@event.send(meth)).must_be_instance_of(String)
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe DeviceInput do
|
84
|
+
describe "read_loop" do
|
85
|
+
before do
|
86
|
+
@io = StringIO.new("\x00" * 64)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "must read at least one message from an io with 64 bytes" do
|
90
|
+
events = []
|
91
|
+
DeviceInput.read_loop(@io) { |event|
|
92
|
+
events << event
|
93
|
+
}
|
94
|
+
expect(events).wont_be_empty
|
95
|
+
expect(events.first).must_be_instance_of(E)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
if ENV['CODE_COVERAGE'] and
|
2
|
+
!%w[false no].include?(ENV['CODE_COVERAGE'].downcase)
|
3
|
+
|
4
|
+
require 'simplecov'
|
5
|
+
require 'simplecov_json_formatter'
|
6
|
+
|
7
|
+
class SimpleCov::Formatter::TextFormatter
|
8
|
+
FILENAME = 'metrics/coverage'
|
9
|
+
|
10
|
+
def format(result)
|
11
|
+
tot = result.files
|
12
|
+
rpt = ["Coverage: %0.1f%%" % tot.covered_percent,
|
13
|
+
"Strength: %0.2f" % tot.covered_strength,
|
14
|
+
" Lines: %i" % tot.lines_of_code,
|
15
|
+
" Covered: %i" % tot.covered_lines,
|
16
|
+
" N/A: %i" % tot.never_lines,
|
17
|
+
]
|
18
|
+
if tot.missed_lines > 0
|
19
|
+
rpt << "Missed: %i" % tot.missed_lines
|
20
|
+
end
|
21
|
+
if tot.skipped_lines > 0
|
22
|
+
rpt << "Skipped: %i" % tot.skipped_lines
|
23
|
+
end
|
24
|
+
rpt << result.files.map { |sfile|
|
25
|
+
"%i%% (%i/%i)\t%s" % [sfile.covered_percent,
|
26
|
+
sfile.covered_lines.length,
|
27
|
+
sfile.lines_of_code,
|
28
|
+
sfile.filename]
|
29
|
+
}.join("\n")
|
30
|
+
rpt = rpt.join("\n")
|
31
|
+
|
32
|
+
puts
|
33
|
+
puts rpt
|
34
|
+
if File.writable?(FILENAME)
|
35
|
+
File.open(FILENAME, 'w') { |f|
|
36
|
+
f.write(rpt + "\n")
|
37
|
+
}
|
38
|
+
puts "wrote #{FILENAME}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
SimpleCov.formatters = [
|
44
|
+
SimpleCov::Formatter::TextFormatter,
|
45
|
+
SimpleCov::Formatter::JSONFormatter,
|
46
|
+
]
|
47
|
+
|
48
|
+
SimpleCov.start
|
49
|
+
end
|
50
|
+
|
51
|
+
require 'minitest/autorun'
|
metadata
CHANGED
@@ -1,80 +1,68 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: device_input
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rick Hull
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
12
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
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: slop
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - "~>"
|
32
18
|
- !ruby/object:Gem::Version
|
33
|
-
version: '4'
|
34
|
-
type: :
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
35
21
|
prerelease: false
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
24
|
- - "~>"
|
39
25
|
- !ruby/object:Gem::Version
|
40
|
-
version: '4'
|
26
|
+
version: '4.0'
|
41
27
|
description: |
|
42
28
|
Pure ruby to read input events from the Linux kernel input device subsystem.
|
43
29
|
No dependencies. Ruby 2+ required
|
44
|
-
email:
|
30
|
+
email:
|
45
31
|
executables:
|
46
32
|
- evdump
|
47
33
|
extensions: []
|
48
34
|
extra_rdoc_files: []
|
49
35
|
files:
|
50
36
|
- README.md
|
37
|
+
- Rakefile
|
51
38
|
- VERSION
|
52
39
|
- bin/evdump
|
40
|
+
- device_input.gemspec
|
53
41
|
- lib/device_input.rb
|
54
|
-
- lib/device_input/compat.rb
|
55
42
|
- lib/device_input/labels.rb
|
43
|
+
- test/device_input.rb
|
44
|
+
- test/helper.rb
|
56
45
|
homepage: https://github.com/rickhull/device_input
|
57
46
|
licenses:
|
58
47
|
- GPL-3.0
|
59
48
|
metadata: {}
|
60
|
-
post_install_message:
|
49
|
+
post_install_message:
|
61
50
|
rdoc_options: []
|
62
51
|
require_paths:
|
63
52
|
- lib
|
64
53
|
required_ruby_version: !ruby/object:Gem::Requirement
|
65
54
|
requirements:
|
66
|
-
- - "
|
55
|
+
- - ">="
|
67
56
|
- !ruby/object:Gem::Version
|
68
|
-
version: '2'
|
57
|
+
version: '2.3'
|
69
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
59
|
requirements:
|
71
60
|
- - ">="
|
72
61
|
- !ruby/object:Gem::Version
|
73
62
|
version: '0'
|
74
63
|
requirements: []
|
75
|
-
|
76
|
-
|
77
|
-
signing_key:
|
64
|
+
rubygems_version: 3.4.4
|
65
|
+
signing_key:
|
78
66
|
specification_version: 4
|
79
67
|
summary: Read input events from e.g. /dev/input/event0
|
80
68
|
test_files: []
|
data/lib/device_input/compat.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'device_input/labels'
|
2
|
-
|
3
|
-
# :nocov:
|
4
|
-
module DeviceInput
|
5
|
-
if RbConfig::CONFIG.fetch("MAJOR").to_i < 2
|
6
|
-
raise "unsupported ruby version #{RbConfig::CONFIG['RUBY_VERSION_NAME']}"
|
7
|
-
else
|
8
|
-
RUBY23 = RbConfig::CONFIG.fetch("MINOR").to_i >= 3
|
9
|
-
end
|
10
|
-
|
11
|
-
unless RUBY23
|
12
|
-
class Event
|
13
|
-
def CODES.dig(*args)
|
14
|
-
memo = self
|
15
|
-
args.each { |a|
|
16
|
-
memo = memo[a] rescue nil
|
17
|
-
break unless memo
|
18
|
-
}
|
19
|
-
memo
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
# :nocov:
|