vigilem-evdev 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/ext/Rakefile +31 -0
  4. data/ext/rake_helper.rb +10 -0
  5. data/lib/vigilem/_evdev.rb +24 -0
  6. data/lib/vigilem/evdev.rb +14 -0
  7. data/lib/vigilem/evdev/at_exit.rb +8 -0
  8. data/lib/vigilem/evdev/context_filter.rb +92 -0
  9. data/lib/vigilem/evdev/demultiplexer.rb +26 -0
  10. data/lib/vigilem/evdev/device.rb +182 -0
  11. data/lib/vigilem/evdev/device_capabilities.rb +53 -0
  12. data/lib/vigilem/evdev/dom.rb +8 -0
  13. data/lib/vigilem/evdev/dom/adapter.rb +87 -0
  14. data/lib/vigilem/evdev/dom/code_values_tables.rb +172 -0
  15. data/lib/vigilem/evdev/dom/input_event_converter.rb +329 -0
  16. data/lib/vigilem/evdev/dom/input_event_utils.rb +48 -0
  17. data/lib/vigilem/evdev/dom/key_values_tables.rb +248 -0
  18. data/lib/vigilem/evdev/dom/kp_table.rb +52 -0
  19. data/lib/vigilem/evdev/focus_context_filter.rb +124 -0
  20. data/lib/vigilem/evdev/input_system_handler.rb +69 -0
  21. data/lib/vigilem/evdev/key_map_cache.rb +64 -0
  22. data/lib/vigilem/evdev/multiplexer.rb +73 -0
  23. data/lib/vigilem/evdev/system.rb +17 -0
  24. data/lib/vigilem/evdev/system/input.rb +1053 -0
  25. data/lib/vigilem/evdev/system/input/event.rb +4 -0
  26. data/lib/vigilem/evdev/system/input/input_event.rb +33 -0
  27. data/lib/vigilem/evdev/system/int.rb +9 -0
  28. data/lib/vigilem/evdev/system/ioctl.rb +143 -0
  29. data/lib/vigilem/evdev/system/keymap_loaders.rb +89 -0
  30. data/lib/vigilem/evdev/system/keymap_loaders/dumpkeys_loader.rb +98 -0
  31. data/lib/vigilem/evdev/system/keymap_loaders/kmap_loader.rb +74 -0
  32. data/lib/vigilem/evdev/system/posix_types.rb +5 -0
  33. data/lib/vigilem/evdev/system/time.rb +21 -0
  34. data/lib/vigilem/evdev/transfer_agent.rb +40 -0
  35. data/lib/vigilem/evdev/version.rb +5 -0
  36. data/lib/vigilem/evdev/vty_context_filter.rb +216 -0
  37. data/spec/after_each_example_group.rb +29 -0
  38. data/spec/delete_test_cache_after_group.rb +26 -0
  39. data/spec/spec_helper.rb +30 -0
  40. data/spec/vigilem/_evdev_spec.rb +11 -0
  41. data/spec/vigilem/evdev/context_filter_spec.rb +114 -0
  42. data/spec/vigilem/evdev/demultiplexer_spec.rb +44 -0
  43. data/spec/vigilem/evdev/device_capabilities_spec.rb +0 -0
  44. data/spec/vigilem/evdev/device_spec.rb +97 -0
  45. data/spec/vigilem/evdev/dom/adapter_spec.rb +5 -0
  46. data/spec/vigilem/evdev/dom/input_event_converter_spec.rb +253 -0
  47. data/spec/vigilem/evdev/dom/input_event_utils_spec.rb +23 -0
  48. data/spec/vigilem/evdev/focus_context_filter_spec.rb +112 -0
  49. data/spec/vigilem/evdev/input_system_handler_spec.rb +146 -0
  50. data/spec/vigilem/evdev/key_map_cache_spec.rb +65 -0
  51. data/spec/vigilem/evdev/multiplexer_spec.rb +55 -0
  52. data/spec/vigilem/evdev/system/input/input_event_spec.rb +33 -0
  53. data/spec/vigilem/evdev/system/input_spec.rb +274 -0
  54. data/spec/vigilem/evdev/system/int_spec.rb +30 -0
  55. data/spec/vigilem/evdev/system/ioctl_spec.rb +206 -0
  56. data/spec/vigilem/evdev/system/keymap_loaders/dumpkeys_loader_spec.rb +5 -0
  57. data/spec/vigilem/evdev/system/keymap_loaders/kmap_loader_spec.rb +24 -0
  58. data/spec/vigilem/evdev/system/keymap_loaders_spec.rb +22 -0
  59. data/spec/vigilem/evdev/system/posix_types_spec.rb +15 -0
  60. data/spec/vigilem/evdev/system/time_spec.rb +18 -0
  61. data/spec/vigilem/evdev/transfer_agent_spec.rb +57 -0
  62. data/spec/vigilem/evdev/vty_context_filter_spec.rb +282 -0
  63. metadata +286 -0
