-
Notifications
You must be signed in to change notification settings - Fork 4
/
listener.go
192 lines (172 loc) · 5.01 KB
/
listener.go
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
package gowinkey
import (
"time"
)
// listener listens for global key events.
type listener struct {
modifiers Modifiers
pressedKeys KeySet
predicates []Predicate
}
func newListener(predicates ...Predicate) *listener {
return &listener{
pressedKeys: make(KeySet),
predicates: predicates,
}
}
// Listen listens for global key events, sending them on the
// events channel.
// Listen halts execution and closes the events channel as
// soon as stopFn is called.
// Listen does not block.
// The given predicates act as a filter. Only events matching
// all predicates will be sent on the events channel.
func Listen(predicates ...Predicate) (events <-chan KeyEvent, stopFn func()) {
return newListener(predicates...).listen()
}
// listen listens for global key events, sending them on the
// returned channel. listen halts execution and closes the
// returned channel as soon as the returned function is called.
// listen does not block.
func (l *listener) listen() (<-chan KeyEvent, func()) {
events, stopChan := make(chan KeyEvent), make(chan bool)
go func() {
l.swallowQueuedStates()
l.doListen(events, stopChan)
}()
return events, func() { stopChan <- true; close(events) }
}
// swallowQueuedStates drains the message queue so that the
// listener does not catch any events that were issue before
// listener.listen was called.
func (l listener) swallowQueuedStates() {
for i := 0; i < 256; i++ {
_getKeyState(i)
}
}
// doListen listens for global key events,
// sending them on the events channel.
func (l *listener) doListen(events chan KeyEvent, stopChan <-chan bool) {
Outer:
for {
select {
case <-stopChan:
break Outer
default:
time.Sleep(10 * time.Millisecond)
l.listenOnce(events)
}
}
}
// listenOnce listens for the state of each of the 254 known
// virtual keys and sends according key events on the events
// channel.
func (l *listener) listenOnce(events chan KeyEvent) {
for i := 0; i < 255; i++ {
key := VirtualKey(i)
if l.isDuplicateModifier(key) {
continue
}
state := getKeyState(i)
event := KeyEvent{
VirtualKey: key,
State: state,
}
if state == KeyDown {
if !l.pressedKeys.Contains(key) {
l.pressedKeys.Add(key)
l.processModifier(key, KeyDown)
l.applyModifiers(&event)
event.PressedKeys = l.pressedKeys
if l.satisfiesPredicates(event) {
events <- event
}
}
} else {
if l.pressedKeys.Contains(key) {
l.pressedKeys.Delete(key)
l.processModifier(key, KeyUp)
l.applyModifiers(&event)
event.PressedKeys = l.pressedKeys
if l.satisfiesPredicates(event) {
events <- event
}
}
}
}
}
// isDuplicateModifier reports whether the given
// virtual key represents a duplicate modifier.
//
// This is needed, because the Windows API fires two events
// when a modifier key is pressed - one for the specific key
// (say, VK_LSHIFT) and one for the "raw" modifier
// (say, VK_SHIFT).
func (l listener) isDuplicateModifier(key VirtualKey) bool {
return key == VK_SHIFT || key == VK_CONTROL || key == VK_MENU
}
// processModifier extracts modifier information from the given
// given virtual key and updates the listener.modifiers accordingly.
func (l *listener) processModifier(key VirtualKey, state KeyState) {
mod := l.keyToModifier(key)
if state == KeyDown {
l.modifiers |= mod
} else {
if !l.modifierCounterpartPressed(key) {
l.modifiers = l.modifiers.RemoveModifiers(mod)
}
}
}
// keyToModifier returns the modifier associated with
// the given virtual key. If the key does not represent
// any modifier, keyToModifier returns 0.
func (l listener) keyToModifier(key VirtualKey) Modifiers {
switch key {
case VK_SHIFT, VK_LSHIFT, VK_RSHIFT:
return ModifierShift
case VK_CONTROL, VK_LCONTROL, VK_RCONTROL:
return ModifierControl
case VK_MENU, VK_LMENU, VK_RMENU:
return ModifierMenu
}
return 0
}
// modifierCounterpartPressed reports whether the "counterpart" of
// the given modifier key is pressed, where by counterpart we mean
// the left version for right modifier keys and vice versa.
//
// If key does not represent a modifier key,
// modifierCounterpartPressed returns false.
func (l listener) modifierCounterpartPressed(key VirtualKey) bool {
switch key {
case VK_LSHIFT:
return l.pressedKeys.Contains(VK_RSHIFT)
case VK_RSHIFT:
return l.pressedKeys.Contains(VK_LSHIFT)
case VK_LCONTROL:
return l.pressedKeys.Contains(VK_RCONTROL)
case VK_RCONTROL:
return l.pressedKeys.Contains(VK_LCONTROL)
case VK_LMENU:
return l.pressedKeys.Contains(VK_RMENU)
case VK_RMENU:
return l.pressedKeys.Contains(VK_LMENU)
}
return false
}
// applyModifiers applies modifiers for
// the currently pressed keys to the event.
func (l listener) applyModifiers(event *KeyEvent) {
eventMod := l.keyToModifier(event.VirtualKey)
event.Modifiers = l.modifiers.RemoveModifiers(eventMod)
}
// satisfiesPredicates reports whether the given
// key event satisfies all listener.predicates.
func (l listener) satisfiesPredicates(event KeyEvent) bool {
for _, p := range l.predicates {
if !p(event) {
return false
}
}
return true
}