~eliasnaur/gio

ref: b981ccf9eda43816ae9d809466fe96c8e0c2475b gio/ui/input/key.go -rw-r--r-- 2.5 KiB
b981ccf9Elias Naur ui/input: support single stepping through events 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.OpHandler
			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
}