@@ -0,0 +1,5 @@
1
+ require 'ffi'
2
+
3
+ FFI.typedef :long, :__kernel_long_t
4
+ FFI.typedef :__kernel_long_t, :__kernel_time_t
5
+ FFI.typedef :int, :__kernel_suseconds_t
@@ -0,0 +1,21 @@
1
+ require 'vigilem/support'
2
+
3
+ require 'vigilem/evdev/system/posix_types'
4
+
5
+ module Vigilem
6
+ module Evdev
7
+ module Time
8
+ # represents timeval from time.h
9
+ class Timeval < ::VFFIStruct
10
+ layout_with_methods :tv_sec, :__kernel_time_t,
11
+ :tv_usec, :__kernel_suseconds_t
12
+
13
+ #
14
+ # @return [Numeric]
15
+ def to_f
16
+ tv_sec.to_f + (tv_usec.to_f/1000000.0)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ require 'vigilem/core/transfer_agent'
2
+
3
+ require 'vigilem/evdev/demultiplexer'
4
+
5
+ require 'vigilem/evdev/multiplexer'
6
+
7
+ module Vigilem
8
+ module Evdev
9
+ #
10
+ #
11
+ class TransferAgent < Core::TransferAgent
12
+
13
+ class << self
14
+
15
+ # @todo move away from singleton and look at the one used by x11
16
+ # @param args [Hash]
17
+ # @param :inputs [Array]
18
+ # @param :outputs [Hash{observer_object => {event_opts}]
19
+ # @see Demultiplexer#add_oberver
20
+ # @return [TransferAgent]
21
+ def acquire(args={})
22
+ if @transfer_agent
23
+ @transfer_agent.multiplexer.add_inputs(*args[:inputs]) if args[:inputs]
24
+ @transfer_agent.add_observers(args[:outputs]) if args[:outputs]
25
+ if ((din = @transfer_agent.demultiplexer.input) || (mout = @transfer_agent.multiplexer.out)).nil? or not mout.equal?(din)
26
+ @transfer_agent.demultiplexer.input = @transfer_agent.multiplexer.out = (mout || din || [])
27
+ end
28
+ @transfer_agent
29
+ else
30
+ m = Multiplexer.acquire(args[:inputs])
31
+ d = Demultiplexer.acquire(args[:outputs])
32
+ @transfer_agent = new(d, m)
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,5 @@
1
+ module Vigilem
2
+ module Evdev
3
+ VERSION = '0.1.3'
4
+ end
5
+ end
@@ -0,0 +1,216 @@
1
+ require 'vigilem/support/core_ext'
2
+
3
+ require 'vigilem/support/key_map'
4
+
5
+ require 'vigilem/_evdev'
6
+
7
+ require 'vigilem/evdev/context_filter'
8
+
9
+ module Vigilem
10
+ module Evdev
11
+ #
12
+ # filters events if the VTY differs from the one of this process
13
+ class VTYContextFilter
14
+
15
+ KeyMap = Support::KeyMap
16
+
17
+ include ContextFilter
18
+ # @todo make these class_methods
19
+ attr_reader :current_console_num, :console_keys,
20
+ :current_console_keys, :other_console_keys
21
+
22
+ #
23
+ # @param [KeyMap] keymap
24
+ # @return
25
+ def initialize(keymap=Evdev.key_map)
26
+ @key_map = keymap unless keymap.eql? Evdev.key_map
27
+
28
+ @current_console_num = `fgconsole`.rstrip.to_i
29
+ curr_con_keys, oth_con_keys =
30
+ self.class.console_keys(keymap).partition {|syms,v| v == "Console_#{@current_console_num}" }
31
+ @current_console_keys, @other_console_keys = KeyMap[curr_con_keys], KeyMap[oth_con_keys]
32
+
33
+ @current_console_keys.left_side_aliases(:keycode, :keycodes)
34
+ @current_console_keys.right_side_aliases(:keysym, :keysyms)
35
+
36
+ @other_console_keys.left_side_aliases(:keycode, :keycodes)
37
+ @other_console_keys.right_side_aliases(:keysym, :keysyms)
38
+
39
+ @current_keys = []
40
+ end
41
+
42
+ #
43
+ # @param [KeyMap] keymap
44
+ # @return [KeyMap]
45
+ def self.console_keys(keymap)
46
+ @console_keys = if keymap.metadata[:loader].class.name =~ /KmapLoader/
47
+ keymap.select {|k,v| v =~ /console_\d+/i }
48
+ else
49
+ console_syms = keymap.info.keysyms.select {|k,v| v =~ /console_\d+/i }
50
+ tmp = keymap.select {|k,v| v =~ /^#{console_syms.keys.join('|')}$/ }
51
+ tmp.each {|k,v| tmp[k] = console_syms[v] }
52
+ end
53
+ end
54
+
55
+ #
56
+ # @return [KeyMap]
57
+ def key_map
58
+ @key_map || Evdev.key_map
59
+ end
60
+
61
+ #
62
+ # @return [Array]
63
+ def current_keys
64
+ if @current_keys and current_keys_changed?
65
+ max_and_one = KeyMap.mod_weights.values.max + 1
66
+ @current_keys.sort_by! {|ksym| KeyMap.mod_weights[ksym.downcase] || max_and_one }
67
+ @current_keys_hash_cache = @current_keys.hash
68
+ @current_keys
69
+ else
70
+ if @current_keys.nil?
71
+ @current_keys = []
72
+ @current_keys_hash_cache = @current_keys.hash
73
+ end
74
+ @current_keys
75
+ end
76
+ end
77
+
78
+ #
79
+ # @param [Array<System::InputEvent>] events
80
+ # @return [Array]
81
+ def process(*events)
82
+ events.select do |event|
83
+ off_status = off?
84
+ key_check = if event.type == System::Input::EV_KEY
85
+ if event.value == 1
86
+ add_key(keysym_or_keycode(event.code))
87
+ off_status
88
+ elsif event.value == 0
89
+ kork = keysym_or_keycode(event.code)
90
+ release_status = allow_release?(kork)
91
+ remove_key(kork)
92
+ release_status
93
+ end
94
+ end
95
+ if key_check.nil? then off_status else key_check end
96
+ end
97
+ end
98
+
99
+ #
100
+ # @param key
101
+ # @return [Array]
102
+ def add_key(keycode_or_keysym)
103
+ current_keys << keycode_or_keysym
104
+ end
105
+
106
+ #
107
+ # @param [Fixnum] key_num
108
+ # @return
109
+ def remove_key(keycode_or_keysym)
110
+ current_keys.delete(keycode_or_keysym)
111
+ end
112
+
113
+ #
114
+ # @todo name
115
+ # @return [String]
116
+ def keysym_or_keycode(key_num)
117
+ sym = keysym(keycode = "keycode#{key_num}")
118
+ if sym =~ /shift|alt|c(on)?tro?l|capsshift/i
119
+ sym
120
+ else
121
+ keycode
122
+ end
123
+ end
124
+
125
+ # @todo move to KeyMapUtils, or something like that
126
+ # @param [Integer] key_num
127
+ # @return [String]
128
+ def keysym(keycode)
129
+ if key_map.metadata[:loader].class.name =~ /KmapLoader/
130
+ key_map.keysym(keycode)
131
+ else
132
+ key_map.info.keysyms[key_map.char_ref(keycode)]
133
+ end
134
+ end
135
+
136
+ #
137
+ # @return [TrueClass || FalseClass || NilClass]
138
+ def on?
139
+ if changed_vty?
140
+ self.filter_ommisions = current_keys_downcase
141
+ on_change(ON)
142
+ elsif reverted_vty?
143
+ self.filter_ommisions = current_keys_downcase
144
+ on_change(OFF)
145
+ end
146
+ was_on?
147
+ end
148
+
149
+ #
150
+ # @return [TrueClass || FalseClass]
151
+ def reverted_vty?
152
+ was_on? and current_console_keys.keysym(current_keys_downcase)
153
+ end
154
+
155
+ #
156
+ # @return [TrueClass || FalseClass]
157
+ def changed_vty?
158
+ was_off? and other_console_keys.keysym(current_keys_downcase)
159
+ end
160
+
161
+ #
162
+ # @return [TrueClass || FalseClass]
163
+ def off?
164
+ not on?
165
+ end
166
+
167
+ private
168
+ #
169
+ # @return [Integer] the hash of current_keys last time it was set
170
+ def current_keys_hash_cache
171
+ @current_keys_hash_cache ||= @current_keys.hash
172
+ end
173
+
174
+ #
175
+ # @return [TrueClass || FalseClass] if the cached value of
176
+ # #current_keys.hash changed
177
+ def current_keys_changed?
178
+ current_keys_hash_cache != @current_keys.hash
179
+ end
180
+
181
+ # @todo name!
182
+ # @return [Array]
183
+ def current_keys_downcase
184
+ downcase_hash ||= 0
185
+ if @current_keys_downcase.nil? or current_keys_hash_cache != downcase_hash
186
+ downcase_hash = current_keys_hash_cache
187
+ @current_keys_downcase = current_keys.map(&:downcase)
188
+ else
189
+ @current_keys_downcase
190
+ end
191
+ end
192
+
193
+ private
194
+ attr_writer :filter_ommisions
195
+
196
+ #
197
+ # @param other
198
+ # @return [TrueClass || FalseClass]
199
+ def allow_release?(keycode_or_keysym)
200
+ lower_kork = keycode_or_keysym.downcase
201
+ if filter_ommisions.include? lower_kork
202
+ filter_ommisions.delete(lower_kork)
203
+ on?
204
+ else
205
+ off?
206
+ end
207
+ end
208
+
209
+ #
210
+ # @return [Array]
211
+ def filter_ommisions
212
+ @filter_ommisions ||= []
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,29 @@
1
+ #
2
+ # fires after every example_group
3
+ module AfterEachExampleGroup
4
+ def after_each_example_group?
5
+ @after_each_example_group_flag ||= false
6
+ end
7
+
8
+ def after_each_example_group(&block)
9
+ if block
10
+ @after_each_example_group_flag = true
11
+ @after_each_example_group = block
12
+ else
13
+ @after_each_example_group
14
+ end
15
+ end
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+
20
+ config.before :all do |example_group|
21
+ if ((egc = example_group.class).respond_to? :after_each_example_group? and egc.after_each_example_group?)
22
+ (egc.descendants - [egc]).map do |eg|
23
+ eg.append_after(:context, &egc.after_each_example_group)
24
+ end
25
+ end
26
+ end
27
+
28
+ config.extend AfterEachExampleGroup
29
+ end
@@ -0,0 +1,26 @@
1
+ RSpec.configure do |config|
2
+
3
+ config.before :all do |example_group|
4
+ klass = example_group.class
5
+
6
+ (klass.descendants - [klass]).each do |egc|
7
+ if egc.metadata.key?(:clean_up_test_cache)
8
+ require 'fileutils'
9
+ require 'vigilem/evdev/key_map_cache'
10
+ test_name = 'key_map_cache_test'
11
+ egc.before(:each) do
12
+ Vigilem::Evdev::KeyMapCache.default_path = nil
13
+ Vigilem::Evdev::KeyMapCache.default_filename = test_name
14
+ end
15
+ egc.after(:each) do
16
+ Vigilem::Evdev::KeyMapCache.default_path = nil
17
+ Vigilem::Evdev::KeyMapCache.default_filename = nil
18
+ pth = File.join(Bundler.root, 'data', test_name)
19
+ FileUtils.remove(pth) if File.exists?(pth)
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,30 @@
1
+ event_files = Dir["/dev/input/event*"]
2
+
3
+ if event_files.empty?
4
+ puts %q<can't find character devices in /dev/input/event*>
5
+ exit
6
+ elsif not event_files.any? {|f| File.readable?(f) }
7
+ puts "Your user account isn't allowed to read from /dev/input/event*. please rerun as sudo"
8
+ exit
9
+ end
10
+
11
+ require 'bundler'
12
+ Bundler.setup
13
+
14
+ require 'timeout'
15
+
16
+ require 'inline'
17
+
18
+ require 'vigilem/support/core_ext/debug_puts'
19
+
20
+ require 'vigilem/support/patch/ffi/pointer'
21
+
22
+ require 'after_each_example_group'
23
+
24
+ require 'delete_test_cache_after_group'
25
+
26
+ $ver = `uname -r`.split('-').first
27
+
28
+ $major = (ary = $ver.split('.')).first.to_i
29
+
30
+ $minor = ary[1].to_i
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ require 'vigilem/_evdev'
4
+
5
+ describe Vigilem::Evdev, :clean_up_test_cache do
6
+ describe '#key_map' do
7
+ it 'loads the keymap' do
8
+ expect(described_class.key_map).to be_a Vigilem::Support::KeyMap
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,114 @@
1
+ require 'vigilem/evdev/context_filter'
2
+
3
+ describe Vigilem::Evdev::ContextFilter do
4
+
5
+ class ContextFilterHost
6
+ include Vigilem::Evdev::ContextFilter
7
+ end
8
+
9
+ subject { ContextFilterHost.new }
10
+
11
+ describe '::included' do
12
+ it 'extends Forwardable' do
13
+ expect(subject.class.singleton_class.included_modules).to include(Forwardable)
14
+ end
15
+ end
16
+
17
+ describe '#last_known_state' do
18
+ it 'defaults to nil/UKNOWN' do
19
+ expect(subject.last_known_state).to be_nil
20
+ end
21
+ end
22
+
23
+ describe '#was_on?' do
24
+ it 'compares ON to #last_known_state defaulting to false' do
25
+ expect(subject.was_on?).to be_falsey
26
+ end
27
+
28
+ it 'returns true if #last_known_state == ON' do
29
+ subject.send(:last_known_state=, described_class::ON)
30
+ expect(subject.was_on?).to be_truthy
31
+ end
32
+ end
33
+
34
+ describe '#was_off?' do
35
+ it 'compares OFF to #last_known_state defaulting to true' do
36
+ expect(subject.was_off?).to be_truthy
37
+ end
38
+
39
+ it 'returns true if #last_known_state == OFF' do
40
+ subject.send(:last_known_state=, described_class::ON)
41
+ expect(subject.was_off?).to be_falsey
42
+ end
43
+ end
44
+
45
+ describe '#on?' do
46
+ it 'raises error because it needs to be overridden' do
47
+ expect { subject.on? }.to raise_error(NotImplementedError)
48
+ end
49
+ end
50
+
51
+ #alias_method :filtered?, :on?
52
+
53
+
54
+ describe '#off?' do
55
+ it 'raises error because it needs to be overridden' do
56
+ expect { subject.off? }.to raise_error(NotImplementedError)
57
+ end
58
+ end
59
+
60
+ describe '#on_change' do
61
+ it 'updates #last_known_state' do
62
+ subject.on_change(described_class::ON)
63
+ expect(subject.last_known_state).to eql(described_class::ON)
64
+ end
65
+
66
+ class FakeObserver
67
+ def update(type, value)
68
+ (@updates ||= []).concat([type, value])
69
+ end
70
+ attr_reader :updates
71
+ end
72
+
73
+ it 'notifies observers' do
74
+ fo = FakeObserver.new
75
+ subject.add_observer(fo)
76
+ subject.on_change(described_class::ON)
77
+ expect(fo.updates).to eql([subject, described_class::ON])
78
+ end
79
+ end
80
+
81
+ context 'private' do
82
+ describe '#last_known_state=' do
83
+ it 'sets #last_known_state' do
84
+ subject.send(:last_known_state=, described_class::ON)
85
+ expect(subject.last_known_state).to eql(described_class::ON)
86
+ end
87
+ end
88
+
89
+ describe '#was_on=' do
90
+ it 'sets #was_on?' do
91
+ subject.send(:was_on=, false)
92
+ expect(subject.was_on?).to be_falsey
93
+ end
94
+
95
+ it 'updates #last_known_state' do
96
+ subject.send(:was_on=, true)
97
+ expect(subject.last_known_state).to eql(described_class::ON)
98
+ end
99
+ end
100
+
101
+ describe '#was_off=' do
102
+ it 'sets #was_off?' do
103
+ subject.send(:was_off=, true)
104
+ expect(subject.was_off?).to be_truthy
105
+ end
106
+
107
+ it 'updates #last_known_state' do
108
+ subject.send(:was_off=, true)
109
+ expect(subject.last_known_state).to eql(described_class::OFF)
110
+ end
111
+ end
112
+ end
113
+
114
+ end