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()
defer u.keyboardStateLock.Unlock()
@ -185,7 +185,7 @@ func (u *UsbGadget) listenKeyboardEvents() {
l.Trace().Msg("starting")
go func() {
buf := make([]byte, hidReadBufferSize)
buf := make([]uint8, hidReadBufferSize)
for {
select {
case <-u.keyboardStateCtx.Done():
@ -245,12 +245,12 @@ func (u *UsbGadget) OpenKeyboardHidFile() error {
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 {
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 {
u.logWithSuppression("keyboardWriteHidFile", 100, u.log, err, "failed to write to hidg0")
u.keyboardHidFile.Close()
@ -261,7 +261,7 @@ func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error {
return nil
}
func (u *UsbGadget) KeyboardReport(modifier byte, keys []byte) error {
func (u *UsbGadget) KeyboardReport(modifier uint8, keys []uint8) error {
u.keyboardLock.Lock()
defer u.keyboardLock.Unlock()
defer u.resetUserInputTime()
@ -270,7 +270,7 @@ func (u *UsbGadget) KeyboardReport(modifier byte, keys []byte) error {
keys = 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)
@ -290,7 +290,7 @@ const (
)
// KeyCodeToMaskMap is a slice of KeyCodeMask for quick lookup
var KeyCodeToMaskMap = map[byte]byte{
var KeyCodeToMaskMap = map[uint8]uint8{
LeftControl: ModifierMaskLeftControl,
LeftShift: ModifierMaskLeftShift,
LeftAlt: ModifierMaskLeftAlt,
@ -301,14 +301,14 @@ var KeyCodeToMaskMap = map[byte]byte{
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()
defer u.keyboardLock.Unlock()
defer u.resetUserInputTime()
var state = u.keysDownState
modifier := state.Modifier
keys := append([]byte(nil), state.Keys...)
keys := state.Keys[:]
if mask, exists := KeyCodeToMaskMap[key]; exists {
// 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")
}
var result = KeysDownState{
Modifier: modifier,
Keys: []byte(keys[:]),
}
state.Modifier = modifier
state.Keys = 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
}
func (u *UsbGadget) AbsMouseReport(x int, y int, buttons uint8) error {
func (u *UsbGadget) AbsMouseReport(x, y int, buttons uint8) error {
u.absMouseLock.Lock()
defer u.absMouseLock.Unlock()
err := u.absMouseWriteHidFile([]byte{
1, // Report ID 1
buttons, // Buttons
byte(x), // X Low Byte
byte(x >> 8), // X High Byte
byte(y), // Y Low Byte
byte(y >> 8), // Y High Byte
1, // Report ID 1
buttons, // Buttons
uint8(x), // X Low Byte
uint8(x >> 8), // X High Byte
uint8(y), // Y Low Byte
uint8(y >> 8), // Y High Byte
})
if err != nil {
return err

View File

@ -75,15 +75,15 @@ func (u *UsbGadget) relMouseWriteHidFile(data []byte) error {
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()
defer u.relMouseLock.Unlock()
err := u.relMouseWriteHidFile([]byte{
buttons, // Buttons
byte(mx), // X
byte(my), // Y
0, // Wheel
buttons, // Buttons
uint8(mx), // X
uint8(my), // Y
0, // Wheel
})
if err != nil {
return err

View File

@ -42,8 +42,8 @@ var defaultUsbGadgetDevices = Devices{
}
type KeysDownState struct {
Modifier byte `json:"modifier"`
Keys ByteSlice `json:"keys"`
Modifier uint8 `json:"modifier"`
Keys []uint8 `json:"keys"`
}
// UsbGadget is a struct that represents a USB gadget.
@ -65,7 +65,7 @@ type UsbGadget struct {
relMouseHidFile *os.File
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)
keyboardStateLock sync.Mutex
@ -131,7 +131,7 @@ func newUsbGadget(name string, configMap map[string]gadgetConfigItem, enabledDev
keyboardStateCtx: keyboardCtx,
keyboardStateCancel: keyboardCancel,
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,
lastUserInput: time.Now(),
log: logger,

View File

@ -2,7 +2,6 @@ package usbgadget
import (
"bytes"
"encoding/json"
"fmt"
"path/filepath"
"strconv"
@ -11,31 +10,6 @@ import (
"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 {
pathArr := append([]string{basePath}, paths...)
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)
if len(results) == 0 {

View File

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

View File

@ -31,7 +31,9 @@ export default function useKeyboard() {
if ("error" in resp) {
console.error("Failed to send keypress:", resp.error);
} else {
console.log(resp);
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
setKeysDownState(keyDownState);
}

View File

@ -661,7 +661,7 @@ export default function KvmIdRoute() {
useEffect(() => {
if (rpcDataChannel?.readyState !== "open") return;
send("getVideoState", {}, (resp: JsonRpcResponse) => {
send("getVideoState", {}, resp => {
if ("error" in resp) return;
setHdmiState(resp.result as Parameters<VideoState["setHdmiState"]>[0]);
});
@ -673,7 +673,7 @@ export default function KvmIdRoute() {
if (keyboardLedState !== undefined) return;
console.log("Requesting keyboard led state");
send("getKeyboardLedState", {}, (resp: JsonRpcResponse) => {
send("getKeyboardLedState", {}, resp => {
if ("error" in resp) {
console.error("Failed to get keyboard led state", resp.error);
return;
@ -689,7 +689,7 @@ export default function KvmIdRoute() {
if (keysDownState !== undefined) return;
console.log("Requesting keys down state");
send("getKeyDownState", {}, (resp: JsonRpcResponse) => {
send("getKeyDownState", {}, resp => {
if ("error" in resp) {
console.error("Failed to get key down state", resp.error);
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)
}
func rpcKeypressReport(key byte, press bool) (usbgadget.KeysDownState, error) {
func rpcKeypressReport(key uint8, press bool) (usbgadget.KeysDownState, error) {
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)
}
func rpcRelMouseReport(dx int8, dy int8, buttons uint8) error {
func rpcRelMouseReport(dx, dy int8, buttons uint8) error {
return gadget.RelMouseReport(dx, dy, buttons)
}