mirror of https://github.com/jetkvm/kvm.git
208 lines
5.0 KiB
Go
208 lines
5.0 KiB
Go
package hidrpc
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
)
|
|
|
|
// Message ..
|
|
type Message struct {
|
|
t MessageType
|
|
d []byte
|
|
}
|
|
|
|
// Marshal marshals the message to a byte array.
|
|
func (m *Message) Marshal() ([]byte, error) {
|
|
return Marshal(m)
|
|
}
|
|
|
|
func (m *Message) Type() MessageType {
|
|
return m.t
|
|
}
|
|
|
|
func (m *Message) String() string {
|
|
switch m.t {
|
|
case TypeHandshake:
|
|
return "Handshake"
|
|
case TypeKeypressReport:
|
|
if len(m.d) < 2 {
|
|
return fmt.Sprintf("KeypressReport{Malformed: %v}", m.d)
|
|
}
|
|
return fmt.Sprintf("KeypressReport{Key: %d, Press: %v}", m.d[0], m.d[1] == uint8(1))
|
|
case TypeKeyboardReport:
|
|
if len(m.d) < 2 {
|
|
return fmt.Sprintf("KeyboardReport{Malformed: %v}", m.d)
|
|
}
|
|
return fmt.Sprintf("KeyboardReport{Modifier: %d, Keys: %v}", m.d[0], m.d[1:])
|
|
case TypePointerReport:
|
|
if len(m.d) < 9 {
|
|
return fmt.Sprintf("PointerReport{Malformed: %v}", m.d)
|
|
}
|
|
return fmt.Sprintf("PointerReport{X: %d, Y: %d, Button: %d}", m.d[0:4], m.d[4:8], m.d[8])
|
|
case TypeMouseReport:
|
|
if len(m.d) < 3 {
|
|
return fmt.Sprintf("MouseReport{Malformed: %v}", m.d)
|
|
}
|
|
return fmt.Sprintf("MouseReport{DX: %d, DY: %d, Button: %d}", m.d[0], m.d[1], m.d[2])
|
|
case TypeKeypressKeepAliveReport:
|
|
return "KeypressKeepAliveReport"
|
|
case TypeKeyboardMacroReport:
|
|
if len(m.d) < 5 {
|
|
return fmt.Sprintf("KeyboardMacroReport{Malformed: %v}", m.d)
|
|
}
|
|
return fmt.Sprintf("KeyboardMacroReport{IsPaste: %v, Length: %d}", m.d[0] == uint8(1), binary.BigEndian.Uint32(m.d[1:5]))
|
|
default:
|
|
return fmt.Sprintf("Unknown{Type: %d, Data: %v}", m.t, m.d)
|
|
}
|
|
}
|
|
|
|
// KeypressReport ..
|
|
type KeypressReport struct {
|
|
Key byte
|
|
Press bool
|
|
}
|
|
|
|
// KeypressReport returns the keypress report from the message.
|
|
func (m *Message) KeypressReport() (KeypressReport, error) {
|
|
if m.t != TypeKeypressReport {
|
|
return KeypressReport{}, fmt.Errorf("invalid message type: %d", m.t)
|
|
}
|
|
|
|
return KeypressReport{
|
|
Key: m.d[0],
|
|
Press: m.d[1] == uint8(1),
|
|
}, nil
|
|
}
|
|
|
|
// KeyboardReport ..
|
|
type KeyboardReport struct {
|
|
Modifier byte
|
|
Keys []byte
|
|
}
|
|
|
|
// KeyboardReport returns the keyboard report from the message.
|
|
func (m *Message) KeyboardReport() (KeyboardReport, error) {
|
|
if m.t != TypeKeyboardReport {
|
|
return KeyboardReport{}, fmt.Errorf("invalid message type: %d", m.t)
|
|
}
|
|
|
|
return KeyboardReport{
|
|
Modifier: m.d[0],
|
|
Keys: m.d[1:],
|
|
}, nil
|
|
}
|
|
|
|
// Macro ..
|
|
type KeyboardMacroStep struct {
|
|
Modifier byte // 1 byte
|
|
Keys []byte // 6 bytes: hidKeyBufferSize
|
|
Delay uint16 // 2 bytes
|
|
}
|
|
type KeyboardMacroReport struct {
|
|
IsPaste bool
|
|
StepCount uint32
|
|
Steps []KeyboardMacroStep
|
|
}
|
|
|
|
// HidKeyBufferSize is the size of the keys buffer in the keyboard report.
|
|
const HidKeyBufferSize = 6
|
|
|
|
// KeyboardMacroReport returns the keyboard macro report from the message.
|
|
func (m *Message) KeyboardMacroReport() (KeyboardMacroReport, error) {
|
|
if m.t != TypeKeyboardMacroReport {
|
|
return KeyboardMacroReport{}, fmt.Errorf("invalid message type: %d", m.t)
|
|
}
|
|
|
|
isPaste := m.d[0] == uint8(1)
|
|
stepCount := binary.BigEndian.Uint32(m.d[1:5])
|
|
|
|
// check total length
|
|
expectedLength := int(stepCount)*9 + 5
|
|
if len(m.d) != expectedLength {
|
|
return KeyboardMacroReport{}, fmt.Errorf("invalid length: %d, expected: %d", len(m.d), expectedLength)
|
|
}
|
|
|
|
steps := make([]KeyboardMacroStep, 0, int(stepCount))
|
|
offset := 5
|
|
for i := 0; i < int(stepCount); i++ {
|
|
steps = append(steps, KeyboardMacroStep{
|
|
Modifier: m.d[offset],
|
|
Keys: m.d[offset+1 : offset+7],
|
|
Delay: binary.BigEndian.Uint16(m.d[offset+7 : offset+9]),
|
|
})
|
|
|
|
offset += 1 + HidKeyBufferSize + 2
|
|
}
|
|
|
|
return KeyboardMacroReport{
|
|
IsPaste: isPaste,
|
|
Steps: steps,
|
|
StepCount: stepCount,
|
|
}, nil
|
|
}
|
|
|
|
// PointerReport ..
|
|
type PointerReport struct {
|
|
X int
|
|
Y int
|
|
Button uint8
|
|
}
|
|
|
|
func toInt(b []byte) int {
|
|
return int(b[0])<<24 + int(b[1])<<16 + int(b[2])<<8 + int(b[3])<<0
|
|
}
|
|
|
|
// PointerReport returns the point report from the message.
|
|
func (m *Message) PointerReport() (PointerReport, error) {
|
|
if m.t != TypePointerReport {
|
|
return PointerReport{}, fmt.Errorf("invalid message type: %d", m.t)
|
|
}
|
|
|
|
if len(m.d) != 9 {
|
|
return PointerReport{}, fmt.Errorf("invalid message length: %d", len(m.d))
|
|
}
|
|
|
|
return PointerReport{
|
|
X: toInt(m.d[0:4]),
|
|
Y: toInt(m.d[4:8]),
|
|
Button: uint8(m.d[8]),
|
|
}, nil
|
|
}
|
|
|
|
// MouseReport ..
|
|
type MouseReport struct {
|
|
DX int8
|
|
DY int8
|
|
Button uint8
|
|
}
|
|
|
|
// MouseReport returns the mouse report from the message.
|
|
func (m *Message) MouseReport() (MouseReport, error) {
|
|
if m.t != TypeMouseReport {
|
|
return MouseReport{}, fmt.Errorf("invalid message type: %d", m.t)
|
|
}
|
|
|
|
return MouseReport{
|
|
DX: int8(m.d[0]),
|
|
DY: int8(m.d[1]),
|
|
Button: uint8(m.d[2]),
|
|
}, nil
|
|
}
|
|
|
|
type KeyboardMacroState struct {
|
|
State bool
|
|
IsPaste bool
|
|
}
|
|
|
|
// KeyboardMacroState returns the keyboard macro state report from the message.
|
|
func (m *Message) KeyboardMacroState() (KeyboardMacroState, error) {
|
|
if m.t != TypeKeyboardMacroState {
|
|
return KeyboardMacroState{}, fmt.Errorf("invalid message type: %d", m.t)
|
|
}
|
|
|
|
return KeyboardMacroState{
|
|
State: m.d[0] == uint8(1),
|
|
IsPaste: m.d[1] == uint8(1),
|
|
}, nil
|
|
}
|