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