revdev 0.1.0

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