accessibility_core 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/.yardopts +9 -0
- data/History.markdown +36 -0
- data/README.markdown +66 -0
- data/Rakefile +72 -0
- data/ext/accessibility/bridge/ext/accessibility/bridge/bridge.c +490 -0
- data/ext/accessibility/bridge/ext/accessibility/bridge/extconf.rb +22 -0
- data/ext/accessibility/bridge/lib/accessibility/bridge.rb +33 -0
- data/ext/accessibility/bridge/lib/accessibility/bridge/common.rb +57 -0
- data/ext/accessibility/bridge/lib/accessibility/bridge/macruby.rb +185 -0
- data/ext/accessibility/bridge/lib/accessibility/bridge/mri.rb +121 -0
- data/ext/accessibility/bridge/lib/accessibility/bridge/version.rb +6 -0
- data/ext/accessibility/bridge/test/array_test.rb +31 -0
- data/ext/accessibility/bridge/test/boxed_test.rb +23 -0
- data/ext/accessibility/bridge/test/cfrange_test.rb +21 -0
- data/ext/accessibility/bridge/test/cgpoint_test.rb +54 -0
- data/ext/accessibility/bridge/test/cgrect_test.rb +60 -0
- data/ext/accessibility/bridge/test/cgsize_test.rb +54 -0
- data/ext/accessibility/bridge/test/helper.rb +19 -0
- data/ext/accessibility/bridge/test/nsstring_test.rb +22 -0
- data/ext/accessibility/bridge/test/nsurl_test.rb +17 -0
- data/ext/accessibility/bridge/test/object_test.rb +19 -0
- data/ext/accessibility/bridge/test/range_test.rb +16 -0
- data/ext/accessibility/bridge/test/string_test.rb +35 -0
- data/ext/accessibility/bridge/test/uri_test.rb +15 -0
- data/ext/accessibility/core/bridge.h +1 -0
- data/ext/accessibility/core/core.c +705 -0
- data/ext/accessibility/core/extconf.rb +22 -0
- data/ext/accessibility/highlighter/extconf.rb +22 -0
- data/ext/accessibility/highlighter/highlighter.c +7 -0
- data/lib/accessibility/core.rb +12 -0
- data/lib/accessibility/core/core_ext/common.rb +57 -0
- data/lib/accessibility/core/core_ext/macruby.rb +140 -0
- data/lib/accessibility/core/core_ext/mri.rb +121 -0
- data/lib/accessibility/core/macruby.rb +858 -0
- data/lib/accessibility/core/version.rb +6 -0
- data/test/helper.rb +48 -0
- metadata +158 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
if on_macruby?
|
4
|
+
|
5
|
+
##
|
6
|
+
# Boxed is the common ancestor of all structs defined by bridge support
|
7
|
+
# in MacRuby.
|
8
|
+
class BoxedTest < MiniTest::Unit::TestCase
|
9
|
+
|
10
|
+
def test_to_ax_raises_for_arbitrary_boxes
|
11
|
+
assert_raises(NotImplementedError) { NSEdgeInsets.new.to_ax }
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_to_ruby # bet you would never dare to abuse the parser like this!
|
15
|
+
assert_equal CGPointZero, CGPointZero .to_ax.to_ruby
|
16
|
+
assert_equal CGSize.new(10,10), CGSize.new(10, 10) .to_ax.to_ruby
|
17
|
+
assert_equal CGRectMake(1,2,3,4), CGRectMake(1,2,3,4).to_ax.to_ruby
|
18
|
+
assert_equal 1..10, CFRange.new(1, 10) .to_ax.to_ruby
|
19
|
+
assert_equal Range.new(1,10), CFRange.new(1,10) .to_ax.to_ruby
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
if on_macruby?
|
4
|
+
class CFRangeTest < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_to_ax
|
7
|
+
range = CFRange.new(5, 4)
|
8
|
+
value = range.to_ax
|
9
|
+
ptr = Pointer.new CFRange.type
|
10
|
+
AXValueGetValue(value, 4, ptr)
|
11
|
+
assert_equal range, ptr.value, 'range makes a value'
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_cf_range_to_ruby_range_compatability
|
15
|
+
assert_equal CFRangeMake(1,10).to_ax, (1..10 ).to_ax
|
16
|
+
assert_equal CFRangeMake(1, 9).to_ax, (1...10 ).to_ax
|
17
|
+
assert_equal CFRangeMake(0, 3).to_ax, (0..2 ).to_ax
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class CGPointTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_attributes
|
6
|
+
p = CGPoint.new
|
7
|
+
assert_respond_to p, :x
|
8
|
+
assert_respond_to p, :y
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_to_a
|
12
|
+
p = CGPoint.new 1, 2
|
13
|
+
assert_equal [1, 2], p.to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_to_point
|
17
|
+
p = CGPoint.new
|
18
|
+
assert_same p, p.to_point
|
19
|
+
|
20
|
+
p = CGPoint.new 4, 2
|
21
|
+
assert_same p, p.to_point
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_initialize
|
25
|
+
p = CGPoint.new
|
26
|
+
assert_equal 0, p.x
|
27
|
+
assert_equal 0, p.y
|
28
|
+
|
29
|
+
x, y = rand_nums 2
|
30
|
+
p = CGPoint.new x, y
|
31
|
+
assert_equal x, p.x
|
32
|
+
assert_equal y, p.y
|
33
|
+
|
34
|
+
x, y = rand_floats 2
|
35
|
+
p = CGPoint.new x, y
|
36
|
+
assert_equal x, p.x
|
37
|
+
assert_equal y, p.y
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_inspect
|
41
|
+
assert_match /Point x=1.0 y=2.0>/, CGPoint.new(1, 2).inspect
|
42
|
+
assert_match /Point x=3.0 y=5.0>/, CGPoint.new(3, 5).inspect
|
43
|
+
end
|
44
|
+
|
45
|
+
if on_macruby?
|
46
|
+
def test_to_ax
|
47
|
+
value = CGPointZero.to_ax
|
48
|
+
ptr = Pointer.new CGPoint.type
|
49
|
+
AXValueGetValue(value, 1, ptr)
|
50
|
+
assert_equal CGPointZero, ptr.value, 'point makes a value'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class CGRectTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_attributes
|
6
|
+
r = CGRect.new
|
7
|
+
assert_respond_to r, :origin
|
8
|
+
assert_respond_to r, :size
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_to_a # we want to match MacRuby here
|
12
|
+
r = CGRect.new
|
13
|
+
assert_equal [CGPoint.new, CGSize.new], r.to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_to_rect
|
17
|
+
r = CGRect.new
|
18
|
+
assert_same r, r.to_rect
|
19
|
+
|
20
|
+
r = CGRect.new CGPoint.new(4, 2), CGSize.new(8, 3)
|
21
|
+
assert_same r, r.to_rect
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_initialize
|
25
|
+
r = CGRect.new
|
26
|
+
assert_equal 0, r.origin.x
|
27
|
+
assert_equal 0, r.origin.y
|
28
|
+
assert_equal 0, r.size.width
|
29
|
+
assert_equal 0, r.size.height
|
30
|
+
|
31
|
+
x, y, w, h = rand_nums 4
|
32
|
+
p = CGPoint.new x, y
|
33
|
+
s = CGSize.new w, h
|
34
|
+
r = CGRect.new p, s
|
35
|
+
assert_equal p, r.origin
|
36
|
+
assert_equal s, r.size
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_inspect
|
40
|
+
p1 = CGPoint.new *rand_nums(2)
|
41
|
+
p2 = CGPoint.new *rand_nums(2)
|
42
|
+
s1 = CGSize.new *rand_nums(2)
|
43
|
+
s2 = CGSize.new *rand_nums(2)
|
44
|
+
r1 = CGRect.new p1, s1
|
45
|
+
r2 = CGRect.new p2, s2
|
46
|
+
assert_match /Rect origin=#{p1.inspect} size=#{s1.inspect}>/, r1.inspect
|
47
|
+
assert_match /Rect origin=#{p2.inspect} size=#{s2.inspect}>/, r2.inspect
|
48
|
+
end
|
49
|
+
|
50
|
+
if on_macruby?
|
51
|
+
def test_to_ax
|
52
|
+
value = CGRectZero.to_ax
|
53
|
+
ptr = Pointer.new CGRect.type
|
54
|
+
AXValueGetValue(value, 3, ptr)
|
55
|
+
assert_equal CGRectZero, ptr.value, 'rect makes a value'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class CGSizeTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_attributes
|
6
|
+
s = CGSize.new
|
7
|
+
assert_respond_to s, :width
|
8
|
+
assert_respond_to s, :height
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_to_a
|
12
|
+
s = CGSize.new 1, 2
|
13
|
+
assert_equal [1, 2], s.to_a
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_to_size
|
17
|
+
s = CGSize.new
|
18
|
+
assert_same s, s.to_size
|
19
|
+
|
20
|
+
s = CGSize.new 4, 2
|
21
|
+
assert_same s, s.to_size
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_initialize
|
25
|
+
s = CGSize.new
|
26
|
+
assert_equal 0, s.width
|
27
|
+
assert_equal 0, s.height
|
28
|
+
|
29
|
+
w, h = rand_nums 2
|
30
|
+
s = CGSize.new w, h
|
31
|
+
assert_equal w, s.width
|
32
|
+
assert_equal h, s.height
|
33
|
+
|
34
|
+
w, h = rand_floats 2
|
35
|
+
s = CGSize.new w, h
|
36
|
+
assert_equal w, s.width
|
37
|
+
assert_equal h, s.height
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_inspect
|
41
|
+
assert_match /Size width=1.0 height=2.0>/, CGSize.new(1, 2).inspect
|
42
|
+
assert_match /Size width=3.0 height=5.0>/, CGSize.new(3, 5).inspect
|
43
|
+
end
|
44
|
+
|
45
|
+
if on_macruby?
|
46
|
+
def test_to_ax
|
47
|
+
value = CGSizeZero.to_ax
|
48
|
+
ptr = Pointer.new CGSize.type
|
49
|
+
AXValueGetValue(value, 2, ptr)
|
50
|
+
assert_equal CGSizeZero, ptr.value, 'size makes a value'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/pride'
|
3
|
+
require 'accessibility/bridge'
|
4
|
+
|
5
|
+
class MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
def rand_nums count, range = 1_000
|
8
|
+
Array.new count do
|
9
|
+
rand range
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def rand_floats count, range = 1_000.0
|
14
|
+
Array.new count do
|
15
|
+
rand * range
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
if on_macruby?
|
4
|
+
class NSStringTest < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_to_url
|
7
|
+
site = 'http://marketcircle.com/'
|
8
|
+
url = site.to_url
|
9
|
+
refute_nil url
|
10
|
+
assert_equal NSURL.URLWithString(site), url
|
11
|
+
|
12
|
+
file = 'file://localhost/Applications/Calculator.app/'
|
13
|
+
url = file.to_url
|
14
|
+
refute_nil url
|
15
|
+
assert_equal NSURL.fileURLWithPath('/Applications/Calculator.app/'), url
|
16
|
+
|
17
|
+
void = 'not a url at all'
|
18
|
+
assert_nil void.to_url
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
if on_macruby?
|
4
|
+
class TestNSURL < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_to_url_returns_self
|
7
|
+
url = NSURL.URLWithString 'http://macruby.org'
|
8
|
+
assert_same url, url.to_url
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_to_s
|
12
|
+
s = 'http://marketcircle.com'
|
13
|
+
assert_equal s, NSURL.URLWithString(s).to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class ObjectTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
if on_macruby?
|
6
|
+
def test_to_ruby
|
7
|
+
assert_same Object, Object.to_ruby
|
8
|
+
assert_same 10, 10.to_ruby
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_to_ax
|
12
|
+
assert_same Object, Object.to_ax
|
13
|
+
assert_same 10, 10.to_ax
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# we may have other tests for extensions to the Object class
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
if on_macruby?
|
4
|
+
class RangeTest < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_to_ax
|
7
|
+
assert_equal CFRange.new(5, 4).to_ax, (5..8).to_ax
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_to_ax_raises_when_given_negative_indicies
|
11
|
+
assert_raises(ArgumentError) { (1..-10).to_ax }
|
12
|
+
assert_raises(ArgumentError) { (-5...10).to_ax }
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
class StringTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
if on_macruby?
|
6
|
+
def test_to_url
|
7
|
+
site = 'http://marketcircle.com/'
|
8
|
+
url = site.to_url
|
9
|
+
refute_nil url
|
10
|
+
assert_equal NSURL.URLWithString(site), url
|
11
|
+
|
12
|
+
file = 'file://localhost/Applications/Calculator.app/'
|
13
|
+
url = file.to_url
|
14
|
+
refute_nil url
|
15
|
+
assert_equal NSURL.fileURLWithPath('/Applications/Calculator.app/'), url
|
16
|
+
|
17
|
+
assert_nil 'not a url at all'.to_url
|
18
|
+
end
|
19
|
+
|
20
|
+
else
|
21
|
+
|
22
|
+
def test_to_url
|
23
|
+
site = 'http://marketcircle.com/'
|
24
|
+
url = site.to_url
|
25
|
+
refute_nil url
|
26
|
+
assert_equal URI.parse(site), url
|
27
|
+
|
28
|
+
# Ruby's URI class does not handle the file scheme :(
|
29
|
+
# @todo propose the change upstream at some point?
|
30
|
+
|
31
|
+
assert_raises(URI::InvalidURIError) { 'not a url at all'.to_url }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test/helper'
|
2
|
+
|
3
|
+
unless on_macruby?
|
4
|
+
class TestURIExtensions < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def test_to_url_returns_self
|
7
|
+
url = URI.parse 'http://macruby.org'
|
8
|
+
assert_same url, url.to_url
|
9
|
+
|
10
|
+
url = URI.parse 'ftp://herp.com'
|
11
|
+
assert_same url, url.to_url
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
#include "../bridge/ext/accessibility/bridge/bridge.c"
|
@@ -0,0 +1,705 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
|
3
|
+
#ifdef NOT_MACRUBY /* This entire extension is pointless when running on MacRuby */
|
4
|
+
|
5
|
+
#import <Cocoa/Cocoa.h>
|
6
|
+
#include "bridge.h"
|
7
|
+
|
8
|
+
|
9
|
+
static ID ivar_attrs;
|
10
|
+
static ID ivar_param_attrs;
|
11
|
+
static ID ivar_actions;
|
12
|
+
static ID ivar_pid;
|
13
|
+
static ID ivar_key_rate;
|
14
|
+
|
15
|
+
static ID sel_to_f;
|
16
|
+
|
17
|
+
static ID rate_very_slow;
|
18
|
+
static ID rate_slow;
|
19
|
+
static ID rate_normal;
|
20
|
+
static ID rate_default;
|
21
|
+
static ID rate_fast;
|
22
|
+
static ID rate_zomg;
|
23
|
+
|
24
|
+
|
25
|
+
static
|
26
|
+
VALUE
|
27
|
+
handle_error(VALUE self, AXError code)
|
28
|
+
{
|
29
|
+
// TODO port the error handler from AXElements
|
30
|
+
switch (code)
|
31
|
+
{
|
32
|
+
case kAXErrorInvalidUIElement:
|
33
|
+
rb_raise(rb_eArgError, "invalid element (probably dead)");
|
34
|
+
case kAXErrorAttributeUnsupported:
|
35
|
+
rb_raise(rb_eArgError, "attribute unsupported");
|
36
|
+
case kAXErrorActionUnsupported:
|
37
|
+
rb_raise(rb_eArgError, "action unsupported");
|
38
|
+
case kAXErrorParameterizedAttributeUnsupported:
|
39
|
+
rb_raise(rb_eArgError, "parameterized attribute unsupported");
|
40
|
+
default:
|
41
|
+
rb_raise(rb_eRuntimeError, "you done goofed [%d]", code);
|
42
|
+
}
|
43
|
+
|
44
|
+
return Qnil;
|
45
|
+
}
|
46
|
+
|
47
|
+
|
48
|
+
static
|
49
|
+
VALUE
|
50
|
+
rb_acore_application_for(VALUE self, VALUE pid)
|
51
|
+
{
|
52
|
+
NSDate* date = [NSDate date];
|
53
|
+
[[NSRunLoop currentRunLoop] runUntilDate:date];
|
54
|
+
CFRelease(date);
|
55
|
+
|
56
|
+
pid_t the_pid = NUM2PIDT(pid);
|
57
|
+
NSRunningApplication* running_app =
|
58
|
+
[NSRunningApplication runningApplicationWithProcessIdentifier:the_pid];
|
59
|
+
|
60
|
+
if (running_app) {
|
61
|
+
VALUE app = wrap_ref(AXUIElementCreateApplication(the_pid));
|
62
|
+
CFRelease(running_app);
|
63
|
+
return app;
|
64
|
+
}
|
65
|
+
|
66
|
+
rb_raise(
|
67
|
+
rb_eArgError,
|
68
|
+
"pid `%d' must belong to a running application",
|
69
|
+
the_pid
|
70
|
+
);
|
71
|
+
|
72
|
+
return Qnil; // unreachable
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
static
|
77
|
+
VALUE
|
78
|
+
rb_acore_system_wide(VALUE self)
|
79
|
+
{
|
80
|
+
return wrap_ref(AXUIElementCreateSystemWide());
|
81
|
+
}
|
82
|
+
|
83
|
+
|
84
|
+
static
|
85
|
+
VALUE
|
86
|
+
rb_acore_key_rate(VALUE self)
|
87
|
+
{
|
88
|
+
return rb_ivar_get(self, ivar_key_rate);
|
89
|
+
}
|
90
|
+
|
91
|
+
|
92
|
+
static
|
93
|
+
VALUE
|
94
|
+
rb_acore_set_key_rate(VALUE self, VALUE rate)
|
95
|
+
{
|
96
|
+
if (TYPE(rate) == T_SYMBOL) {
|
97
|
+
ID key_rate = SYM2ID(rate);
|
98
|
+
if (key_rate == rate_very_slow)
|
99
|
+
rate = DBL2NUM(0.9);
|
100
|
+
else if (key_rate == rate_slow)
|
101
|
+
rate = DBL2NUM(0.09);
|
102
|
+
else if (key_rate == rate_normal || rate == rate_default)
|
103
|
+
rate = DBL2NUM(0.009);
|
104
|
+
else if (key_rate == rate_fast)
|
105
|
+
rate = DBL2NUM(0.0009);
|
106
|
+
else if (key_rate == rate_zomg)
|
107
|
+
rate = DBL2NUM(0.00009);
|
108
|
+
else
|
109
|
+
rb_raise(rb_eArgError, "Unknown rate `%s'", rb_id2name(key_rate));
|
110
|
+
}
|
111
|
+
else {
|
112
|
+
rate = rb_funcall(rate, sel_to_f, 0);
|
113
|
+
}
|
114
|
+
|
115
|
+
return rb_ivar_set(self, ivar_key_rate, rate);
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
static
|
120
|
+
int
|
121
|
+
acore_is_system_wide(VALUE other)
|
122
|
+
{
|
123
|
+
AXUIElementRef system = AXUIElementCreateSystemWide();
|
124
|
+
int result = CFEqual(unwrap_ref(other), system);
|
125
|
+
CFRelease(system);
|
126
|
+
return result;
|
127
|
+
}
|
128
|
+
#define IS_SYSTEM_WIDE(x) (acore_is_system_wide(x))
|
129
|
+
|
130
|
+
|
131
|
+
static
|
132
|
+
VALUE
|
133
|
+
rb_acore_attributes(VALUE self)
|
134
|
+
{
|
135
|
+
VALUE cached_attrs = rb_ivar_get(self, ivar_attrs);
|
136
|
+
if (cached_attrs != Qnil)
|
137
|
+
return cached_attrs;
|
138
|
+
|
139
|
+
CFArrayRef attrs = NULL;
|
140
|
+
AXError code = AXUIElementCopyAttributeNames(unwrap_ref(self), &attrs);
|
141
|
+
switch (code)
|
142
|
+
{
|
143
|
+
case kAXErrorSuccess:
|
144
|
+
cached_attrs = wrap_array_strings(attrs);
|
145
|
+
rb_ivar_set(self, ivar_attrs, cached_attrs);
|
146
|
+
CFRelease(attrs);
|
147
|
+
return cached_attrs;
|
148
|
+
case kAXErrorInvalidUIElement:
|
149
|
+
return rb_ary_new();
|
150
|
+
default:
|
151
|
+
// TODO we should actually allow for a grace period and try again in
|
152
|
+
// every case where would be deferring to the default error handler,
|
153
|
+
// and maybe even in every case where we get a non-zero result code
|
154
|
+
//
|
155
|
+
// WE SHOULD HANDLE THINGS LIKE FAILURE AND CANNOT COMPLETE LIKE THIS
|
156
|
+
return handle_error(self, code);
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
|
161
|
+
static
|
162
|
+
VALUE
|
163
|
+
rb_acore_attribute(VALUE self, VALUE name)
|
164
|
+
{
|
165
|
+
CFTypeRef attr = NULL;
|
166
|
+
CFStringRef attr_name = unwrap_string(name);
|
167
|
+
AXError code = AXUIElementCopyAttributeValue(
|
168
|
+
unwrap_ref(self),
|
169
|
+
attr_name,
|
170
|
+
&attr
|
171
|
+
);
|
172
|
+
CFRelease(attr_name);
|
173
|
+
switch (code)
|
174
|
+
{
|
175
|
+
case kAXErrorSuccess:
|
176
|
+
return to_ruby(attr);
|
177
|
+
case kAXErrorFailure:
|
178
|
+
case kAXErrorNoValue:
|
179
|
+
case kAXErrorInvalidUIElement:
|
180
|
+
case kAXErrorAttributeUnsupported:
|
181
|
+
return Qnil;
|
182
|
+
default:
|
183
|
+
return handle_error(self, code);
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
|
188
|
+
static
|
189
|
+
VALUE
|
190
|
+
rb_acore_size_of(VALUE self, VALUE name)
|
191
|
+
{
|
192
|
+
CFIndex size = 0;
|
193
|
+
CFStringRef attr_name = unwrap_string(name);
|
194
|
+
AXError code = AXUIElementGetAttributeValueCount(
|
195
|
+
unwrap_ref(self),
|
196
|
+
attr_name,
|
197
|
+
&size
|
198
|
+
);
|
199
|
+
CFRelease(attr_name);
|
200
|
+
switch (code)
|
201
|
+
{
|
202
|
+
case kAXErrorSuccess:
|
203
|
+
return INT2FIX(size);
|
204
|
+
case kAXErrorFailure:
|
205
|
+
case kAXErrorNoValue:
|
206
|
+
case kAXErrorInvalidUIElement:
|
207
|
+
return INT2FIX(0);
|
208
|
+
default:
|
209
|
+
return handle_error(self, code);
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
|
214
|
+
static
|
215
|
+
VALUE
|
216
|
+
rb_acore_is_writable(VALUE self, VALUE name)
|
217
|
+
{
|
218
|
+
Boolean result;
|
219
|
+
CFStringRef attr_name = unwrap_string(name);
|
220
|
+
AXError code = AXUIElementIsAttributeSettable(
|
221
|
+
unwrap_ref(self),
|
222
|
+
attr_name,
|
223
|
+
&result
|
224
|
+
);
|
225
|
+
CFRelease(attr_name);
|
226
|
+
switch (code)
|
227
|
+
{
|
228
|
+
case kAXErrorSuccess:
|
229
|
+
return (result ? Qtrue : Qfalse);
|
230
|
+
case kAXErrorFailure:
|
231
|
+
case kAXErrorNoValue:
|
232
|
+
case kAXErrorInvalidUIElement:
|
233
|
+
return Qfalse;
|
234
|
+
default:
|
235
|
+
return handle_error(self, code);
|
236
|
+
}
|
237
|
+
}
|
238
|
+
|
239
|
+
|
240
|
+
static
|
241
|
+
VALUE
|
242
|
+
rb_acore_set(VALUE self, VALUE name, VALUE value)
|
243
|
+
{
|
244
|
+
CFTypeRef ax_value = to_ax(value);
|
245
|
+
CFStringRef attr_name = unwrap_string(name);
|
246
|
+
AXError code = AXUIElementSetAttributeValue(
|
247
|
+
unwrap_ref(self),
|
248
|
+
attr_name,
|
249
|
+
ax_value
|
250
|
+
);
|
251
|
+
switch (code)
|
252
|
+
{
|
253
|
+
case kAXErrorSuccess:
|
254
|
+
return value;
|
255
|
+
default:
|
256
|
+
return handle_error(self, code); // name, value
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
|
261
|
+
static
|
262
|
+
VALUE
|
263
|
+
rb_acore_role(VALUE self)
|
264
|
+
{
|
265
|
+
CFTypeRef value = NULL;
|
266
|
+
AXError code = AXUIElementCopyAttributeValue(
|
267
|
+
unwrap_ref(self),
|
268
|
+
kAXRoleAttribute,
|
269
|
+
&value
|
270
|
+
);
|
271
|
+
switch (code)
|
272
|
+
{
|
273
|
+
case kAXErrorSuccess:
|
274
|
+
return wrap_string(value);
|
275
|
+
case kAXErrorNoValue:
|
276
|
+
case kAXErrorInvalidUIElement:
|
277
|
+
return Qnil;
|
278
|
+
default:
|
279
|
+
return handle_error(self, code);
|
280
|
+
}
|
281
|
+
}
|
282
|
+
|
283
|
+
|
284
|
+
static
|
285
|
+
VALUE
|
286
|
+
rb_acore_subrole(VALUE self)
|
287
|
+
{
|
288
|
+
CFTypeRef value = NULL;
|
289
|
+
AXError code = AXUIElementCopyAttributeValue(
|
290
|
+
unwrap_ref(self),
|
291
|
+
kAXSubroleAttribute,
|
292
|
+
&value
|
293
|
+
);
|
294
|
+
switch (code)
|
295
|
+
{
|
296
|
+
case kAXErrorSuccess:
|
297
|
+
return wrap_string((CFStringRef)value);
|
298
|
+
case kAXErrorFailure:
|
299
|
+
case kAXErrorNoValue:
|
300
|
+
case kAXErrorInvalidUIElement:
|
301
|
+
case kAXErrorAttributeUnsupported:
|
302
|
+
return Qnil;
|
303
|
+
default:
|
304
|
+
return handle_error(self, code);
|
305
|
+
}
|
306
|
+
}
|
307
|
+
|
308
|
+
|
309
|
+
static
|
310
|
+
VALUE
|
311
|
+
rb_acore_parent(VALUE self)
|
312
|
+
{
|
313
|
+
CFTypeRef value = NULL;
|
314
|
+
AXError code = AXUIElementCopyAttributeValue(
|
315
|
+
unwrap_ref(self),
|
316
|
+
kAXParentAttribute,
|
317
|
+
&value
|
318
|
+
);
|
319
|
+
switch (code)
|
320
|
+
{
|
321
|
+
case kAXErrorSuccess:
|
322
|
+
return wrap_ref(value);
|
323
|
+
case kAXErrorFailure:
|
324
|
+
case kAXErrorNoValue:
|
325
|
+
case kAXErrorInvalidUIElement:
|
326
|
+
case kAXErrorAttributeUnsupported:
|
327
|
+
return Qnil;
|
328
|
+
default:
|
329
|
+
return handle_error(self, code);
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
|
334
|
+
static
|
335
|
+
VALUE
|
336
|
+
rb_acore_children(VALUE self)
|
337
|
+
{
|
338
|
+
CFTypeRef value = NULL;
|
339
|
+
AXError code = AXUIElementCopyAttributeValue(
|
340
|
+
unwrap_ref(self),
|
341
|
+
kAXChildrenAttribute,
|
342
|
+
&value
|
343
|
+
);
|
344
|
+
switch (code)
|
345
|
+
{
|
346
|
+
case kAXErrorSuccess:
|
347
|
+
return wrap_array_refs(value);
|
348
|
+
case kAXErrorNoValue:
|
349
|
+
case kAXErrorInvalidUIElement:
|
350
|
+
return rb_ary_new();
|
351
|
+
default:
|
352
|
+
return handle_error(self, code);
|
353
|
+
}
|
354
|
+
}
|
355
|
+
|
356
|
+
|
357
|
+
static
|
358
|
+
VALUE
|
359
|
+
rb_acore_value(VALUE self)
|
360
|
+
{
|
361
|
+
CFTypeRef value = NULL;
|
362
|
+
AXError code = AXUIElementCopyAttributeValue(
|
363
|
+
unwrap_ref(self),
|
364
|
+
kAXValueAttribute,
|
365
|
+
&value
|
366
|
+
);
|
367
|
+
switch (code)
|
368
|
+
{
|
369
|
+
case kAXErrorSuccess:
|
370
|
+
return to_ruby(value);
|
371
|
+
default:
|
372
|
+
return handle_error(self, code);
|
373
|
+
}
|
374
|
+
}
|
375
|
+
|
376
|
+
|
377
|
+
static
|
378
|
+
VALUE
|
379
|
+
rb_acore_pid(VALUE self)
|
380
|
+
{
|
381
|
+
VALUE cached_pid = rb_ivar_get(self, ivar_pid);
|
382
|
+
if (cached_pid != Qnil)
|
383
|
+
return cached_pid;
|
384
|
+
|
385
|
+
pid_t pid = 0;
|
386
|
+
AXError code = AXUIElementGetPid(unwrap_ref(self), &pid);
|
387
|
+
|
388
|
+
switch (code)
|
389
|
+
{
|
390
|
+
case kAXErrorSuccess:
|
391
|
+
break;
|
392
|
+
case kAXErrorInvalidUIElement:
|
393
|
+
if (IS_SYSTEM_WIDE(self)) {
|
394
|
+
pid = 0;
|
395
|
+
break;
|
396
|
+
}
|
397
|
+
default:
|
398
|
+
handle_error(self, code);
|
399
|
+
}
|
400
|
+
|
401
|
+
cached_pid = PIDT2NUM(pid);
|
402
|
+
rb_ivar_set(self, ivar_pid, cached_pid);
|
403
|
+
return cached_pid;
|
404
|
+
}
|
405
|
+
|
406
|
+
|
407
|
+
static
|
408
|
+
VALUE
|
409
|
+
rb_acore_parameterized_attributes(VALUE self)
|
410
|
+
{
|
411
|
+
VALUE cached_attrs = rb_ivar_get(self, ivar_param_attrs);
|
412
|
+
if (cached_attrs != Qnil)
|
413
|
+
return cached_attrs;
|
414
|
+
|
415
|
+
CFArrayRef attrs = NULL;
|
416
|
+
AXError code = AXUIElementCopyParameterizedAttributeNames(
|
417
|
+
unwrap_ref(self),
|
418
|
+
&attrs
|
419
|
+
);
|
420
|
+
switch (code)
|
421
|
+
{
|
422
|
+
case kAXErrorSuccess:
|
423
|
+
cached_attrs = wrap_array_strings(attrs);
|
424
|
+
rb_ivar_set(self, ivar_param_attrs, cached_attrs);
|
425
|
+
CFRelease(attrs);
|
426
|
+
return cached_attrs;
|
427
|
+
case kAXErrorInvalidUIElement:
|
428
|
+
return rb_ary_new();
|
429
|
+
default:
|
430
|
+
return handle_error(self, code);
|
431
|
+
}
|
432
|
+
}
|
433
|
+
|
434
|
+
|
435
|
+
static
|
436
|
+
VALUE
|
437
|
+
rb_acore_parameterized_attribute(VALUE self, VALUE name, VALUE parameter)
|
438
|
+
{
|
439
|
+
CFTypeRef param = to_ax(parameter);
|
440
|
+
CFTypeRef attr = NULL;
|
441
|
+
CFStringRef attr_name = unwrap_string(name);
|
442
|
+
AXError code = AXUIElementCopyParameterizedAttributeValue(
|
443
|
+
unwrap_ref(self),
|
444
|
+
attr_name,
|
445
|
+
param,
|
446
|
+
&attr
|
447
|
+
);
|
448
|
+
CFRelease(param);
|
449
|
+
CFRelease(attr_name);
|
450
|
+
switch (code)
|
451
|
+
{
|
452
|
+
case kAXErrorSuccess:
|
453
|
+
return to_ruby(attr);
|
454
|
+
case kAXErrorNoValue:
|
455
|
+
case kAXErrorInvalidUIElement:
|
456
|
+
return Qnil;
|
457
|
+
default:
|
458
|
+
return handle_error(self, code);
|
459
|
+
}
|
460
|
+
}
|
461
|
+
|
462
|
+
|
463
|
+
static
|
464
|
+
VALUE
|
465
|
+
rb_acore_actions(VALUE self)
|
466
|
+
{
|
467
|
+
VALUE cached_actions = rb_ivar_get(self, ivar_actions);
|
468
|
+
if (cached_actions != Qnil)
|
469
|
+
return cached_actions;
|
470
|
+
|
471
|
+
CFArrayRef actions = NULL;
|
472
|
+
AXError code = AXUIElementCopyActionNames(unwrap_ref(self), &actions);
|
473
|
+
switch (code)
|
474
|
+
{
|
475
|
+
case kAXErrorSuccess:
|
476
|
+
cached_actions = wrap_array_strings(actions);
|
477
|
+
rb_ivar_set(self, ivar_actions, cached_actions);
|
478
|
+
CFRelease(actions);
|
479
|
+
return cached_actions;
|
480
|
+
case kAXErrorInvalidUIElement:
|
481
|
+
return rb_ary_new();
|
482
|
+
default:
|
483
|
+
return handle_error(self, code);
|
484
|
+
}
|
485
|
+
}
|
486
|
+
|
487
|
+
|
488
|
+
static
|
489
|
+
VALUE
|
490
|
+
rb_acore_perform(VALUE self, VALUE name)
|
491
|
+
{
|
492
|
+
CFStringRef action = unwrap_string(name);
|
493
|
+
AXError code = AXUIElementPerformAction(unwrap_ref(self), action);
|
494
|
+
|
495
|
+
CFRelease(action);
|
496
|
+
switch (code)
|
497
|
+
{
|
498
|
+
case kAXErrorSuccess:
|
499
|
+
return Qtrue;
|
500
|
+
case kAXErrorInvalidUIElement:
|
501
|
+
return Qfalse;
|
502
|
+
default:
|
503
|
+
return handle_error(self, code);
|
504
|
+
}
|
505
|
+
}
|
506
|
+
|
507
|
+
|
508
|
+
static
|
509
|
+
VALUE
|
510
|
+
rb_acore_post(VALUE self, VALUE events)
|
511
|
+
{
|
512
|
+
events = rb_ary_to_ary(events);
|
513
|
+
long length = RARRAY_LEN(events);
|
514
|
+
useconds_t sleep_time = NUM2DBL(rb_ivar_get(rb_cElement, ivar_key_rate)) * 100000;
|
515
|
+
|
516
|
+
// CGCharCode key_char = 0; // TODO this value seems to not matter?
|
517
|
+
VALUE pair;
|
518
|
+
CGKeyCode virtual_key;
|
519
|
+
int key_state;
|
520
|
+
AXError code;
|
521
|
+
|
522
|
+
|
523
|
+
for (long i = 0; i < length; i++) {
|
524
|
+
pair = rb_ary_entry(events, i);
|
525
|
+
virtual_key = NUM2INT(rb_ary_entry(pair, 0));
|
526
|
+
key_state = rb_ary_entry(pair, 1) == Qtrue ? true : false;
|
527
|
+
code = AXUIElementPostKeyboardEvent(
|
528
|
+
unwrap_ref(self),
|
529
|
+
0,
|
530
|
+
virtual_key,
|
531
|
+
key_state
|
532
|
+
);
|
533
|
+
switch (code)
|
534
|
+
{
|
535
|
+
case kAXErrorSuccess:
|
536
|
+
break;
|
537
|
+
default:
|
538
|
+
handle_error(self, code);
|
539
|
+
}
|
540
|
+
|
541
|
+
usleep(sleep_time);
|
542
|
+
}
|
543
|
+
|
544
|
+
return self;
|
545
|
+
}
|
546
|
+
|
547
|
+
|
548
|
+
static
|
549
|
+
VALUE
|
550
|
+
rb_acore_is_invalid(VALUE self)
|
551
|
+
{
|
552
|
+
CFTypeRef value = NULL;
|
553
|
+
AXError code = AXUIElementCopyAttributeValue(
|
554
|
+
unwrap_ref(self),
|
555
|
+
kAXRoleAttribute,
|
556
|
+
&value
|
557
|
+
);
|
558
|
+
if (value)
|
559
|
+
CFRelease(value);
|
560
|
+
return (code == kAXErrorInvalidUIElement ? Qtrue : Qfalse);
|
561
|
+
}
|
562
|
+
|
563
|
+
|
564
|
+
static
|
565
|
+
VALUE
|
566
|
+
rb_acore_application(VALUE self)
|
567
|
+
{
|
568
|
+
return rb_acore_application_for(rb_cElement, rb_acore_pid(self));
|
569
|
+
}
|
570
|
+
|
571
|
+
|
572
|
+
static
|
573
|
+
VALUE
|
574
|
+
rb_acore_set_timeout_to(VALUE self, VALUE seconds)
|
575
|
+
{
|
576
|
+
float timeout = NUM2DBL(seconds);
|
577
|
+
AXError code = AXUIElementSetMessagingTimeout(unwrap_ref(self), timeout);
|
578
|
+
|
579
|
+
switch (code)
|
580
|
+
{
|
581
|
+
case kAXErrorSuccess:
|
582
|
+
return seconds;
|
583
|
+
default:
|
584
|
+
return handle_error(self, code); // seconds
|
585
|
+
}
|
586
|
+
}
|
587
|
+
|
588
|
+
|
589
|
+
static
|
590
|
+
VALUE
|
591
|
+
rb_acore_element_at(VALUE self, VALUE point)
|
592
|
+
{
|
593
|
+
if (self == rb_cElement)
|
594
|
+
self = rb_acore_system_wide(self);
|
595
|
+
|
596
|
+
AXUIElementRef ref = NULL;
|
597
|
+
CGPoint p = unwrap_point(point);
|
598
|
+
AXError code = AXUIElementCopyElementAtPosition(
|
599
|
+
unwrap_ref(self),
|
600
|
+
p.x,
|
601
|
+
p.y,
|
602
|
+
&ref
|
603
|
+
);
|
604
|
+
switch (code)
|
605
|
+
{
|
606
|
+
case kAXErrorSuccess:
|
607
|
+
return wrap_ref(ref);
|
608
|
+
case kAXErrorNoValue:
|
609
|
+
return Qnil;
|
610
|
+
case kAXErrorInvalidUIElement:
|
611
|
+
if (!IS_SYSTEM_WIDE(self))
|
612
|
+
return rb_acore_element_at(rb_acore_system_wide(rb_cElement), point);
|
613
|
+
else
|
614
|
+
return Qnil;
|
615
|
+
default:
|
616
|
+
return handle_error(self, code); // point, nil, nil
|
617
|
+
}
|
618
|
+
}
|
619
|
+
|
620
|
+
|
621
|
+
static
|
622
|
+
VALUE
|
623
|
+
rb_acore_equality(VALUE self, VALUE other)
|
624
|
+
{
|
625
|
+
if (CLASS_OF(other) == rb_cElement)
|
626
|
+
if (CFEqual(unwrap_ref(self), unwrap_ref(other)))
|
627
|
+
return Qtrue;
|
628
|
+
return Qfalse;
|
629
|
+
}
|
630
|
+
#endif
|
631
|
+
|
632
|
+
|
633
|
+
void
|
634
|
+
Init_core()
|
635
|
+
{
|
636
|
+
#ifdef NOT_MACRUBY
|
637
|
+
if (!AXAPIEnabled())
|
638
|
+
rb_raise(
|
639
|
+
rb_eRuntimeError,
|
640
|
+
"\n" \
|
641
|
+
"------------------------------------------------------------------------\n" \
|
642
|
+
"Universal Access is disabled on this machine.\n" \
|
643
|
+
"Please enable it in the System Preferences.\n" \
|
644
|
+
"See https://github.com/Marketcircle/AXElements#getting-setup\n" \
|
645
|
+
"------------------------------------------------------------------------\n"
|
646
|
+
);
|
647
|
+
|
648
|
+
Init_bridge();
|
649
|
+
|
650
|
+
// these should be defined by now
|
651
|
+
rb_mAccessibility = rb_const_get(rb_cObject, rb_intern("Accessibility"));
|
652
|
+
rb_cElement = rb_define_class_under(rb_mAccessibility, "Element", rb_cObject);
|
653
|
+
|
654
|
+
ivar_attrs = rb_intern("@attrs");
|
655
|
+
ivar_param_attrs = rb_intern("@param_attrs");
|
656
|
+
ivar_actions = rb_intern("@actions");
|
657
|
+
ivar_pid = rb_intern("@pid");
|
658
|
+
ivar_key_rate = rb_intern("@key_rate");
|
659
|
+
|
660
|
+
rb_define_singleton_method(rb_cElement, "application_for", rb_acore_application_for, 1);
|
661
|
+
rb_define_singleton_method(rb_cElement, "system_wide", rb_acore_system_wide, 0);
|
662
|
+
rb_define_singleton_method(rb_cElement, "element_at", rb_acore_element_at, 1);
|
663
|
+
rb_define_singleton_method(rb_cElement, "key_rate", rb_acore_key_rate, 0);
|
664
|
+
rb_define_singleton_method(rb_cElement, "key_rate=", rb_acore_set_key_rate, 1);
|
665
|
+
|
666
|
+
sel_to_f = rb_intern("to_f");
|
667
|
+
rate_very_slow = rb_intern("very_slow");
|
668
|
+
rate_slow = rb_intern("slow");
|
669
|
+
rate_normal = rb_intern("normal");
|
670
|
+
rate_default = rb_intern("default");
|
671
|
+
rate_fast = rb_intern("fast");
|
672
|
+
rate_zomg = rb_intern("zomg");
|
673
|
+
rb_acore_set_key_rate(rb_cElement, DBL2NUM(0.009)); // initialize the value right now
|
674
|
+
|
675
|
+
rb_define_method(rb_cElement, "attributes", rb_acore_attributes, 0);
|
676
|
+
rb_define_method(rb_cElement, "attribute", rb_acore_attribute, 1);
|
677
|
+
rb_define_method(rb_cElement, "size_of", rb_acore_size_of, 1);
|
678
|
+
rb_define_method(rb_cElement, "writable?", rb_acore_is_writable, 1);
|
679
|
+
rb_define_method(rb_cElement, "set", rb_acore_set, 2);
|
680
|
+
|
681
|
+
rb_define_method(rb_cElement, "role", rb_acore_role, 0);
|
682
|
+
rb_define_method(rb_cElement, "subrole", rb_acore_subrole, 0);
|
683
|
+
rb_define_method(rb_cElement, "parent", rb_acore_parent, 0);
|
684
|
+
rb_define_method(rb_cElement, "children", rb_acore_children, 0);
|
685
|
+
rb_define_method(rb_cElement, "value", rb_acore_value, 0);
|
686
|
+
rb_define_method(rb_cElement, "pid", rb_acore_pid, 0);
|
687
|
+
|
688
|
+
rb_define_method(rb_cElement, "parameterized_attributes", rb_acore_parameterized_attributes, 0);
|
689
|
+
rb_define_method(rb_cElement, "parameterized_attribute", rb_acore_parameterized_attribute, 2);
|
690
|
+
|
691
|
+
rb_define_method(rb_cElement, "actions", rb_acore_actions, 0);
|
692
|
+
rb_define_method(rb_cElement, "perform", rb_acore_perform, 1);
|
693
|
+
rb_define_method(rb_cElement, "post", rb_acore_post, 1);
|
694
|
+
|
695
|
+
rb_define_method(rb_cElement, "invalid?", rb_acore_is_invalid, 0);
|
696
|
+
rb_define_method(rb_cElement, "set_timeout_to", rb_acore_set_timeout_to, 1);
|
697
|
+
// TODO make this meaningful, currently has no effect on calling rb_acore_post
|
698
|
+
rb_define_method(rb_cElement, "key_rate", rb_acore_key_rate, 0);
|
699
|
+
rb_define_method(rb_cElement, "key_rate=", rb_acore_set_key_rate, 1);
|
700
|
+
rb_define_method(rb_cElement, "application", rb_acore_application, 0);
|
701
|
+
rb_define_method(rb_cElement, "element_at", rb_acore_element_at, 1);
|
702
|
+
rb_define_method(rb_cElement, "==", rb_acore_equality, 1);
|
703
|
+
|
704
|
+
#endif
|
705
|
+
}
|