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