key_test.go raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 package router
4
5 import (
6 "reflect"
7 "testing"
8
9 "github.com/p9c/p9/pkg/gel/gio/io/event"
10 "github.com/p9c/p9/pkg/gel/gio/io/key"
11 "github.com/p9c/p9/pkg/gel/gio/op"
12 )
13
14 func TestKeyWakeup(t *testing.T) {
15 handler := new(int)
16 var ops op.Ops
17 key.InputOp{Tag: handler}.Add(&ops)
18
19 var r Router
20 // Test that merely adding a handler doesn't trigger redraw.
21 r.Frame(&ops)
22 if _, wake := r.WakeupTime(); wake {
23 t.Errorf("adding key.InputOp triggered a redraw")
24 }
25 // However, adding a handler queues a Focus(false) event.
26 if evts := r.Events(handler); len(evts) != 1 {
27 t.Errorf("no Focus event for newly registered key.InputOp")
28 }
29 // Verify that r.Events does trigger a redraw.
30 r.Frame(&ops)
31 if _, wake := r.WakeupTime(); !wake {
32 t.Errorf("key.FocusEvent event didn't trigger a redraw")
33 }
34 }
35
36 func TestKeyMultiples(t *testing.T) {
37 handlers := make([]int, 3)
38 ops := new(op.Ops)
39 r := new(Router)
40
41 key.SoftKeyboardOp{Show: true}.Add(ops)
42 key.InputOp{Tag: &handlers[0]}.Add(ops)
43 key.FocusOp{Tag: &handlers[2]}.Add(ops)
44 key.InputOp{Tag: &handlers[1]}.Add(ops)
45
46 // The last one must be focused:
47 key.InputOp{Tag: &handlers[2]}.Add(ops)
48
49 r.Frame(ops)
50
51 assertKeyEvent(t, r.Events(&handlers[0]), false)
52 assertKeyEvent(t, r.Events(&handlers[1]), false)
53 assertKeyEvent(t, r.Events(&handlers[2]), true)
54 assertFocus(t, r, &handlers[2])
55 assertKeyboard(t, r, TextInputOpen)
56 }
57
58 func TestKeyStacked(t *testing.T) {
59 handlers := make([]int, 4)
60 ops := new(op.Ops)
61 r := new(Router)
62
63 s := op.Save(ops)
64 key.InputOp{Tag: &handlers[0]}.Add(ops)
65 key.FocusOp{Tag: nil}.Add(ops)
66 s.Load()
67 s = op.Save(ops)
68 key.SoftKeyboardOp{Show: false}.Add(ops)
69 key.InputOp{Tag: &handlers[1]}.Add(ops)
70 key.FocusOp{Tag: &handlers[1]}.Add(ops)
71 s.Load()
72 s = op.Save(ops)
73 key.InputOp{Tag: &handlers[2]}.Add(ops)
74 key.SoftKeyboardOp{Show: true}.Add(ops)
75 s.Load()
76 s = op.Save(ops)
77 key.InputOp{Tag: &handlers[3]}.Add(ops)
78 s.Load()
79
80 r.Frame(ops)
81
82 assertKeyEvent(t, r.Events(&handlers[0]), false)
83 assertKeyEvent(t, r.Events(&handlers[1]), true)
84 assertKeyEvent(t, r.Events(&handlers[2]), false)
85 assertKeyEvent(t, r.Events(&handlers[3]), false)
86 assertFocus(t, r, &handlers[1])
87 assertKeyboard(t, r, TextInputOpen)
88 }
89
90 func TestKeySoftKeyboardNoFocus(t *testing.T) {
91 ops := new(op.Ops)
92 r := new(Router)
93
94 // It's possible to open the keyboard
95 // without any active focus:
96 key.SoftKeyboardOp{Show: true}.Add(ops)
97
98 r.Frame(ops)
99
100 assertFocus(t, r, nil)
101 assertKeyboard(t, r, TextInputOpen)
102 }
103
104 func TestKeyRemoveFocus(t *testing.T) {
105 handlers := make([]int, 2)
106 ops := new(op.Ops)
107 r := new(Router)
108
109 // New InputOp with Focus and Keyboard:
110 s := op.Save(ops)
111 key.InputOp{Tag: &handlers[0]}.Add(ops)
112 key.FocusOp{Tag: &handlers[0]}.Add(ops)
113 key.SoftKeyboardOp{Show: true}.Add(ops)
114 s.Load()
115
116 // New InputOp without any focus:
117 s = op.Save(ops)
118 key.InputOp{Tag: &handlers[1]}.Add(ops)
119 s.Load()
120
121 r.Frame(ops)
122
123 // Add some key events:
124 event := event.Event(key.Event{Name: key.NameTab, Modifiers: key.ModShortcut, State: key.Press})
125 r.Queue(event)
126
127 assertKeyEvent(t, r.Events(&handlers[0]), true, event)
128 assertKeyEvent(t, r.Events(&handlers[1]), false)
129 assertFocus(t, r, &handlers[0])
130 assertKeyboard(t, r, TextInputOpen)
131
132 ops.Reset()
133
134 // Will get the focus removed:
135 s = op.Save(ops)
136 key.InputOp{Tag: &handlers[0]}.Add(ops)
137 s.Load()
138
139 // Unchanged:
140 s = op.Save(ops)
141 key.InputOp{Tag: &handlers[1]}.Add(ops)
142 s.Load()
143
144 // Remove focus by focusing on a tag that don't exist.
145 s = op.Save(ops)
146 key.FocusOp{Tag: new(int)}.Add(ops)
147 s.Load()
148
149 r.Frame(ops)
150
151 assertKeyEventUnexpected(t, r.Events(&handlers[1]))
152 assertFocus(t, r, nil)
153 assertKeyboard(t, r, TextInputClose)
154
155 ops.Reset()
156
157 s = op.Save(ops)
158 key.InputOp{Tag: &handlers[0]}.Add(ops)
159 s.Load()
160
161 s = op.Save(ops)
162 key.InputOp{Tag: &handlers[1]}.Add(ops)
163 s.Load()
164
165 r.Frame(ops)
166
167 assertKeyEventUnexpected(t, r.Events(&handlers[0]))
168 assertKeyEventUnexpected(t, r.Events(&handlers[1]))
169 assertFocus(t, r, nil)
170 assertKeyboard(t, r, TextInputKeep)
171
172 ops.Reset()
173
174 // Set focus to InputOp which already
175 // exists in the previous frame:
176 s = op.Save(ops)
177 key.FocusOp{Tag: &handlers[0]}.Add(ops)
178 key.InputOp{Tag: &handlers[0]}.Add(ops)
179 key.SoftKeyboardOp{Show: true}.Add(ops)
180 s.Load()
181
182 // Remove focus.
183 s = op.Save(ops)
184 key.InputOp{Tag: &handlers[1]}.Add(ops)
185 key.FocusOp{Tag: nil}.Add(ops)
186 s.Load()
187
188 r.Frame(ops)
189
190 assertKeyEventUnexpected(t, r.Events(&handlers[1]))
191 assertFocus(t, r, nil)
192 assertKeyboard(t, r, TextInputOpen)
193 }
194
195 func TestKeyFocusedInvisible(t *testing.T) {
196 handlers := make([]int, 2)
197 ops := new(op.Ops)
198 r := new(Router)
199
200 // Set new InputOp with focus:
201 s := op.Save(ops)
202 key.FocusOp{Tag: &handlers[0]}.Add(ops)
203 key.InputOp{Tag: &handlers[0]}.Add(ops)
204 key.SoftKeyboardOp{Show: true}.Add(ops)
205 s.Load()
206
207 // Set new InputOp without focus:
208 s = op.Save(ops)
209 key.InputOp{Tag: &handlers[1]}.Add(ops)
210 s.Load()
211
212 r.Frame(ops)
213
214 assertKeyEvent(t, r.Events(&handlers[0]), true)
215 assertKeyEvent(t, r.Events(&handlers[1]), false)
216 assertFocus(t, r, &handlers[0])
217 assertKeyboard(t, r, TextInputOpen)
218
219 ops.Reset()
220
221 //
222 // Removed first (focused) element!
223 //
224
225 // Unchanged:
226 s = op.Save(ops)
227 key.InputOp{Tag: &handlers[1]}.Add(ops)
228 s.Load()
229
230 r.Frame(ops)
231
232 assertKeyEventUnexpected(t, r.Events(&handlers[0]))
233 assertKeyEventUnexpected(t, r.Events(&handlers[1]))
234 assertFocus(t, r, nil)
235 assertKeyboard(t, r, TextInputClose)
236
237 ops.Reset()
238
239 // Respawn the first element:
240 // It must receive one `Event{Focus: false}`.
241 s = op.Save(ops)
242 key.InputOp{Tag: &handlers[0]}.Add(ops)
243 s.Load()
244
245 // Unchanged
246 s = op.Save(ops)
247 key.InputOp{Tag: &handlers[1]}.Add(ops)
248 s.Load()
249
250 r.Frame(ops)
251
252 assertKeyEvent(t, r.Events(&handlers[0]), false)
253 assertKeyEventUnexpected(t, r.Events(&handlers[1]))
254 assertFocus(t, r, nil)
255 assertKeyboard(t, r, TextInputKeep)
256
257 }
258
259 func assertKeyEvent(t *testing.T, events []event.Event, expected bool, expectedInputs ...event.Event) {
260 t.Helper()
261 var evtFocus int
262 var evtKeyPress int
263 for _, e := range events {
264 switch ev := e.(type) {
265 case key.FocusEvent:
266 if ev.Focus != expected {
267 t.Errorf("focus is expected to be %v, got %v", expected, ev.Focus)
268 }
269 evtFocus++
270 case key.Event, key.EditEvent:
271 if len(expectedInputs) <= evtKeyPress {
272 t.Errorf("unexpected key events")
273 }
274 if !reflect.DeepEqual(ev, expectedInputs[evtKeyPress]) {
275 t.Errorf("expected %v events, got %v", expectedInputs[evtKeyPress], ev)
276 }
277 evtKeyPress++
278 }
279 }
280 if evtFocus <= 0 {
281 t.Errorf("expected focus event")
282 }
283 if evtFocus > 1 {
284 t.Errorf("expected single focus event")
285 }
286 if evtKeyPress != len(expectedInputs) {
287 t.Errorf("expected key events")
288 }
289 }
290
291 func assertKeyEventUnexpected(t *testing.T, events []event.Event) {
292 t.Helper()
293 var evtFocus int
294 for _, e := range events {
295 switch e.(type) {
296 case key.FocusEvent:
297 evtFocus++
298 }
299 }
300 if evtFocus > 1 {
301 t.Errorf("unexpected focus event")
302 }
303 }
304
305 func assertFocus(t *testing.T, router *Router, expected event.Tag) {
306 t.Helper()
307 if router.kqueue.focus != expected {
308 t.Errorf("expected %v to be focused, got %v", expected, router.kqueue.focus)
309 }
310 }
311
312 func assertKeyboard(t *testing.T, router *Router, expected TextInputState) {
313 t.Helper()
314 if router.kqueue.state != expected {
315 t.Errorf("expected %v keyboard, got %v", expected, router.kqueue.state)
316 }
317 }
318