revdev 0.1.0

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.
data/lib/revdev.rb ADDED
@@ -0,0 +1,44 @@
1
+ # -*- coding:utf-8; mode:ruby; -*-
2
+
3
+ require "revdev/revdev.so"
4
+
5
+ require "revdev/each_values_equal"
6
+
7
+ require "revdev/version"
8
+ require "revdev/event_device"
9
+ require "revdev/input_event"
10
+ require "revdev/input_id"
11
+
12
+ # just import linux/input.h
13
+ module Revdev
14
+ class EventDevice; end
15
+ class InputEvent; end
16
+ class InputId; end
17
+
18
+ PREFIX_CONVERTER = {
19
+ 'BTN' => 'KEY',
20
+ 'MT' => nil, # TODO how to use MT prefix values
21
+ 'ID' => nil, # TODO how to use ID prefix values
22
+ 'BUS' => nil # TODO how to use BUS prefix values
23
+ }
24
+
25
+ REVERSE_MAPS = Hash.new
26
+ constants.each do |const|
27
+ m = const.to_s.match(/^(FF_STATUS|[A-Z]{2,4})_/)
28
+ next if m.nil?
29
+
30
+ prefix = m[1]
31
+ if prefix == 'EV'
32
+ REVERSE_MAPS[:EV] ||= Hash.new
33
+ REVERSE_MAPS[:EV][const_get const] = const.to_sym
34
+ next
35
+ end
36
+ prefix = PREFIX_CONVERTER[prefix] if PREFIX_CONVERTER.has_key? prefix
37
+ next if prefix.nil?
38
+
39
+ ev = "EV_#{prefix}".to_sym
40
+ REVERSE_MAPS[ev] ||= Hash.new
41
+ REVERSE_MAPS[ev][const_get const] = const.to_sym
42
+ end
43
+
44
+ end
@@ -0,0 +1,12 @@
1
+
2
+ # -*- coding:utf-8; mode:ruby; -*-
3
+
4
+ module Revdev
5
+ module EachValuesEqual
6
+ def == obj
7
+ obj.instance_variables.delete_if do |name|
8
+ obj.instance_variable_get(name) == instance_variable_get(name)
9
+ end.empty?
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,81 @@
1
+ # -*- coding:utf-8; mode:ruby; -*-
2
+
3
+ module Revdev
4
+ class EventDevice
5
+
6
+ def initialize arg
7
+ if arg.kind_of? File
8
+ @file = arg
9
+ else
10
+ @file = File.new arg, 'r+'
11
+ end
12
+ end
13
+
14
+ def read_ioctl_with command
15
+ r = ""
16
+ @file.ioctl command, r
17
+ return r
18
+ end
19
+
20
+ def driver_version
21
+ r = read_ioctl_with EVIOCGVERSION
22
+ r.unpack('i').first
23
+ end
24
+
25
+ def read_ioctl_as_string_with command
26
+ r = read_ioctl_with command
27
+ r.unpack('Z*').first
28
+ end
29
+
30
+ def device_name
31
+ read_ioctl_as_string_with EVIOCGNAME
32
+ end
33
+
34
+ def physical_location
35
+ read_ioctl_as_string_with EVIOCGPHYS
36
+ end
37
+
38
+ def uniq_id
39
+ read_ioctl_as_string_with EVIOCGUNIQ
40
+ end
41
+
42
+ def device_prop
43
+ read_ioctl_as_string_with EVIOCGPROP
44
+ end
45
+
46
+ def global_key_state
47
+ read_ioctl_as_string_with EVIOCGKEY
48
+ end
49
+
50
+ def all_leds_status
51
+ read_ioctl_as_string_with EVIOCGLED
52
+ end
53
+
54
+ def all_sounds_status
55
+ read_ioctl_as_string_with EVIOCGSND
56
+ end
57
+
58
+ def all_switch_status
59
+ read_ioctl_as_string_with EVIOCGSW
60
+ end
61
+
62
+ # grab all input events of the event device
63
+ def grab
64
+ @file.ioctl EVIOCGRAB, 1
65
+ end
66
+
67
+ # release the grabbed event device
68
+ def ungrab
69
+ @file.ioctl EVIOCGRAB, 0
70
+ end
71
+
72
+ def read_input_event
73
+ InputEvent.new @file.read InputEvent::SIZEOF
74
+ end
75
+
76
+ def write_input_event ie
77
+ @file.syswrite ie.to_byte_string
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,48 @@
1
+ # -*- coding:utf-8; mode:ruby; -*-
2
+
3
+ module Revdev
4
+
5
+ # wraper of "struct input_event" on "input.h"
6
+ class InputEvent
7
+ include EachValuesEqual
8
+ attr_accessor :time, :type, :code, :value
9
+
10
+ # arg: String(byte string), Hash, Time
11
+ # type, code, value: Integer (ignored values if arg is String or Hash)
12
+ def initialize arg=nil, type = nil, code = nil, value = nil
13
+ if arg.kind_of? String
14
+ raw_initialize arg
15
+ elsif arg.kind_of? Hash
16
+ [:time, :type, :code, :value].each do |iv|
17
+ instance_variable_set("@#{iv}", arg[iv] || arg[iv.to_s])
18
+ end
19
+ @time ||= Time.now
20
+ else
21
+ @time = arg || Time.now
22
+ @type = type
23
+ @code = code
24
+ @value = value
25
+ end
26
+ end
27
+
28
+ # human readable @type of input event
29
+ def hr_type
30
+ REVERSE_MAPS[:EV][@type]
31
+ end
32
+
33
+ # human readable @code of input event
34
+ def hr_code
35
+ ht = hr_type
36
+ return nil if ht.nil?
37
+ map = REVERSE_MAPS[ht]
38
+ map && map[@code]
39
+ end
40
+
41
+ # human readable @code of input event
42
+ # not implement
43
+ def hr_value
44
+ nil
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,27 @@
1
+ # -*- coding:utf-8; mode:ruby; -*-
2
+
3
+ module Revdev
4
+
5
+ # wraper of "struct input_id" on "input.h"
6
+ class InputId
7
+ include Revdev::EachValuesEqual
8
+ attr_accessor :bustype, :vendor, :product, :version
9
+
10
+ def initialize(arg=nil, vendor=nil, product=nil, version=nil)
11
+ if arg.kind_of? String
12
+ raw_initialize arg
13
+ elsif arg.kind_of? Hash
14
+ [:bustype, :vendor, :product, :version].each do |iv|
15
+ instance_variable_set("@#{iv}", arg[iv] || arg[iv.to_s])
16
+ end
17
+ else
18
+ @bustype = arg
19
+ @vendor = vendor
20
+ @product = product
21
+ @version = version
22
+ end
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,3 @@
1
+ module Revdev
2
+ VERSION = "0.1.0"
3
+ end
data/revdev.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ # -*- coding:utf-8-unix; mode:ruby; -*-
2
+ require File.expand_path('../lib/revdev/version', __FILE__)
3
+
4
+ Gem::Specification.new do |g|
5
+ g.name = "revdev"
6
+ g.version = Revdev::VERSION
7
+ g.authors = ["Keiichiro Ui"]
8
+ g.email = ["keiichiro.ui@gmail.com"]
9
+ g.summary = "ruby binding to handling event devices."
10
+ g.description = "revdev is a ruby binding to handling event devices."
11
+ g.homepage = "https://rubygems.org/gems/revdev"
12
+ g.files = `git ls-files`.split($\)
13
+ # g.files = Dir.glob 'lib/**/*.rb'
14
+ # g.files += Dir.glob 'ext/**/*.{rb,c,h}'
15
+ g.executables = g.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ g.test_files = g.files.grep(%r{^(test|spec|features)/})
17
+ g.require_paths = ["lib"]
18
+ g.extensions = Dir.glob 'ext/**/extconf.rb'
19
+ g.add_development_dependency 'rake'
20
+ g.add_development_dependency 'bundler'
21
+ end
@@ -0,0 +1,95 @@
1
+ # -*- coding:utf-8; mode:ruby; -*-
2
+
3
+ require 'test/unit'
4
+ require 'revdev'
5
+
6
+ class EventDeviceTest < Test::Unit::TestCase
7
+ include Revdev
8
+
9
+ @@target = "test/tmp/file"
10
+
11
+ def initialize *args
12
+ super
13
+
14
+ @@target = File.expand_path @@target
15
+ dir = File.dirname @@target
16
+ if not File.directory? dir
17
+ Dir.mkdir dir
18
+ end
19
+ FileUtils.touch @@target
20
+
21
+ end
22
+
23
+ def test_consts
24
+ puts "## InputEvent Constants"
25
+ puts "# of consts: #{Revdev.constants.length}"
26
+ puts "# of REVERSE_MAP entries: #{Revdev::REVERSE_MAPS.size}"
27
+ puts "each # of REVERSE_MAP entries"
28
+ REVERSE_MAPS.each do |k,v|
29
+ puts "%15s => %4s" % [k.inspect,v.size]
30
+ end
31
+ end
32
+
33
+ def test_init
34
+ assert_nothing_raised do
35
+ EventDevice.new File.new @@target
36
+ EventDevice.new @@target
37
+ end
38
+ end
39
+
40
+ def test_ioctl_string_getters
41
+ return_data = "abc\000\234\90\444"
42
+ expected_data = "abc"
43
+ file = File.new @@target
44
+ $data = return_data
45
+
46
+ def file.ioctl command, data
47
+ if command.kind_of? Numeric
48
+ data << $data
49
+ else
50
+ raise "invalid command:#{command.class}"
51
+ end
52
+ end
53
+
54
+ [:device_name, :physical_location, :uniq_id, :device_prop, :global_key_state,
55
+ :all_leds_status, :all_sounds_status, :all_switch_status].each do |m|
56
+ evdev = EventDevice.new file
57
+ assert_equal expected_data, evdev.method(m).call
58
+ end
59
+ end
60
+
61
+ def test_read_input_event
62
+ file = File.new @@target
63
+ ie = InputEvent.new nil, 1, 2, 3
64
+ $data = ie.to_byte_string
65
+ $self = self
66
+
67
+ def file.read len
68
+ $self.assert_equal $data.length, len
69
+ $data
70
+ end
71
+
72
+ evdev = EventDevice.new file
73
+ assert_nothing_raised do
74
+ iee = evdev.read_input_event
75
+ assert_equal ie, iee
76
+ end
77
+ end
78
+
79
+ def test_write_key_input_event
80
+ file = File.new @@target
81
+ ie = InputEvent.new nil, 1, 2, 3
82
+ $data = ie.to_byte_string
83
+ $self = self
84
+
85
+ def file.syswrite data
86
+ $self.assert_equal $data, data
87
+ end
88
+
89
+ evdev = EventDevice.new file
90
+ assert_nothing_raised do
91
+ evdev.write_input_event ie
92
+ end
93
+ end
94
+
95
+ end
@@ -0,0 +1,60 @@
1
+ # -*- coding:utf-8; mode:ruby; -*-
2
+
3
+ require 'test/unit'
4
+ require 'revdev'
5
+
6
+ class InputEventTest < Test::Unit::TestCase
7
+ include Revdev
8
+
9
+ U16_MAX = 2**16 - 1
10
+ S32_MAX = 2**31 - 1
11
+
12
+ def setup
13
+ end
14
+
15
+ def teardown
16
+ end
17
+
18
+ def test_init
19
+ puts
20
+ ie = iee = ieee = nil
21
+ assert_nothing_raised do
22
+ t = Time.now
23
+ ie = InputEvent.new t, 1, 3, S32_MAX
24
+ p ie
25
+ iee = InputEvent.new :time => t,:type => 1, :code => 3, :value => S32_MAX
26
+ p iee
27
+ ieee = InputEvent.new ie.to_byte_string
28
+ p ieee
29
+ end
30
+ assert_equal ie, iee
31
+ assert_equal ie, ieee
32
+ end
33
+
34
+ def test_hr_blar
35
+ htype = :EV_KEY
36
+ type = self.class.const_get htype
37
+ hcode = :KEY_2
38
+ code = self.class.const_get hcode
39
+ value = 0
40
+
41
+ ie = InputEvent.new nil, type, code, value
42
+
43
+ assert_nothing_raised do
44
+ assert_equal htype, ie.hr_type
45
+ assert_equal hcode, ie.hr_code
46
+ assert_equal nil, ie.hr_value
47
+ end
48
+ end
49
+
50
+ def test_to_byte_string
51
+ t = Time.now
52
+ ie = InputEvent.new t, 1, 3, 0
53
+ iee = nil
54
+ assert_nothing_raised do
55
+ iee = InputEvent.new ie.to_byte_string
56
+ end
57
+ assert_equal ie, iee
58
+ end
59
+
60
+ end
@@ -0,0 +1,34 @@
1
+ # -*- coding:utf-8; mode:ruby; -*-
2
+
3
+ require 'test/unit'
4
+ require 'revdev'
5
+
6
+ class InputIdTest < Test::Unit::TestCase
7
+ include Revdev
8
+
9
+ U16_MAX = 2**16 - 1
10
+
11
+ def setup
12
+ end
13
+
14
+ def teardown
15
+ end
16
+
17
+ def test_init
18
+ puts
19
+
20
+ i = ii = iii = nil
21
+ assert_nothing_raised do
22
+ i = InputId.new 1, 2, 3, U16_MAX
23
+ p i
24
+ ii = InputId.new :bustype => 1, :vendor => 2, :product => 3, :version => U16_MAX
25
+ p ii
26
+ iii = InputId.new i.to_byte_string
27
+ p iii
28
+ end
29
+
30
+ assert_equal i, ii
31
+ assert_equal i, iii
32
+ end
33
+
34
+ end
@@ -0,0 +1,148 @@
1
+ # -*- coding:utf-8; mode:ruby; -*-
2
+
3
+ require 'test/unit'
4
+ require 'revdev'
5
+
6
+ class RevdevTest # < Test::Unit::TestCase
7
+
8
+ # DEVICE_FILE = "/dev/input/event0"
9
+ DEVICE_FILE = "/dev/input/event1"
10
+ # DEVICE_FILE = "/dev/input/event2"
11
+ # DEVICE_FILE = "/dev/input/event3"
12
+ # DEVICE_FILE = "/dev/input/event4"
13
+ # DEVICE_FILE = "/dev/input/event5"
14
+ DEVICE_NAME = "AT Translated Set 2 keyboard"
15
+
16
+ def initialize test_method_name
17
+ super
18
+ end
19
+
20
+ def setup
21
+ @evdev = Revdev::EventDevice.new DEVICE_FILE
22
+ end
23
+
24
+ def teardown
25
+ end
26
+
27
+ def test_driver_version
28
+ r = @evdev.driver_version
29
+ puts "\tdriver_version:\t"+r.to_s
30
+ end
31
+
32
+ def test_device_name
33
+ r = @evdev.device_name
34
+ puts "\tdevice_name:\t"+r
35
+ assert_equal String, r.class
36
+ assert_not_equal 0, r.length
37
+ end
38
+
39
+ def test_physical_location
40
+ begin
41
+ r = @evdev.physical_location
42
+ puts "\tphysical_location:\t"+r
43
+ assert_equal String, r.class
44
+ rescue Errno::ENOENT
45
+ # no assertion
46
+ end
47
+ end
48
+
49
+ def test_uniq_id
50
+ begin
51
+ r = @evdev.uniq_id
52
+ puts "\tuniq_id:\t"+r
53
+ assert_equal String, r.class
54
+ rescue Errno::ENOENT
55
+ # no assertion
56
+ end
57
+ end
58
+
59
+ def test_device_prop
60
+ begin
61
+ r = @evdev.device_prop
62
+ puts "\tdevice_prop:\t"+r
63
+ assert_equal String, r.class
64
+ rescue Errno::ENOENT
65
+ # no assertion
66
+ end
67
+ end
68
+
69
+ def test_global_key_state
70
+ begin
71
+ r = @evdev.global_key_state
72
+ puts "\tglobal_key_state:\t"+r
73
+ assert_equal String, r.class
74
+ rescue Errno::ENOENT
75
+ # no assertion
76
+ end
77
+ end
78
+
79
+ def test_all_leds_status
80
+ begin
81
+ r = @evdev.all_leds_status
82
+ puts "\tall_leds_status:\t"+r
83
+ assert_equal String, r.class
84
+ rescue Errno::ENOENT
85
+ # no assertion
86
+ end
87
+ end
88
+
89
+ def test_all_sounds_status
90
+ begin
91
+ r = @evdev.all_sounds_status
92
+ puts "\tall_sounds_status:\t"+r
93
+ assert_equal String, r.class
94
+ rescue Errno::ENOENT
95
+ # no assertion
96
+ end
97
+ end
98
+
99
+ def test_all_switch_status
100
+ begin
101
+ r = @evdev.all_switch_status
102
+ puts "\tall_switch_status:\t"+r
103
+ rescue Errno::ENOENT
104
+ # no assertion
105
+ end
106
+ end
107
+
108
+ def test#_read_input_event
109
+ Dir.glob("/dev/input/event{2,3,4}").each do |file|
110
+ evdev = Revdev::EventDevice.new file
111
+ puts "listening #{evdev.device_name} ..."
112
+ ie = evdev.read_input_event
113
+ assert_equal Time, ie.time.class
114
+ assert_equal Fixnum, ie.type.class
115
+ assert_equal Fixnum, ie.code.class
116
+ assert_equal Fixnum, ie.value.class
117
+ p ie
118
+ puts "hr_type: #{ie.hr_type.inspect}"
119
+ puts "hr_code: #{ie.hr_code.inspect}"
120
+ puts "hr_val: #{ie.hr_value.inspect}"
121
+ end
122
+ end
123
+
124
+ def test_write_key_input_event
125
+ evdev = Revdev::EventDevice.new "/dev/input/event2"
126
+ puts "writing 'abc' to #{evdev.device_name} ..."
127
+
128
+ type_key = Revdev::InputEvent::EV_KEY
129
+ type_syn = Revdev::InputEvent::EV_SYN
130
+ code_a = Revdev::InputEvent::KEY_A
131
+ code_report = Revdev::InputEvent::SYN_REPORT
132
+ value_press = 1
133
+ value_release = 0
134
+ [Revdev::InputEvent.new(nil, type_key, code_a, value_press),
135
+ Revdev::InputEvent.new(nil, type_key, code_a, value_release),
136
+ Revdev::InputEvent.new(nil, type_key, code_a, value_press),
137
+ Revdev::InputEvent.new(nil, type_key, code_a, value_release),
138
+ Revdev::InputEvent.new(nil, type_syn, code_report, 0)
139
+ ].each do |ie|
140
+ p ie
141
+ evdev.write_input_event ie
142
+ end
143
+ end
144
+
145
+ def test_constants
146
+ puts "Revdev::InputEvent::SIZEOF : #{Revdev::InputEvent::SIZEOF}"
147
+ end
148
+ end