AXElements 1.0.0.beta4 → 6.0.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.
- checksums.yaml +7 -0
- data/History.markdown +7 -0
- data/README.markdown +41 -29
- data/Rakefile +1 -6
- data/lib/accessibility/dsl.rb +17 -15
- data/lib/accessibility/pretty_printer.rb +40 -12
- data/lib/accessibility/system_info.rb +2 -0
- data/lib/accessibility/text_highlighter.rb +73 -0
- data/lib/accessibility/translator.rb +1 -0
- data/lib/accessibility/version.rb +1 -1
- data/lib/accessibility.rb +13 -114
- data/lib/ax/application.rb +54 -42
- data/lib/ax/element.rb +27 -7
- data/lib/ax/scroll_area.rb +1 -0
- data/lib/ax/systemwide.rb +5 -4
- data/lib/ax/text_area.rb +16 -0
- data/lib/ax/text_field.rb +10 -0
- data/lib/ax_elements/mri.rb +36 -1
- data/rakelib/ci.rake +9 -0
- data/rakelib/doc.rake +4 -13
- data/rakelib/ext.rake +1 -57
- data/rakelib/gem.rake +7 -23
- data/rakelib/test.rake +10 -17
- data/test/helper.rb +15 -18
- data/test/integration/accessibility/test_dsl.rb +9 -3
- data/test/integration/ax/test_application.rb +1 -1
- data/test/integration/ax/test_text_area.rb +62 -0
- data/test/integration/ax/test_text_field.rb +49 -0
- data/test/sanity/accessibility/test_dsl.rb +1 -0
- data/test/sanity/accessibility/test_errors.rb +1 -1
- data/test/sanity/accessibility/test_pretty_printer.rb +6 -1
- data/test/sanity/accessibility/test_qualifier.rb +1 -1
- data/test/sanity/accessibility/test_system_info.rb +109 -0
- data/test/sanity/accessibility/test_translator.rb +1 -1
- data/test/sanity/accessibility/test_version.rb +2 -2
- data/test/sanity/ax_elements/test_nsarray_compat.rb +1 -1
- data/test/sanity/ax_elements/test_nsobject_inspect.rb +1 -1
- data/test/sanity/test_ax_elements.rb +1 -1
- metadata +34 -59
- data/ext/accessibility/key_coder/extconf.rb +0 -22
- data/ext/accessibility/key_coder/key_coder.c +0 -123
- data/lib/accessibility/string.rb +0 -502
- data/test/sanity/accessibility/test_string.rb +0 -238
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test/integration/helper'
|
2
|
+
|
3
|
+
class TestAXTextField < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def search_field
|
6
|
+
@field ||= app.main_window.search_field
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup
|
10
|
+
search_field.value = 'The cake is a lie!'
|
11
|
+
end
|
12
|
+
|
13
|
+
def teardown
|
14
|
+
search_field.value = ''
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# @group Tests
|
19
|
+
|
20
|
+
def test_highlight_text_regexp
|
21
|
+
[
|
22
|
+
/cake/,
|
23
|
+
/The/,
|
24
|
+
/e!/,
|
25
|
+
/a/
|
26
|
+
].each do |expected|
|
27
|
+
search_field.highlight_text expected
|
28
|
+
actual = search_field.selected_text
|
29
|
+
expected = search_field.value
|
30
|
+
assert_equal expected, actual, expected
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_highlight_text_string
|
35
|
+
expected = 'is a'
|
36
|
+
search_field.highlight_text expected
|
37
|
+
actual = search_field.selected_text
|
38
|
+
assert_equal expected, actual
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_highlight_text_range
|
42
|
+
range = 5..10
|
43
|
+
expected = search_field.value[range]
|
44
|
+
search_field.highlight_text range
|
45
|
+
actual = search_field.selected_text
|
46
|
+
assert_equal expected, actual
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -66,6 +66,8 @@ class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def test_position
|
69
|
+
@attributes = [:position]
|
70
|
+
|
69
71
|
@attribute = CGPoint.new
|
70
72
|
assert_match /\(0\.0, 0\.0\)/, pp_position
|
71
73
|
|
@@ -75,11 +77,14 @@ class TestAccessibilityPrettyPrinter < MiniTest::Unit::TestCase
|
|
75
77
|
|
76
78
|
# this sometimes happens, even though it shouldn't
|
77
79
|
def test_position_is_nil
|
78
|
-
@
|
80
|
+
@attributes = [:position]
|
81
|
+
@attribute = nil
|
79
82
|
assert_equal EMPTY_STRING, pp_position
|
80
83
|
end
|
81
84
|
|
82
85
|
def test_children_pluralizes_properly
|
86
|
+
@attributes = [:children]
|
87
|
+
|
83
88
|
[[2, /2 children/ ],
|
84
89
|
[9001, /9001 children/],
|
85
90
|
[3.14, /3.14 children/],
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
require 'accessibility/system_info'
|
3
|
+
|
4
|
+
class TestAcessibilitySystemInfo < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_name
|
7
|
+
name = Accessibility::SystemInfo.name
|
8
|
+
assert_kind_of String, name
|
9
|
+
refute_empty name
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_hostnames
|
13
|
+
names = Accessibility::SystemInfo.hostnames
|
14
|
+
assert_kind_of Array, names
|
15
|
+
assert_kind_of String, names.first
|
16
|
+
names.each { |name| refute_empty name }
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_hostname
|
20
|
+
name = Accessibility::SystemInfo.hostname
|
21
|
+
assert_kind_of String, name
|
22
|
+
refute_empty name
|
23
|
+
assert_includes Accessibility::SystemInfo.hostnames, name
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_addresses
|
27
|
+
addresses = Accessibility::SystemInfo.addresses
|
28
|
+
assert_kind_of Array, addresses
|
29
|
+
assert_kind_of String, addresses.first
|
30
|
+
addresses.each { |addr| refute_empty addr }
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_ipv4_addresses
|
34
|
+
addresses = Accessibility::SystemInfo.ipv4_addresses
|
35
|
+
assert_kind_of Array, addresses
|
36
|
+
assert_kind_of String, addresses.first, "Do you have IPv4 disabled?"
|
37
|
+
home = addresses.find { |addr| addr.match(/127.0.0.1/) }
|
38
|
+
refute_nil home
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_ipv6_addresses
|
42
|
+
addresses = Accessibility::SystemInfo.ipv6_addresses
|
43
|
+
assert_kind_of Array, addresses
|
44
|
+
assert_kind_of String, addresses.first, "Do you have IPv6 disabled?"
|
45
|
+
home = addresses.find { |addr| addr.match(/::1/) }
|
46
|
+
refute_nil home
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_model
|
50
|
+
model = Accessibility::SystemInfo.model
|
51
|
+
assert_kind_of String, model
|
52
|
+
refute_empty model
|
53
|
+
# this assuming that all Macs have Mac in the model name
|
54
|
+
assert_match /Mac/, model
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_osx_version
|
58
|
+
version = Accessibility::SystemInfo.osx_version
|
59
|
+
assert_kind_of String, version
|
60
|
+
refute_empty version
|
61
|
+
assert_match /^Version 10\.\d+\.\d+ \(Build [\dA-Z]+\)$/, version
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_uptime
|
65
|
+
time = Accessibility::SystemInfo.uptime
|
66
|
+
assert_kind_of Float, time
|
67
|
+
assert time > 0.0
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_num_processors
|
71
|
+
procs = Accessibility::SystemInfo.num_processors
|
72
|
+
assert_kind_of Fixnum, procs
|
73
|
+
assert procs > 0
|
74
|
+
assert_equal Accessibility::SystemInfo.number_of_processors, procs
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_num_active_processors
|
78
|
+
procs = Accessibility::SystemInfo.num_active_processors
|
79
|
+
assert_kind_of Fixnum, procs
|
80
|
+
assert procs > 0
|
81
|
+
assert_equal Accessibility::SystemInfo.number_of_active_processors, procs
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_total_ram
|
85
|
+
ram = Accessibility::SystemInfo.total_ram
|
86
|
+
assert_kind_of Fixnum, ram
|
87
|
+
assert ram > 2.gigabytes # everyone has more than 2GB of RAM these days...right?
|
88
|
+
assert_equal Accessibility::SystemInfo.ram, ram
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_battery_state
|
92
|
+
state = Accessibility::SystemInfo.battery_state
|
93
|
+
assert_kind_of Symbol, state
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_battery_charge_level
|
97
|
+
level = Accessibility::SystemInfo.battery_level
|
98
|
+
assert_kind_of Float, level
|
99
|
+
assert level <= 1.0 && level >= -1.0
|
100
|
+
assert_equal Accessibility::SystemInfo.battery_charge_level, level
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_battery_life_estimate
|
104
|
+
est = Accessibility::SystemInfo.battery_life_estimate
|
105
|
+
assert_kind_of Fixnum, est
|
106
|
+
assert est >= -1
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'test/
|
1
|
+
require 'test/helper'
|
2
2
|
require 'accessibility/version'
|
3
3
|
|
4
4
|
class TestAccessibilityVersion < MiniTest::Unit::TestCase
|
@@ -9,7 +9,7 @@ class TestAccessibilityVersion < MiniTest::Unit::TestCase
|
|
9
9
|
|
10
10
|
def test_version_method
|
11
11
|
assert_match Accessibility::VERSION, Accessibility.version
|
12
|
-
assert_match Accessibility::
|
12
|
+
assert_match Accessibility::CODE_NAME, Accessibility.version
|
13
13
|
end
|
14
14
|
|
15
15
|
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: AXElements
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease: 6
|
4
|
+
version: 6.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Mark Rada
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-11-26 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: mouse
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: screen_recorder
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: accessibility_core
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ~>
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,70 +48,46 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ~>
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 0.4.1
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
56
|
+
name: accessibility_keyboard
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ~>
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
61
|
+
version: 1.0.0
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ~>
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: 3.2.11
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
|
-
name: yard
|
80
|
-
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
|
-
requirements:
|
83
|
-
- - ~>
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
version: 0.8.3
|
86
|
-
type: :development
|
87
|
-
prerelease: false
|
88
|
-
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
65
|
requirements:
|
91
66
|
- - ~>
|
92
67
|
- !ruby/object:Gem::Version
|
93
|
-
version: 0.
|
68
|
+
version: 1.0.0
|
94
69
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
70
|
+
name: activesupport
|
96
71
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
72
|
requirements:
|
99
73
|
- - ~>
|
100
74
|
- !ruby/object:Gem::Version
|
101
|
-
version: 0.
|
102
|
-
type: :
|
75
|
+
version: 4.0.1
|
76
|
+
type: :runtime
|
103
77
|
prerelease: false
|
104
78
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
79
|
requirements:
|
107
80
|
- - ~>
|
108
81
|
- !ruby/object:Gem::Version
|
109
|
-
version: 0.
|
110
|
-
description:
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
'
|
82
|
+
version: 4.0.1
|
83
|
+
description: |
|
84
|
+
AXElements is a UI automation library built on top of various OS X
|
85
|
+
frameworks. You can use AXElements to write functional tests for
|
86
|
+
Cocoa apps, script UI interactions, or even to build higher level
|
87
|
+
tools such as screen readers.
|
117
88
|
email: mrada@marketcircle.com
|
118
89
|
executables: []
|
119
|
-
extensions:
|
120
|
-
- ext/accessibility/key_coder/extconf.rb
|
90
|
+
extensions: []
|
121
91
|
extra_rdoc_files: []
|
122
92
|
files:
|
123
93
|
- lib/accessibility/dsl.rb
|
@@ -127,8 +97,8 @@ files:
|
|
127
97
|
- lib/accessibility/graph.rb
|
128
98
|
- lib/accessibility/pretty_printer.rb
|
129
99
|
- lib/accessibility/qualifier.rb
|
130
|
-
- lib/accessibility/string.rb
|
131
100
|
- lib/accessibility/system_info.rb
|
101
|
+
- lib/accessibility/text_highlighter.rb
|
132
102
|
- lib/accessibility/translator.rb
|
133
103
|
- lib/accessibility/version.rb
|
134
104
|
- lib/accessibility.rb
|
@@ -142,6 +112,8 @@ files:
|
|
142
112
|
- lib/ax/scroll_area.rb
|
143
113
|
- lib/ax/static_text.rb
|
144
114
|
- lib/ax/systemwide.rb
|
115
|
+
- lib/ax/text_area.rb
|
116
|
+
- lib/ax/text_field.rb
|
145
117
|
- lib/ax_elements/active_support_selections.rb
|
146
118
|
- lib/ax_elements/awesome_print.rb
|
147
119
|
- lib/ax_elements/exception_workaround.rb
|
@@ -149,8 +121,7 @@ files:
|
|
149
121
|
- lib/ax_elements/nsarray_compat.rb
|
150
122
|
- lib/ax_elements.rb
|
151
123
|
- lib/AXElements.rb
|
152
|
-
-
|
153
|
-
- ext/accessibility/key_coder/key_coder.c
|
124
|
+
- rakelib/ci.rake
|
154
125
|
- rakelib/doc.rake
|
155
126
|
- rakelib/ext.rake
|
156
127
|
- rakelib/gem.rake
|
@@ -168,13 +139,15 @@ files:
|
|
168
139
|
- test/integration/ax/test_element.rb
|
169
140
|
- test/integration/ax/test_menu.rb
|
170
141
|
- test/integration/ax/test_row.rb
|
142
|
+
- test/integration/ax/test_text_area.rb
|
143
|
+
- test/integration/ax/test_text_field.rb
|
171
144
|
- test/integration/ax_elements/test_nsarray_compat.rb
|
172
145
|
- test/sanity/accessibility/test_dsl.rb
|
173
146
|
- test/sanity/accessibility/test_errors.rb
|
174
147
|
- test/sanity/accessibility/test_factory.rb
|
175
148
|
- test/sanity/accessibility/test_pretty_printer.rb
|
176
149
|
- test/sanity/accessibility/test_qualifier.rb
|
177
|
-
- test/sanity/accessibility/
|
150
|
+
- test/sanity/accessibility/test_system_info.rb
|
178
151
|
- test/sanity/accessibility/test_translator.rb
|
179
152
|
- test/sanity/accessibility/test_version.rb
|
180
153
|
- test/sanity/ax/test_application.rb
|
@@ -185,31 +158,30 @@ files:
|
|
185
158
|
- test/sanity/test_accessibility.rb
|
186
159
|
- test/sanity/test_ax_elements.rb
|
187
160
|
- test/helper.rb
|
188
|
-
homepage: http://
|
161
|
+
homepage: http://axelements.com
|
189
162
|
licenses:
|
190
163
|
- BSD 3-clause
|
164
|
+
metadata: {}
|
191
165
|
post_install_message:
|
192
166
|
rdoc_options: []
|
193
167
|
require_paths:
|
194
168
|
- lib
|
195
169
|
required_ruby_version: !ruby/object:Gem::Requirement
|
196
|
-
none: false
|
197
170
|
requirements:
|
198
|
-
- -
|
171
|
+
- - '>='
|
199
172
|
- !ruby/object:Gem::Version
|
200
173
|
version: '0'
|
201
174
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
|
-
none: false
|
203
175
|
requirements:
|
204
|
-
- -
|
176
|
+
- - '>='
|
205
177
|
- !ruby/object:Gem::Version
|
206
|
-
version:
|
178
|
+
version: '0'
|
207
179
|
requirements: []
|
208
180
|
rubyforge_project:
|
209
|
-
rubygems_version: 1.
|
181
|
+
rubygems_version: 2.1.11
|
210
182
|
signing_key:
|
211
|
-
specification_version:
|
212
|
-
summary:
|
183
|
+
specification_version: 4
|
184
|
+
summary: UI Automation for OS X
|
213
185
|
test_files:
|
214
186
|
- test/integration/accessibility/test_dsl.rb
|
215
187
|
- test/integration/accessibility/test_enumerators.rb
|
@@ -220,13 +192,15 @@ test_files:
|
|
220
192
|
- test/integration/ax/test_element.rb
|
221
193
|
- test/integration/ax/test_menu.rb
|
222
194
|
- test/integration/ax/test_row.rb
|
195
|
+
- test/integration/ax/test_text_area.rb
|
196
|
+
- test/integration/ax/test_text_field.rb
|
223
197
|
- test/integration/ax_elements/test_nsarray_compat.rb
|
224
198
|
- test/sanity/accessibility/test_dsl.rb
|
225
199
|
- test/sanity/accessibility/test_errors.rb
|
226
200
|
- test/sanity/accessibility/test_factory.rb
|
227
201
|
- test/sanity/accessibility/test_pretty_printer.rb
|
228
202
|
- test/sanity/accessibility/test_qualifier.rb
|
229
|
-
- test/sanity/accessibility/
|
203
|
+
- test/sanity/accessibility/test_system_info.rb
|
230
204
|
- test/sanity/accessibility/test_translator.rb
|
231
205
|
- test/sanity/accessibility/test_version.rb
|
232
206
|
- test/sanity/ax/test_application.rb
|
@@ -237,3 +211,4 @@ test_files:
|
|
237
211
|
- test/sanity/test_accessibility.rb
|
238
212
|
- test/sanity/test_ax_elements.rb
|
239
213
|
- test/helper.rb
|
214
|
+
has_rdoc: yard
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require 'mkmf'
|
2
|
-
|
3
|
-
$CFLAGS << ' -std=c99 -Wall -Werror -ObjC'
|
4
|
-
$LIBS << ' -framework Cocoa -framework Carbon -framework ApplicationServices'
|
5
|
-
|
6
|
-
if RUBY_ENGINE == 'macruby'
|
7
|
-
$CFLAGS << ' -fobjc-gc'
|
8
|
-
else
|
9
|
-
unless RbConfig::CONFIG["CC"].match /clang/
|
10
|
-
clang = `which clang`.chomp
|
11
|
-
if clang.empty?
|
12
|
-
$stdout.puts "Clang not installed. Cannot build C extension"
|
13
|
-
raise "Clang not installed. Cannot build C extension"
|
14
|
-
else
|
15
|
-
RbConfig::MAKEFILE_CONFIG["CC"] = clang
|
16
|
-
RbConfig::MAKEFILE_CONFIG["CXX"] = clang
|
17
|
-
end
|
18
|
-
end
|
19
|
-
$CFLAGS << ' -DNOT_MACRUBY'
|
20
|
-
end
|
21
|
-
|
22
|
-
create_makefile('accessibility/key_coder')
|
@@ -1,123 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* key_coder.c
|
3
|
-
* KeyCoder
|
4
|
-
*
|
5
|
-
* Created by Mark Rada on 11-07-27.
|
6
|
-
* Copyright 2011-2012 Marketcircle Incorporated. All rights reserved.
|
7
|
-
*/
|
8
|
-
|
9
|
-
|
10
|
-
#import <Cocoa/Cocoa.h>
|
11
|
-
#import <Carbon/Carbon.h>
|
12
|
-
#import <ApplicationServices/ApplicationServices.h>
|
13
|
-
|
14
|
-
#include "ruby.h"
|
15
|
-
|
16
|
-
|
17
|
-
/*
|
18
|
-
* Generate the mapping of characters to key codes for keys that can be
|
19
|
-
* remapped based on keyboard layout. Changing the keyboard layout at
|
20
|
-
* runtime will cause the returned hash to be different.
|
21
|
-
*
|
22
|
-
* @example
|
23
|
-
*
|
24
|
-
* KeyCoder.dynamic_mapping => { "a" => 0, "b" => 24, ... }
|
25
|
-
*
|
26
|
-
* @return [Hash{String=>Number}]
|
27
|
-
*/
|
28
|
-
|
29
|
-
static
|
30
|
-
VALUE
|
31
|
-
keycoder_dynamic_mapping()
|
32
|
-
{
|
33
|
-
|
34
|
-
VALUE map = rb_hash_new();
|
35
|
-
|
36
|
-
#ifdef NOT_MACRUBY
|
37
|
-
@autoreleasepool {
|
38
|
-
#endif
|
39
|
-
|
40
|
-
TISInputSourceRef keyboard = TISCopyCurrentKeyboardLayoutInputSource();
|
41
|
-
CFDataRef layout_data = (CFDataRef)TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
|
42
|
-
const UCKeyboardLayout* layout = (const UCKeyboardLayout*)CFDataGetBytePtr(layout_data);
|
43
|
-
|
44
|
-
void (^key_coder)(int) = ^(int key_code) {
|
45
|
-
UniChar string[255];
|
46
|
-
UniCharCount string_length = 0;
|
47
|
-
UInt32 dead_key_state = 0;
|
48
|
-
UCKeyTranslate(
|
49
|
-
layout,
|
50
|
-
key_code,
|
51
|
-
kUCKeyActionDown,
|
52
|
-
0,
|
53
|
-
LMGetKbdType(), // kb type
|
54
|
-
0, // OptionBits keyTranslateOptions,
|
55
|
-
&dead_key_state,
|
56
|
-
255,
|
57
|
-
&string_length,
|
58
|
-
string
|
59
|
-
);
|
60
|
-
|
61
|
-
NSString* nsstring = [NSString stringWithCharacters:string length:string_length];
|
62
|
-
rb_hash_aset(map, rb_str_new_cstr([nsstring UTF8String]), INT2FIX(key_code));
|
63
|
-
};
|
64
|
-
|
65
|
-
// skip 65-92 since they are hard coded and do not change
|
66
|
-
for (int key_code = 0; key_code < 65; key_code++)
|
67
|
-
key_coder(key_code);
|
68
|
-
for (int key_code = 93; key_code < 127; key_code++)
|
69
|
-
key_coder(key_code);
|
70
|
-
|
71
|
-
#ifdef NOT_MACRUBY
|
72
|
-
CFRelease(keyboard);
|
73
|
-
}; // Close the autorelease pool
|
74
|
-
#else
|
75
|
-
CFMakeCollectable(keyboard);
|
76
|
-
#endif
|
77
|
-
|
78
|
-
return map;
|
79
|
-
}
|
80
|
-
|
81
|
-
|
82
|
-
/*
|
83
|
-
* Post the given event to the system and return `true`. This method
|
84
|
-
* will also add a small (9000 microsecond) delay after posting to
|
85
|
-
* ensure that keyboard actions do not go too fast.
|
86
|
-
*
|
87
|
-
* @example
|
88
|
-
*
|
89
|
-
* KeyCoder.post_event [0, true] -> true
|
90
|
-
*
|
91
|
-
* @param [Array(Number, Boolean)]
|
92
|
-
* @return [true]
|
93
|
-
*/
|
94
|
-
|
95
|
-
static
|
96
|
-
VALUE
|
97
|
-
keycoder_post_event(VALUE self, VALUE event)
|
98
|
-
{
|
99
|
-
VALUE code = rb_ary_entry(event, 0);
|
100
|
-
VALUE state = rb_ary_entry(event, 1);
|
101
|
-
|
102
|
-
CGEventRef event_ref = CGEventCreateKeyboardEvent(NULL, FIX2LONG(code), state);
|
103
|
-
CGEventPost(kCGHIDEventTap, event_ref);
|
104
|
-
|
105
|
-
usleep(9000); // 9000 is a magic number
|
106
|
-
return Qtrue;
|
107
|
-
}
|
108
|
-
|
109
|
-
|
110
|
-
void
|
111
|
-
Init_key_coder()
|
112
|
-
{
|
113
|
-
/*
|
114
|
-
* Document-class: KeyCoder
|
115
|
-
*
|
116
|
-
* Class that encapsulates some low level work for finding key code mappings
|
117
|
-
* and posting keyboard events to the system.
|
118
|
-
*
|
119
|
-
*/
|
120
|
-
VALUE cKeyCoder = rb_define_class("KeyCoder", rb_cObject);
|
121
|
-
rb_define_singleton_method(cKeyCoder, "dynamic_mapping", keycoder_dynamic_mapping, 0);
|
122
|
-
rb_define_singleton_method(cKeyCoder, "post_event", keycoder_post_event, 1);
|
123
|
-
}
|