github.com/Seikaijyu/gio@v0.0.1/io/router/key_test.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package router 4 5 import ( 6 "image" 7 "reflect" 8 "testing" 9 10 "github.com/Seikaijyu/gio/f32" 11 "github.com/Seikaijyu/gio/io/event" 12 "github.com/Seikaijyu/gio/io/key" 13 "github.com/Seikaijyu/gio/io/pointer" 14 "github.com/Seikaijyu/gio/op" 15 "github.com/Seikaijyu/gio/op/clip" 16 ) 17 18 func TestKeyWakeup(t *testing.T) { 19 handler := new(int) 20 var ops op.Ops 21 key.InputOp{Tag: handler}.Add(&ops) 22 23 var r Router 24 // Test that merely adding a handler doesn't trigger redraw. 25 r.Frame(&ops) 26 if _, wake := r.WakeupTime(); wake { 27 t.Errorf("adding key.InputOp triggered a redraw") 28 } 29 // However, adding a handler queues a Focus(false) event. 30 if evts := r.Events(handler); len(evts) != 1 { 31 t.Errorf("no Focus event for newly registered key.InputOp") 32 } 33 } 34 35 func TestKeyMultiples(t *testing.T) { 36 handlers := make([]int, 3) 37 ops := new(op.Ops) 38 r := new(Router) 39 40 key.SoftKeyboardOp{Show: true}.Add(ops) 41 key.InputOp{Tag: &handlers[0]}.Add(ops) 42 key.FocusOp{Tag: &handlers[2]}.Add(ops) 43 key.InputOp{Tag: &handlers[1]}.Add(ops) 44 45 // The last one must be focused: 46 key.InputOp{Tag: &handlers[2]}.Add(ops) 47 48 r.Frame(ops) 49 50 assertKeyEvent(t, r.Events(&handlers[0]), false) 51 assertKeyEvent(t, r.Events(&handlers[1]), false) 52 assertKeyEvent(t, r.Events(&handlers[2]), true) 53 assertFocus(t, r, &handlers[2]) 54 assertKeyboard(t, r, TextInputOpen) 55 } 56 57 func TestKeyStacked(t *testing.T) { 58 handlers := make([]int, 4) 59 ops := new(op.Ops) 60 r := new(Router) 61 62 key.InputOp{Tag: &handlers[0]}.Add(ops) 63 key.FocusOp{Tag: nil}.Add(ops) 64 key.SoftKeyboardOp{Show: false}.Add(ops) 65 key.InputOp{Tag: &handlers[1]}.Add(ops) 66 key.FocusOp{Tag: &handlers[1]}.Add(ops) 67 key.InputOp{Tag: &handlers[2]}.Add(ops) 68 key.SoftKeyboardOp{Show: true}.Add(ops) 69 key.InputOp{Tag: &handlers[3]}.Add(ops) 70 71 r.Frame(ops) 72 73 assertKeyEvent(t, r.Events(&handlers[0]), false) 74 assertKeyEvent(t, r.Events(&handlers[1]), true) 75 assertKeyEvent(t, r.Events(&handlers[2]), false) 76 assertKeyEvent(t, r.Events(&handlers[3]), false) 77 assertFocus(t, r, &handlers[1]) 78 assertKeyboard(t, r, TextInputOpen) 79 } 80 81 func TestKeySoftKeyboardNoFocus(t *testing.T) { 82 ops := new(op.Ops) 83 r := new(Router) 84 85 // It's possible to open the keyboard 86 // without any active focus: 87 key.SoftKeyboardOp{Show: true}.Add(ops) 88 89 r.Frame(ops) 90 91 assertFocus(t, r, nil) 92 assertKeyboard(t, r, TextInputOpen) 93 } 94 95 func TestKeyRemoveFocus(t *testing.T) { 96 handlers := make([]int, 2) 97 ops := new(op.Ops) 98 r := new(Router) 99 100 // New InputOp with Focus and Keyboard: 101 key.InputOp{Tag: &handlers[0], Keys: "Short-Tab"}.Add(ops) 102 key.FocusOp{Tag: &handlers[0]}.Add(ops) 103 key.SoftKeyboardOp{Show: true}.Add(ops) 104 105 // New InputOp without any focus: 106 key.InputOp{Tag: &handlers[1], Keys: "Short-Tab"}.Add(ops) 107 108 r.Frame(ops) 109 110 // Add some key events: 111 event := event.Event(key.Event{Name: key.NameTab, Modifiers: key.ModShortcut, State: key.Press}) 112 r.Queue(event) 113 114 assertKeyEvent(t, r.Events(&handlers[0]), true, event) 115 assertKeyEvent(t, r.Events(&handlers[1]), false) 116 assertFocus(t, r, &handlers[0]) 117 assertKeyboard(t, r, TextInputOpen) 118 119 ops.Reset() 120 121 // Will get the focus removed: 122 key.InputOp{Tag: &handlers[0]}.Add(ops) 123 124 // Unchanged: 125 key.InputOp{Tag: &handlers[1]}.Add(ops) 126 127 // Remove focus by focusing on a tag that don't exist. 128 key.FocusOp{Tag: new(int)}.Add(ops) 129 130 r.Frame(ops) 131 132 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 133 assertFocus(t, r, nil) 134 assertKeyboard(t, r, TextInputClose) 135 136 ops.Reset() 137 138 key.InputOp{Tag: &handlers[0]}.Add(ops) 139 140 key.InputOp{Tag: &handlers[1]}.Add(ops) 141 142 r.Frame(ops) 143 144 assertKeyEventUnexpected(t, r.Events(&handlers[0])) 145 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 146 assertFocus(t, r, nil) 147 assertKeyboard(t, r, TextInputClose) 148 149 ops.Reset() 150 151 // Set focus to InputOp which already 152 // exists in the previous frame: 153 key.FocusOp{Tag: &handlers[0]}.Add(ops) 154 key.InputOp{Tag: &handlers[0]}.Add(ops) 155 key.SoftKeyboardOp{Show: true}.Add(ops) 156 157 // Remove focus. 158 key.InputOp{Tag: &handlers[1]}.Add(ops) 159 key.FocusOp{Tag: nil}.Add(ops) 160 161 r.Frame(ops) 162 163 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 164 assertFocus(t, r, nil) 165 assertKeyboard(t, r, TextInputOpen) 166 } 167 168 func TestKeyFocusedInvisible(t *testing.T) { 169 handlers := make([]int, 2) 170 ops := new(op.Ops) 171 r := new(Router) 172 173 // Set new InputOp with focus: 174 key.FocusOp{Tag: &handlers[0]}.Add(ops) 175 key.InputOp{Tag: &handlers[0]}.Add(ops) 176 key.SoftKeyboardOp{Show: true}.Add(ops) 177 178 // Set new InputOp without focus: 179 key.InputOp{Tag: &handlers[1]}.Add(ops) 180 181 r.Frame(ops) 182 183 assertKeyEvent(t, r.Events(&handlers[0]), true) 184 assertKeyEvent(t, r.Events(&handlers[1]), false) 185 assertFocus(t, r, &handlers[0]) 186 assertKeyboard(t, r, TextInputOpen) 187 188 ops.Reset() 189 190 // 191 // Removed first (focused) element! 192 // 193 194 // Unchanged: 195 key.InputOp{Tag: &handlers[1]}.Add(ops) 196 197 r.Frame(ops) 198 199 assertKeyEventUnexpected(t, r.Events(&handlers[0])) 200 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 201 assertFocus(t, r, nil) 202 assertKeyboard(t, r, TextInputClose) 203 204 ops.Reset() 205 206 // Respawn the first element: 207 // It must receive one `Event{Focus: false}`. 208 key.InputOp{Tag: &handlers[0]}.Add(ops) 209 210 // Unchanged 211 key.InputOp{Tag: &handlers[1]}.Add(ops) 212 213 r.Frame(ops) 214 215 assertKeyEvent(t, r.Events(&handlers[0]), false) 216 assertKeyEventUnexpected(t, r.Events(&handlers[1])) 217 assertFocus(t, r, nil) 218 assertKeyboard(t, r, TextInputClose) 219 220 } 221 222 func TestNoOps(t *testing.T) { 223 r := new(Router) 224 r.Frame(nil) 225 } 226 227 func TestDirectionalFocus(t *testing.T) { 228 ops := new(op.Ops) 229 r := new(Router) 230 handlers := []image.Rectangle{ 231 image.Rect(10, 10, 50, 50), 232 image.Rect(50, 20, 100, 80), 233 image.Rect(20, 26, 60, 80), 234 image.Rect(10, 60, 50, 100), 235 } 236 237 for i, bounds := range handlers { 238 cl := clip.Rect(bounds).Push(ops) 239 key.InputOp{Tag: &handlers[i]}.Add(ops) 240 cl.Pop() 241 } 242 r.Frame(ops) 243 244 r.MoveFocus(FocusLeft) 245 assertFocus(t, r, &handlers[0]) 246 r.MoveFocus(FocusLeft) 247 assertFocus(t, r, &handlers[0]) 248 r.MoveFocus(FocusRight) 249 assertFocus(t, r, &handlers[1]) 250 r.MoveFocus(FocusRight) 251 assertFocus(t, r, &handlers[1]) 252 r.MoveFocus(FocusDown) 253 assertFocus(t, r, &handlers[2]) 254 r.MoveFocus(FocusDown) 255 assertFocus(t, r, &handlers[2]) 256 r.MoveFocus(FocusLeft) 257 assertFocus(t, r, &handlers[3]) 258 r.MoveFocus(FocusUp) 259 assertFocus(t, r, &handlers[0]) 260 261 r.MoveFocus(FocusForward) 262 assertFocus(t, r, &handlers[1]) 263 r.MoveFocus(FocusBackward) 264 assertFocus(t, r, &handlers[0]) 265 } 266 267 func TestFocusScroll(t *testing.T) { 268 ops := new(op.Ops) 269 r := new(Router) 270 h := new(int) 271 272 parent := clip.Rect(image.Rect(1, 1, 14, 39)).Push(ops) 273 cl := clip.Rect(image.Rect(10, -20, 20, 30)).Push(ops) 274 key.InputOp{Tag: h}.Add(ops) 275 pointer.InputOp{ 276 Tag: h, 277 Kinds: pointer.Scroll, 278 ScrollBounds: image.Rect(-100, -100, 100, 100), 279 }.Add(ops) 280 // Test that h is scrolled even if behind another handler. 281 pointer.InputOp{ 282 Tag: new(int), 283 }.Add(ops) 284 cl.Pop() 285 parent.Pop() 286 r.Frame(ops) 287 288 r.MoveFocus(FocusLeft) 289 r.RevealFocus(image.Rect(0, 0, 15, 40)) 290 evts := r.Events(h) 291 assertScrollEvent(t, evts[len(evts)-1], f32.Pt(6, -9)) 292 } 293 294 func TestFocusClick(t *testing.T) { 295 ops := new(op.Ops) 296 r := new(Router) 297 h := new(int) 298 299 cl := clip.Rect(image.Rect(0, 0, 10, 10)).Push(ops) 300 key.InputOp{Tag: h}.Add(ops) 301 pointer.InputOp{ 302 Tag: h, 303 Kinds: pointer.Press | pointer.Release, 304 }.Add(ops) 305 cl.Pop() 306 r.Frame(ops) 307 308 r.MoveFocus(FocusLeft) 309 r.ClickFocus() 310 assertEventPointerTypeSequence(t, r.Events(h), pointer.Cancel, pointer.Press, pointer.Release) 311 } 312 313 func TestNoFocus(t *testing.T) { 314 r := new(Router) 315 r.MoveFocus(FocusForward) 316 } 317 318 func TestKeyRouting(t *testing.T) { 319 handlers := make([]int, 5) 320 ops := new(op.Ops) 321 macroOps := new(op.Ops) 322 r := new(Router) 323 324 rect := clip.Rect{Max: image.Pt(10, 10)} 325 326 macro := op.Record(macroOps) 327 key.InputOp{Tag: &handlers[0], Keys: "A"}.Add(ops) 328 cl1 := rect.Push(ops) 329 key.InputOp{Tag: &handlers[1], Keys: "B"}.Add(ops) 330 key.InputOp{Tag: &handlers[2], Keys: "A"}.Add(ops) 331 cl1.Pop() 332 cl2 := rect.Push(ops) 333 key.InputOp{Tag: &handlers[3]}.Add(ops) 334 key.InputOp{Tag: &handlers[4], Keys: "A"}.Add(ops) 335 cl2.Pop() 336 call := macro.Stop() 337 call.Add(ops) 338 339 r.Frame(ops) 340 341 A, B := key.Event{Name: "A"}, key.Event{Name: "B"} 342 r.Queue(A, B) 343 344 // With no focus, the events should traverse the final branch of the hit tree 345 // searching for handlers. 346 assertKeyEvent(t, r.Events(&handlers[4]), false, A) 347 assertKeyEvent(t, r.Events(&handlers[3]), false) 348 assertKeyEvent(t, r.Events(&handlers[2]), false) 349 assertKeyEvent(t, r.Events(&handlers[1]), false, B) 350 assertKeyEvent(t, r.Events(&handlers[0]), false) 351 352 r2 := new(Router) 353 354 call.Add(ops) 355 key.FocusOp{Tag: &handlers[3]}.Add(ops) 356 r2.Frame(ops) 357 358 r2.Queue(A, B) 359 360 // With focus, the events should traverse the branch of the hit tree 361 // containing the focused element. 362 assertKeyEvent(t, r2.Events(&handlers[4]), false) 363 assertKeyEvent(t, r2.Events(&handlers[3]), true) 364 assertKeyEvent(t, r2.Events(&handlers[2]), false) 365 assertKeyEvent(t, r2.Events(&handlers[1]), false) 366 assertKeyEvent(t, r2.Events(&handlers[0]), false, A) 367 } 368 369 func assertKeyEvent(t *testing.T, events []event.Event, expectedFocus bool, expectedInputs ...event.Event) { 370 t.Helper() 371 var evtFocus int 372 var evtKeyPress int 373 for _, e := range events { 374 switch ev := e.(type) { 375 case key.FocusEvent: 376 if ev.Focus != expectedFocus { 377 t.Errorf("focus is expected to be %v, got %v", expectedFocus, ev.Focus) 378 } 379 evtFocus++ 380 case key.Event, key.EditEvent: 381 if len(expectedInputs) <= evtKeyPress { 382 t.Fatalf("unexpected key events") 383 } 384 if !reflect.DeepEqual(ev, expectedInputs[evtKeyPress]) { 385 t.Errorf("expected %v events, got %v", expectedInputs[evtKeyPress], ev) 386 } 387 evtKeyPress++ 388 } 389 } 390 if evtFocus <= 0 { 391 t.Errorf("expected focus event") 392 } 393 if evtFocus > 1 { 394 t.Errorf("expected single focus event") 395 } 396 if evtKeyPress != len(expectedInputs) { 397 t.Errorf("expected key events") 398 } 399 } 400 401 func assertKeyEventUnexpected(t *testing.T, events []event.Event) { 402 t.Helper() 403 var evtFocus int 404 for _, e := range events { 405 switch e.(type) { 406 case key.FocusEvent: 407 evtFocus++ 408 } 409 } 410 if evtFocus > 1 { 411 t.Errorf("unexpected focus event") 412 } 413 } 414 415 func assertFocus(t *testing.T, router *Router, expected event.Tag) { 416 t.Helper() 417 if got := router.key.queue.focus; got != expected { 418 t.Errorf("expected %v to be focused, got %v", expected, got) 419 } 420 } 421 422 func assertKeyboard(t *testing.T, router *Router, expected TextInputState) { 423 t.Helper() 424 if got := router.key.queue.state; got != expected { 425 t.Errorf("expected %v keyboard, got %v", expected, got) 426 } 427 }