~eliasnaur/gio

ref: 7aa7bb3be40858efe2a98f866fcc7db2026b02fd gio/ui/input/key.go -rw-r--r-- 2.5 KiB
7aa7bb3bElias Naur ui: rename ops to have Op suffixed, not prefixed 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// SPDX-License-Identifier: Unlicense OR MIT

package input

import (
	"gioui.org/ui"
	"gioui.org/ui/internal/ops"
	"gioui.org/ui/key"
)

type keyQueue struct {
	focus    Key
	handlers map[Key]*keyHandler
	reader   ui.OpsReader
	state    key.TextInputState
}

type keyHandler struct {
	active bool
}

type listenerPriority uint8

const (
	priNone listenerPriority = iota
	priDefault
	priCurrentFocus
	priNewFocus
)

// InputState returns the last text input state as
// determined in Frame.
func (q *keyQueue) InputState() key.TextInputState {
	return q.state
}

func (q *keyQueue) Frame(root *ui.Ops, events handlerEvents) {
	if q.handlers == nil {
		q.handlers = make(map[Key]*keyHandler)
	}
	for _, h := range q.handlers {
		h.active = false
	}
	q.reader.Reset(root)
	focus, pri, hide := q.resolveFocus(events)
	for k, h := range q.handlers {
		if !h.active {
			delete(q.handlers, k)
			if q.focus == k {
				q.focus = nil
			}
		}
	}
	changed := focus != nil && focus != q.focus
	if focus != q.focus {
		if q.focus != nil {
			events[q.focus] = append(events[q.focus], key.Focus{Focus: false})
		}
		q.focus = focus
		if q.focus != nil {
			events[q.focus] = append(events[q.focus], key.Focus{Focus: true})
		}
	}
	switch {
	case pri == priNewFocus:
		q.state = key.TextInputOpen
	case hide:
		q.state = key.TextInputClosed
	case changed:
		q.state = key.TextInputFocus
	default:
		q.state = key.TextInputKeep
	}
}

func (q *keyQueue) Push(e Event, events handlerEvents) {
	if q.focus == nil {
		return
	}
	events[q.focus] = append(events[q.focus], e)
}

func (q *keyQueue) resolveFocus(events handlerEvents) (Key, listenerPriority, bool) {
	var k Key
	var pri listenerPriority
	var hide bool
loop:
	for {
		encOp, ok := q.reader.Decode()
		if !ok {
			break
		}
		switch ops.OpType(encOp.Data[0]) {
		case ops.TypeKeyHandler:
			var op key.HandlerOp
			op.Decode(encOp.Data, encOp.Refs)
			var newPri listenerPriority
			switch {
			case op.Focus:
				newPri = priNewFocus
			case op.Key == q.focus:
				newPri = priCurrentFocus
			default:
				newPri = priDefault
			}
			if newPri >= pri {
				k, pri = op.Key, newPri
			}
			h, ok := q.handlers[op.Key]
			if !ok {
				h = new(keyHandler)
				q.handlers[op.Key] = h
				// Reset the handler on (each) first appearance.
				events[op.Key] = []Event{key.Focus{Focus: false}}
			}
			h.active = true
		case ops.TypeHideInput:
			hide = true
		case ops.TypePush:
			newK, newPri, h := q.resolveFocus(events)
			hide = hide || h
			if newPri >= pri {
				k, pri = newK, newPri
			}
		case ops.TypePop:
			break loop
		}
	}
	return k, pri, hide
}