github.com/gop9/olt@v0.0.0-20200202132135-d956aad50b08/gio/app/internal/input/key.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package input 4 5 import ( 6 "github.com/gop9/olt/gio/internal/opconst" 7 "github.com/gop9/olt/gio/internal/ops" 8 "github.com/gop9/olt/gio/io/event" 9 "github.com/gop9/olt/gio/io/key" 10 "github.com/gop9/olt/gio/op" 11 ) 12 13 type TextInputState uint8 14 15 type keyQueue struct { 16 focus event.Key 17 handlers map[event.Key]*keyHandler 18 reader ops.Reader 19 state TextInputState 20 } 21 22 type keyHandler struct { 23 active bool 24 } 25 26 type listenerPriority uint8 27 28 const ( 29 priNone listenerPriority = iota 30 priDefault 31 priCurrentFocus 32 priNewFocus 33 ) 34 35 const ( 36 TextInputKeep TextInputState = iota 37 TextInputClose 38 TextInputOpen 39 ) 40 41 // InputState returns the last text input state as 42 // determined in Frame. 43 func (q *keyQueue) InputState() TextInputState { 44 return q.state 45 } 46 47 func (q *keyQueue) Frame(root *op.Ops, events *handlerEvents) { 48 if q.handlers == nil { 49 q.handlers = make(map[event.Key]*keyHandler) 50 } 51 for _, h := range q.handlers { 52 h.active = false 53 } 54 q.reader.Reset(root) 55 focus, pri, hide := q.resolveFocus(events) 56 for k, h := range q.handlers { 57 if !h.active { 58 delete(q.handlers, k) 59 if q.focus == k { 60 q.focus = nil 61 hide = true 62 } 63 } 64 } 65 if focus != q.focus { 66 if q.focus != nil { 67 events.Add(q.focus, key.FocusEvent{Focus: false}) 68 } 69 q.focus = focus 70 if q.focus != nil { 71 events.Add(q.focus, key.FocusEvent{Focus: true}) 72 } else { 73 hide = true 74 } 75 } 76 switch { 77 case pri == priNewFocus: 78 q.state = TextInputOpen 79 case hide: 80 q.state = TextInputClose 81 default: 82 q.state = TextInputKeep 83 } 84 } 85 86 func (q *keyQueue) Push(e event.Event, events *handlerEvents) { 87 if q.focus != nil { 88 events.Add(q.focus, e) 89 } 90 } 91 92 func (q *keyQueue) resolveFocus(events *handlerEvents) (event.Key, listenerPriority, bool) { 93 var k event.Key 94 var pri listenerPriority 95 var hide bool 96 loop: 97 for encOp, ok := q.reader.Decode(); ok; encOp, ok = q.reader.Decode() { 98 switch opconst.OpType(encOp.Data[0]) { 99 case opconst.TypeKeyInput: 100 op := decodeKeyInputOp(encOp.Data, encOp.Refs) 101 var newPri listenerPriority 102 switch { 103 case op.Focus: 104 newPri = priNewFocus 105 case op.Key == q.focus: 106 newPri = priCurrentFocus 107 default: 108 newPri = priDefault 109 } 110 // Switch focus if higher priority or if focus requested. 111 if newPri.replaces(pri) { 112 k, pri = op.Key, newPri 113 } 114 h, ok := q.handlers[op.Key] 115 if !ok { 116 h = new(keyHandler) 117 q.handlers[op.Key] = h 118 // Reset the handler on (each) first appearance. 119 events.Set(op.Key, []event.Event{key.FocusEvent{Focus: false}}) 120 } 121 h.active = true 122 case opconst.TypeHideInput: 123 hide = true 124 case opconst.TypePush: 125 newK, newPri, h := q.resolveFocus(events) 126 hide = hide || h 127 if newPri.replaces(pri) { 128 k, pri = newK, newPri 129 } 130 case opconst.TypePop: 131 break loop 132 } 133 } 134 return k, pri, hide 135 } 136 137 func (p listenerPriority) replaces(p2 listenerPriority) bool { 138 // Favor earliest default focus or latest requested focus. 139 return p > p2 || p == p2 && p == priNewFocus 140 } 141 142 func decodeKeyInputOp(d []byte, refs []interface{}) key.InputOp { 143 if opconst.OpType(d[0]) != opconst.TypeKeyInput { 144 panic("invalid op") 145 } 146 return key.InputOp{ 147 Focus: d[1] != 0, 148 Key: refs[0].(event.Key), 149 } 150 }