github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/io/router/key.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package router 4 5 import ( 6 "github.com/cybriq/giocore/internal/opconst" 7 "github.com/cybriq/giocore/internal/ops" 8 "github.com/cybriq/giocore/io/event" 9 "github.com/cybriq/giocore/io/key" 10 "github.com/cybriq/giocore/op" 11 ) 12 13 type TextInputState uint8 14 15 type keyQueue struct { 16 focus event.Tag 17 handlers map[event.Tag]*keyHandler 18 reader ops.Reader 19 state TextInputState 20 hint key.InputHint 21 } 22 23 type keyHandler struct { 24 // visible will be true if the InputOp is present 25 // in the current frame. 26 visible bool 27 new bool 28 hint key.InputHint 29 } 30 31 const ( 32 TextInputKeep TextInputState = iota 33 TextInputClose 34 TextInputOpen 35 ) 36 37 // InputState returns the last text input state as 38 // determined in Frame. 39 func (q *keyQueue) InputState() TextInputState { 40 return q.state 41 } 42 43 // InputHint returns the input mode from the most recent key.InputOp. 44 func (q *keyQueue) InputHint() (key.InputHint, bool) { 45 if q.focus == nil { 46 return q.hint, false 47 } 48 focused, ok := q.handlers[q.focus] 49 if !ok { 50 return q.hint, false 51 } 52 old := q.hint 53 q.hint = focused.hint 54 return q.hint, old != q.hint 55 } 56 57 func (q *keyQueue) Frame(root *op.Ops, events *handlerEvents) { 58 if q.handlers == nil { 59 q.handlers = make(map[event.Tag]*keyHandler) 60 } 61 for _, h := range q.handlers { 62 h.visible, h.new = false, false 63 } 64 q.reader.Reset(root) 65 66 focus, changed, state := q.resolveFocus(events) 67 for k, h := range q.handlers { 68 if !h.visible { 69 delete(q.handlers, k) 70 if q.focus == k { 71 // Remove the focus from the handler that is no longer visible. 72 q.focus = nil 73 state = TextInputClose 74 } 75 } else if h.new && k != focus { 76 // Reset the handler on (each) first appearance, but don't trigger redraw. 77 events.AddNoRedraw(k, key.FocusEvent{Focus: false}) 78 } 79 } 80 if changed && focus != nil { 81 if _, exists := q.handlers[focus]; !exists { 82 focus = nil 83 } 84 } 85 if changed && focus != q.focus { 86 if q.focus != nil { 87 events.Add(q.focus, key.FocusEvent{Focus: false}) 88 } 89 q.focus = focus 90 if q.focus != nil { 91 events.Add(q.focus, key.FocusEvent{Focus: true}) 92 } else { 93 state = TextInputClose 94 } 95 } 96 q.state = state 97 } 98 99 func (q *keyQueue) Push(e event.Event, events *handlerEvents) { 100 if q.focus != nil { 101 events.Add(q.focus, e) 102 } 103 } 104 105 func (q *keyQueue) resolveFocus(events *handlerEvents) (focus event.Tag, changed bool, state TextInputState) { 106 for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() { 107 switch opconst.OpType(encOp.Data[0]) { 108 case opconst.TypeKeyFocus: 109 op := decodeFocusOp(encOp.Data, encOp.Refs) 110 changed = true 111 focus = op.Tag 112 case opconst.TypeKeySoftKeyboard: 113 op := decodeSoftKeyboardOp(encOp.Data, encOp.Refs) 114 if op.Show { 115 state = TextInputOpen 116 } else { 117 state = TextInputClose 118 } 119 case opconst.TypeKeyInput: 120 op := decodeKeyInputOp(encOp.Data, encOp.Refs) 121 h, ok := q.handlers[op.Tag] 122 if !ok { 123 h = &keyHandler{new: true} 124 q.handlers[op.Tag] = h 125 } 126 h.visible = true 127 h.hint = op.Hint 128 } 129 } 130 return 131 } 132 133 func decodeKeyInputOp(d []byte, refs []interface{}) key.InputOp { 134 if opconst.OpType(d[0]) != opconst.TypeKeyInput { 135 panic("invalid op") 136 } 137 return key.InputOp{ 138 Tag: refs[0].(event.Tag), 139 Hint: key.InputHint(d[1]), 140 } 141 } 142 143 func decodeSoftKeyboardOp(d []byte, refs []interface{}) key.SoftKeyboardOp { 144 if opconst.OpType(d[0]) != opconst.TypeKeySoftKeyboard { 145 panic("invalid op") 146 } 147 return key.SoftKeyboardOp{ 148 Show: d[1] != 0, 149 } 150 } 151 152 func decodeFocusOp(d []byte, refs []interface{}) key.FocusOp { 153 if opconst.OpType(d[0]) != opconst.TypeKeyFocus { 154 panic("invalid op") 155 } 156 return key.FocusOp{ 157 Tag: refs[0], 158 } 159 }