-
Notifications
You must be signed in to change notification settings - Fork 6
/
ScreenReader.gd
285 lines (229 loc) · 6.57 KB
/
ScreenReader.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
tool
extends Node
signal swipe_left
signal swipe_right
signal swipe_up
signal swipe_down
var Accessible = preload("Accessible.gd")
export var enabled = true setget _set_enabled, _get_enabled
export var min_swipe_distance = 5
export var tap_execute_interval = 125
export var explore_by_touch_interval = 200
export var enable_focus_mode = false
var should_stop_on_focus = true
func _set_enabled(v):
if enabled:
augment_tree(get_tree().root)
else:
for accessible in get_tree().get_nodes_in_group("accessibles"):
accessible.queue_free()
enabled = v
func _get_enabled():
return enabled
func augment_node(node):
if not enabled:
return
if node is Control:
Accessible.new(node)
func augment_tree(node):
if not enabled:
return
if node is Accessible:
return
augment_node(node)
for child in node.get_children():
augment_tree(child)
func find_focusable_control(node):
if (
node is Control
and node.is_visible_in_tree()
and (node.focus_mode == Control.FOCUS_CLICK or node.focus_mode == Control.FOCUS_ALL)
):
return node
for child in node.get_children():
var result = find_focusable_control(child)
if result:
return result
return null
func _enter_tree():
pause_mode = Node.PAUSE_MODE_PROCESS
if enabled:
augment_tree(get_tree().root)
get_tree().connect("node_added", self, "augment_node")
connect("swipe_right", self, "swipe_right")
connect("swipe_left", self, "swipe_left")
connect("swipe_up", self, "swipe_up")
connect("swipe_down", self, "swipe_down")
func _press_and_release(action, fake_via_keyboard = false):
if fake_via_keyboard:
for event in InputMap.get_action_list(action):
if event is InputEventKey:
event.pressed = true
Input.action_press(action)
get_tree().input_event(event)
event.pressed = false
Input.action_release(action)
get_tree().input_event(event)
return
var event = InputEventAction.new()
event.action = action
event.pressed = true
Input.action_press(action)
get_tree().input_event(event)
event.pressed = false
Input.action_release(action)
get_tree().input_event(event)
func _ui_left(fake_via_keyboard = false):
_press_and_release("ui_left", fake_via_keyboard)
func _ui_right(fake_via_keyboard = false):
_press_and_release("ui_right", fake_via_keyboard)
func _ui_up(fake_via_keyboard = false):
_press_and_release("ui_up", fake_via_keyboard)
func _ui_down(fake_via_keyboard = false):
_press_and_release("ui_down", fake_via_keyboard)
func _ui_focus_next(fake_via_keyboard = false):
_press_and_release("ui_focus_next", fake_via_keyboard)
func _ui_focus_prev(fake_via_keyboard = false):
_press_and_release("ui_focus_prev", fake_via_keyboard)
func swipe_right():
var fake_via_keyboard = false
if OS.get_name() == "Android":
fake_via_keyboard = true
_ui_focus_next(fake_via_keyboard)
func swipe_left():
var fake_via_keyboard = false
if OS.get_name() == "Android":
fake_via_keyboard = true
_ui_focus_prev(fake_via_keyboard)
func swipe_up():
var focus = find_focusable_control(get_tree().root)
if focus:
focus = focus.get_focus_owner()
if focus:
if focus is Range:
_press_and_release("ui_right")
func swipe_down():
var focus = find_focusable_control(get_tree().root)
if focus:
focus = focus.get_focus_owner()
if focus:
if focus is Range:
_press_and_release("ui_left")
var touch_index = null
var touch_position = null
var touch_start_time = null
var touch_stop_time = null
var explore_by_touch = false
var tap_count = 0
var focus_mode = false
var in_focus_mode_handler = false
func _input(event):
if not enabled:
return
var focus = find_focusable_control(get_tree().root)
if focus:
focus = focus.get_focus_owner()
if focus is Tree and Input.is_action_just_pressed("ui_accept"):
var accessible
for n in focus.get_children():
if n is Accessible:
accessible = n
break
if accessible and accessible.button_index != null:
accessible._tree_input(event)
get_tree().set_input_as_handled()
if enable_focus_mode:
if (
event is InputEventKey
and Input.is_key_pressed(KEY_ESCAPE)
and Input.is_key_pressed(KEY_SHIFT)
and not event.echo
):
get_tree().set_input_as_handled()
if focus_mode:
focus_mode = false
TTS.speak("UI mode", true)
return
else:
focus_mode = true
TTS.speak("Focus mode", true)
return
if focus_mode:
if (
Input.is_action_just_pressed("ui_left")
or Input.is_action_just_pressed("ui_right")
or Input.is_action_just_pressed("ui_up")
or Input.is_action_just_pressed("ui_down")
or Input.is_action_just_pressed("ui_focus_next")
or Input.is_action_just_pressed("ui_focus_prev")
):
if in_focus_mode_handler:
return
in_focus_mode_handler = true
if Input.is_action_just_pressed("ui_left"):
_ui_left()
elif Input.is_action_just_pressed("ui_right"):
_ui_right()
elif Input.is_action_just_pressed("ui_up"):
_ui_up()
elif Input.is_action_just_pressed("ui_down"):
_ui_down()
elif Input.is_action_just_pressed("ui_focus_prev"):
_ui_focus_prev()
elif Input.is_action_just_pressed("ui_focus_next"):
_ui_focus_next()
get_tree().set_input_as_handled()
in_focus_mode_handler = false
return
if event is InputEventScreenTouch:
get_tree().set_input_as_handled()
if touch_index and event.index != touch_index:
return
if event.pressed:
touch_index = event.index
touch_position = event.position
touch_start_time = OS.get_ticks_msec()
touch_stop_time = null
elif touch_position:
touch_index = null
var relative = event.position - touch_position
if relative.length() < min_swipe_distance:
tap_count += 1
elif not explore_by_touch:
if abs(relative.x) > abs(relative.y):
if relative.x > 0:
emit_signal("swipe_right")
else:
emit_signal("swipe_left")
else:
if relative.y > 0:
emit_signal("swipe_down")
else:
emit_signal("swipe_up")
touch_position = null
touch_start_time = null
touch_stop_time = OS.get_ticks_msec()
explore_by_touch = false
elif event is InputEventScreenDrag:
if touch_index and event.index != touch_index:
return
if (
not explore_by_touch
and OS.get_ticks_msec() - touch_start_time >= explore_by_touch_interval
):
explore_by_touch = true
if event is InputEventMouseButton:
if event.device == -1 and not explore_by_touch:
get_tree().set_input_as_handled()
func _process(delta):
if not enabled:
return
if (
touch_stop_time
and OS.get_ticks_msec() - touch_stop_time >= tap_execute_interval
and tap_count != 0
):
touch_stop_time = null
if tap_count == 2:
_press_and_release("ui_accept")
tap_count = 0