Compare commits

..

2 Commits

Author SHA1 Message Date
Marc Brooks 4b9b0a64e9
Merge 0dd7098821 into 608f69db13 2025-08-14 02:48:11 +00:00
Marc Brooks 0dd7098821
Use the KeysDownState for the infobar
Strong typed in the typescript realm.
2025-08-13 21:46:37 -05:00
10 changed files with 48 additions and 78 deletions

View File

@ -100,7 +100,7 @@ func getKeyboardState(b byte) KeyboardState {
} }
} }
func (u *UsbGadget) updateKeyboardState(state byte) { func (u *UsbGadget) updateKeyboardState(state uint8) {
u.keyboardStateLock.Lock() u.keyboardStateLock.Lock()
defer u.keyboardStateLock.Unlock() defer u.keyboardStateLock.Unlock()
@ -185,7 +185,7 @@ func (u *UsbGadget) listenKeyboardEvents() {
l.Trace().Msg("starting") l.Trace().Msg("starting")
go func() { go func() {
buf := make([]byte, hidReadBufferSize) buf := make([]uint8, hidReadBufferSize)
for { for {
select { select {
case <-u.keyboardStateCtx.Done(): case <-u.keyboardStateCtx.Done():
@ -245,12 +245,12 @@ func (u *UsbGadget) OpenKeyboardHidFile() error {
return u.openKeyboardHidFile() return u.openKeyboardHidFile()
} }
func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error { func (u *UsbGadget) keyboardWriteHidFile(modifier uint8, keys []uint8) error {
if err := u.openKeyboardHidFile(); err != nil { if err := u.openKeyboardHidFile(); err != nil {
return err return err
} }
_, err := u.keyboardHidFile.Write(append([]byte{modifier, 0x00}, keys[:hidKeyBufferSize]...)) _, err := u.keyboardHidFile.Write(append([]uint8{modifier, 0x00}, keys[:hidKeyBufferSize]...))
if err != nil { if err != nil {
u.logWithSuppression("keyboardWriteHidFile", 100, u.log, err, "failed to write to hidg0") u.logWithSuppression("keyboardWriteHidFile", 100, u.log, err, "failed to write to hidg0")
u.keyboardHidFile.Close() u.keyboardHidFile.Close()
@ -261,7 +261,7 @@ func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error {
return nil return nil
} }
func (u *UsbGadget) KeyboardReport(modifier byte, keys []byte) error { func (u *UsbGadget) KeyboardReport(modifier uint8, keys []uint8) error {
u.keyboardLock.Lock() u.keyboardLock.Lock()
defer u.keyboardLock.Unlock() defer u.keyboardLock.Unlock()
defer u.resetUserInputTime() defer u.resetUserInputTime()
@ -270,7 +270,7 @@ func (u *UsbGadget) KeyboardReport(modifier byte, keys []byte) error {
keys = keys[:hidKeyBufferSize] keys = keys[:hidKeyBufferSize]
} }
if len(keys) < hidKeyBufferSize { if len(keys) < hidKeyBufferSize {
keys = append(keys, make([]byte, hidKeyBufferSize-len(keys))...) keys = append(keys, make([]uint8, hidKeyBufferSize-len(keys))...)
} }
return u.keyboardWriteHidFile(modifier, keys) return u.keyboardWriteHidFile(modifier, keys)
@ -290,7 +290,7 @@ const (
) )
// KeyCodeToMaskMap is a slice of KeyCodeMask for quick lookup // KeyCodeToMaskMap is a slice of KeyCodeMask for quick lookup
var KeyCodeToMaskMap = map[byte]byte{ var KeyCodeToMaskMap = map[uint8]uint8{
LeftControl: ModifierMaskLeftControl, LeftControl: ModifierMaskLeftControl,
LeftShift: ModifierMaskLeftShift, LeftShift: ModifierMaskLeftShift,
LeftAlt: ModifierMaskLeftAlt, LeftAlt: ModifierMaskLeftAlt,
@ -301,14 +301,14 @@ var KeyCodeToMaskMap = map[byte]byte{
RightSuper: ModifierMaskRightSuper, RightSuper: ModifierMaskRightSuper,
} }
func (u *UsbGadget) KeypressReport(key byte, press bool) (KeysDownState, error) { func (u *UsbGadget) KeypressReport(key uint8, press bool) (KeysDownState, error) {
u.keyboardLock.Lock() u.keyboardLock.Lock()
defer u.keyboardLock.Unlock() defer u.keyboardLock.Unlock()
defer u.resetUserInputTime() defer u.resetUserInputTime()
var state = u.keysDownState var state = u.keysDownState
modifier := state.Modifier modifier := state.Modifier
keys := append([]byte(nil), state.Keys...) keys := state.Keys[:]
if mask, exists := KeyCodeToMaskMap[key]; exists { if mask, exists := KeyCodeToMaskMap[key]; exists {
// If the key is a modifier key, we update the keyboardModifier state // If the key is a modifier key, we update the keyboardModifier state
@ -361,12 +361,10 @@ func (u *UsbGadget) KeypressReport(key byte, press bool) (KeysDownState, error)
u.log.Warn().Uint8("modifier", modifier).Uints8("keys", keys).Msg("Could not write keypress report to hidg0") u.log.Warn().Uint8("modifier", modifier).Uints8("keys", keys).Msg("Could not write keypress report to hidg0")
} }
var result = KeysDownState{ state.Modifier = modifier
Modifier: modifier, state.Keys = keys
Keys: []byte(keys[:]),
}
u.updateKeyDownState(result) u.updateKeyDownState(state)
return result, nil return state, nil
} }

View File

@ -85,17 +85,17 @@ func (u *UsbGadget) absMouseWriteHidFile(data []byte) error {
return nil return nil
} }
func (u *UsbGadget) AbsMouseReport(x int, y int, buttons uint8) error { func (u *UsbGadget) AbsMouseReport(x, y int, buttons uint8) error {
u.absMouseLock.Lock() u.absMouseLock.Lock()
defer u.absMouseLock.Unlock() defer u.absMouseLock.Unlock()
err := u.absMouseWriteHidFile([]byte{ err := u.absMouseWriteHidFile([]byte{
1, // Report ID 1 1, // Report ID 1
buttons, // Buttons buttons, // Buttons
byte(x), // X Low Byte uint8(x), // X Low Byte
byte(x >> 8), // X High Byte uint8(x >> 8), // X High Byte
byte(y), // Y Low Byte uint8(y), // Y Low Byte
byte(y >> 8), // Y High Byte uint8(y >> 8), // Y High Byte
}) })
if err != nil { if err != nil {
return err return err

View File

@ -75,14 +75,14 @@ func (u *UsbGadget) relMouseWriteHidFile(data []byte) error {
return nil return nil
} }
func (u *UsbGadget) RelMouseReport(mx int8, my int8, buttons uint8) error { func (u *UsbGadget) RelMouseReport(mx, my int8, buttons uint8) error {
u.relMouseLock.Lock() u.relMouseLock.Lock()
defer u.relMouseLock.Unlock() defer u.relMouseLock.Unlock()
err := u.relMouseWriteHidFile([]byte{ err := u.relMouseWriteHidFile([]byte{
buttons, // Buttons buttons, // Buttons
byte(mx), // X uint8(mx), // X
byte(my), // Y uint8(my), // Y
0, // Wheel 0, // Wheel
}) })
if err != nil { if err != nil {

View File

@ -42,8 +42,8 @@ var defaultUsbGadgetDevices = Devices{
} }
type KeysDownState struct { type KeysDownState struct {
Modifier byte `json:"modifier"` Modifier uint8 `json:"modifier"`
Keys ByteSlice `json:"keys"` Keys []uint8 `json:"keys"`
} }
// UsbGadget is a struct that represents a USB gadget. // UsbGadget is a struct that represents a USB gadget.
@ -65,7 +65,7 @@ type UsbGadget struct {
relMouseHidFile *os.File relMouseHidFile *os.File
relMouseLock sync.Mutex relMouseLock sync.Mutex
keyboardState byte // keyboard latched state (NumLock, CapsLock, ScrollLock, Compose, Kana) keyboardState uint8 // keyboard latched state (NumLock, CapsLock, ScrollLock, Compose, Kana)
keysDownState KeysDownState // keyboard dynamic state (modifier keys and pressed keys) keysDownState KeysDownState // keyboard dynamic state (modifier keys and pressed keys)
keyboardStateLock sync.Mutex keyboardStateLock sync.Mutex
@ -131,7 +131,7 @@ func newUsbGadget(name string, configMap map[string]gadgetConfigItem, enabledDev
keyboardStateCtx: keyboardCtx, keyboardStateCtx: keyboardCtx,
keyboardStateCancel: keyboardCancel, keyboardStateCancel: keyboardCancel,
keyboardState: 0, keyboardState: 0,
keysDownState: KeysDownState{Modifier: 0, Keys: []byte{0, 0, 0, 0, 0, 0}}, // must be initialized to hidKeyBufferSize (6) zero bytes keysDownState: KeysDownState{Modifier: 0, Keys: []uint8{0, 0, 0, 0, 0, 0}}, // must be initialized to hidKeyBufferSize (6) zero bytes
enabledDevices: *enabledDevices, enabledDevices: *enabledDevices,
lastUserInput: time.Now(), lastUserInput: time.Now(),
log: logger, log: logger,

View File

@ -2,7 +2,6 @@ package usbgadget
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"path/filepath" "path/filepath"
"strconv" "strconv"
@ -11,31 +10,6 @@ import (
"github.com/rs/zerolog" "github.com/rs/zerolog"
) )
type ByteSlice []byte
func (s ByteSlice) MarshalJSON() ([]byte, error) {
vals := make([]int, len(s))
for i, v := range s {
vals[i] = int(v)
}
return json.Marshal(vals)
}
func (s *ByteSlice) UnmarshalJSON(data []byte) error {
var vals []int
if err := json.Unmarshal(data, &vals); err != nil {
return err
}
*s = make([]byte, len(vals))
for i, v := range vals {
if v < 0 || v > 255 {
return fmt.Errorf("value %d out of byte range", v)
}
(*s)[i] = byte(v)
}
return nil
}
func joinPath(basePath string, paths []string) string { func joinPath(basePath string, paths []string) string {
pathArr := append([]string{basePath}, paths...) pathArr := append([]string{basePath}, paths...)
return filepath.Join(pathArr...) return filepath.Join(pathArr...)

View File

@ -566,7 +566,7 @@ func riskyCallRPCHandler(logger zerolog.Logger, handler RPCHandler, params map[s
} }
} }
logger.Trace().Msg("Calling RPC handler") logger.Trace().Interface("args", args).Msg("Calling RPC handler")
results := handlerValue.Call(args) results := handlerValue.Call(args)
if len(results) == 0 { if len(results) == 0 {

View File

@ -11,14 +11,10 @@ import { useJsonRpc } from "@/hooks/useJsonRpc";
import { cx } from "@/cva.config"; import { cx } from "@/cva.config";
import { keys } from "@/keyboardMappings"; import { keys } from "@/keyboardMappings";
import { import {
MouseState,
RTCState,
SettingsState,
useMouseStore, useMouseStore,
useRTCStore, useRTCStore,
useSettingsStore, useSettingsStore,
useVideoStore, useVideoStore,
VideoState,
} from "@/hooks/stores"; } from "@/hooks/stores";
import { import {
@ -31,15 +27,15 @@ import {
export default function WebRTCVideo() { export default function WebRTCVideo() {
// Video and stream related refs and states // Video and stream related refs and states
const videoElm = useRef<HTMLVideoElement>(null); const videoElm = useRef<HTMLVideoElement>(null);
const mediaStream = useRTCStore((state: RTCState) => state.mediaStream); const mediaStream = useRTCStore(state => state.mediaStream);
const [isPlaying, setIsPlaying] = useState(false); const [isPlaying, setIsPlaying] = useState(false);
const peerConnectionState = useRTCStore((state: RTCState) => state.peerConnectionState); const peerConnectionState = useRTCStore(state => state.peerConnectionState);
const [isPointerLockActive, setIsPointerLockActive] = useState(false); const [isPointerLockActive, setIsPointerLockActive] = useState(false);
// Store hooks // Store hooks
const settings = useSettingsStore(); const settings = useSettingsStore();
const { sendKeypressEvent, resetKeyboardState } = useKeyboard(); const { sendKeypressEvent, resetKeyboardState } = useKeyboard();
const setMousePosition = useMouseStore((state: MouseState) => state.setMousePosition); const setMousePosition = useMouseStore(state => state.setMousePosition);
const setMouseMove = useMouseStore((state: MouseState) => state.setMouseMove); const setMouseMove = useMouseStore(state => state.setMouseMove);
const { const {
setClientSize: setVideoClientSize, setClientSize: setVideoClientSize,
setSize: setVideoSize, setSize: setVideoSize,
@ -50,15 +46,15 @@ export default function WebRTCVideo() {
} = useVideoStore(); } = useVideoStore();
// Video enhancement settings // Video enhancement settings
const videoSaturation = useSettingsStore((state: SettingsState) => state.videoSaturation); const videoSaturation = useSettingsStore(state => state.videoSaturation);
const videoBrightness = useSettingsStore((state: SettingsState) => state.videoBrightness); const videoBrightness = useSettingsStore(state => state.videoBrightness);
const videoContrast = useSettingsStore((state: SettingsState) => state.videoContrast); const videoContrast = useSettingsStore(state => state.videoContrast);
// RTC related states // RTC related states
const peerConnection = useRTCStore((state: RTCState ) => state.peerConnection); const peerConnection = useRTCStore(state => state.peerConnection);
// HDMI and UI states // HDMI and UI states
const hdmiState = useVideoStore((state: VideoState) => state.hdmiState); const hdmiState = useVideoStore(state => state.hdmiState);
const hdmiError = ["no_lock", "no_signal", "out_of_range"].includes(hdmiState); const hdmiError = ["no_lock", "no_signal", "out_of_range"].includes(hdmiState);
const isVideoLoading = !isPlaying; const isVideoLoading = !isPlaying;

View File

@ -31,7 +31,9 @@ export default function useKeyboard() {
if ("error" in resp) { if ("error" in resp) {
console.error("Failed to send keypress:", resp.error); console.error("Failed to send keypress:", resp.error);
} else { } else {
console.log(resp);
const keyDownState = resp.result as KeysDownState; const keyDownState = resp.result as KeysDownState;
console.log("Key Down State:", keyDownState);
// We do this for the info bar to display the currently pressed keys for the user // We do this for the info bar to display the currently pressed keys for the user
setKeysDownState(keyDownState); setKeysDownState(keyDownState);
} }

View File

@ -661,7 +661,7 @@ export default function KvmIdRoute() {
useEffect(() => { useEffect(() => {
if (rpcDataChannel?.readyState !== "open") return; if (rpcDataChannel?.readyState !== "open") return;
send("getVideoState", {}, (resp: JsonRpcResponse) => { send("getVideoState", {}, resp => {
if ("error" in resp) return; if ("error" in resp) return;
setHdmiState(resp.result as Parameters<VideoState["setHdmiState"]>[0]); setHdmiState(resp.result as Parameters<VideoState["setHdmiState"]>[0]);
}); });
@ -673,7 +673,7 @@ export default function KvmIdRoute() {
if (keyboardLedState !== undefined) return; if (keyboardLedState !== undefined) return;
console.log("Requesting keyboard led state"); console.log("Requesting keyboard led state");
send("getKeyboardLedState", {}, (resp: JsonRpcResponse) => { send("getKeyboardLedState", {}, resp => {
if ("error" in resp) { if ("error" in resp) {
console.error("Failed to get keyboard led state", resp.error); console.error("Failed to get keyboard led state", resp.error);
return; return;
@ -689,7 +689,7 @@ export default function KvmIdRoute() {
if (keysDownState !== undefined) return; if (keysDownState !== undefined) return;
console.log("Requesting keys down state"); console.log("Requesting keys down state");
send("getKeyDownState", {}, (resp: JsonRpcResponse) => { send("getKeyDownState", {}, resp => {
if ("error" in resp) { if ("error" in resp) {
console.error("Failed to get key down state", resp.error); console.error("Failed to get key down state", resp.error);
return; return;

8
usb.go
View File

@ -43,19 +43,19 @@ func initUsbGadget() {
} }
} }
func rpcKeyboardReport(modifier byte, keys []byte) error { func rpcKeyboardReport(modifier uint8, keys []uint8) error {
return gadget.KeyboardReport(modifier, keys) return gadget.KeyboardReport(modifier, keys)
} }
func rpcKeypressReport(key byte, press bool) (usbgadget.KeysDownState, error) { func rpcKeypressReport(key uint8, press bool) (usbgadget.KeysDownState, error) {
return gadget.KeypressReport(key, press) return gadget.KeypressReport(key, press)
} }
func rpcAbsMouseReport(x int, y int, buttons uint8) error { func rpcAbsMouseReport(x, y int, buttons uint8) error {
return gadget.AbsMouseReport(x, y, buttons) return gadget.AbsMouseReport(x, y, buttons)
} }
func rpcRelMouseReport(dx int8, dy int8, buttons uint8) error { func rpcRelMouseReport(dx, dy int8, buttons uint8) error {
return gadget.RelMouseReport(dx, dy, buttons) return gadget.RelMouseReport(dx, dy, buttons)
} }