/
ch-inputs.go
127 lines (96 loc) · 2.99 KB
/
ch-inputs.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
package spice
import (
"encoding/binary"
"log"
)
const (
SPICE_MSGC_INPUTS_KEY_DOWN = 101
SPICE_MSGC_INPUTS_KEY_UP = 102
SPICE_MSGC_INPUTS_KEY_MODIFIERS = 103
SPICE_MSGC_INPUTS_MOUSE_MOTION = 111
SPICE_MSGC_INPUTS_MOUSE_POSITION = 112
SPICE_MSGC_INPUTS_MOUSE_PRESS = 113
SPICE_MSGC_INPUTS_MOUSE_RELEASE = 114
SPICE_MSG_INPUTS_INIT = 101
SPICE_MSG_INPUTS_KEY_MODIFIERS = 102
SPICE_MSG_INPUTS_MOUSE_MOTION_ACK = 111
// Keyboard led bits
SPICE_SCROLL_LOCK_MODIFIER = 1
SPICE_NUM_LOCK_MODIFIER = 2
SPICE_CAPS_LOCK_MODIFIER = 4
SPICE_INPUTS_CAP_KEY_SCANCODE = 0
)
type ChInputs struct {
cl *Client
conn *SpiceConn
// btn state
btn uint16
}
func (cl *Client) setupInputs(id uint8) (*ChInputs, error) {
conn, err := cl.conn(ChannelInputs, id, nil) //caps(SPICE_INPUTS_CAP_KEY_SCANCODE))
if err != nil {
return nil, err
}
input := &ChInputs{cl: cl, conn: conn}
conn.hndlr = input.handle
go conn.ReadLoop()
// reset keyboard leds
input.conn.WriteMessage(SPICE_MSGC_INPUTS_KEY_MODIFIERS, uint16(0))
cl.driver.SetEventsTarget(input)
return input, nil
}
func (input *ChInputs) handle(typ uint16, data []byte) {
switch typ {
case SPICE_MSG_INPUTS_INIT:
// Note: spice documentation is wrong, this is 16bits and not 32bits
keyMod := binary.LittleEndian.Uint16(data)
log.Printf("spice/inputs: got key modifier status from server, value = %d (initial)", keyMod)
case SPICE_MSG_INPUTS_KEY_MODIFIERS:
keyMod := binary.LittleEndian.Uint16(data)
log.Printf("spice/inputs: got key modifier status from server, value = %d", keyMod)
case SPICE_MSG_INPUTS_MOUSE_MOTION_ACK:
// do nothing
default:
log.Printf("spice/inputs: got message type=%d", typ)
}
}
func (input *ChInputs) OnKeyDown(k []byte) {
scancode := make([]byte, 4)
copy(scancode, k)
input.conn.WriteMessage(SPICE_MSGC_INPUTS_KEY_DOWN, scancode)
}
func (input *ChInputs) OnKeyUp(k []byte) {
scancode := make([]byte, 4)
copy(scancode, k)
// AT scancode: insert 0xF0 before last byte
// XT scancode: set top bit of last part
ln := len(k)
scancode[ln-1] |= 0x80
//log.Printf("spice: sending key up %s as %+v", ev.Name, scancode)
input.conn.WriteMessage(SPICE_MSGC_INPUTS_KEY_UP, scancode)
}
func (input *ChInputs) MousePosition(x, y uint32) {
var displayID uint8
err := input.conn.WriteMessage(SPICE_MSGC_INPUTS_MOUSE_POSITION, x, y, input.btn, displayID)
if err != nil {
log.Printf("Failed to send mouse position: %s", err)
}
}
func (input *ChInputs) MouseDown(btn uint8, x, y uint32) {
state := uint16(1) << btn
if input.btn&state == state {
log.Printf("ignoring btn down %d", btn)
return // already pressed
}
input.btn |= state
input.conn.WriteMessage(SPICE_MSGC_INPUTS_MOUSE_PRESS, btn, input.btn)
}
func (input *ChInputs) MouseUp(btn uint8, x, y uint32) {
state := uint16(1) << btn
if input.btn&state == 0 {
log.Printf("ignoring btn up %d", btn)
return // already released
}
input.btn &= ^state
input.conn.WriteMessage(SPICE_MSGC_INPUTS_MOUSE_RELEASE, btn, input.btn)
}