This commit is contained in:
Siyuan Miao 2025-09-18 12:45:20 +02:00
parent b5978016af
commit 83a0dbe628
9 changed files with 35 additions and 33 deletions

View File

@ -476,7 +476,7 @@ func handleSessionRequest(
cloudLogger.Info().Interface("session", session).Msg("new session accepted") cloudLogger.Info().Interface("session", session).Msg("new session accepted")
cloudLogger.Trace().Interface("session", session).Msg("new session accepted") cloudLogger.Trace().Interface("session", session).Msg("new session accepted")
// Cancel any ongoing keyboard report multi when session changes // Cancel any ongoing keyboard macro when session changes
cancelKeyboardMacro() cancelKeyboardMacro()
currentSession = session currentSession = session

View File

@ -140,7 +140,7 @@ func reportHidRPC(params any, session *Session) {
message, err = hidrpc.NewKeyboardLedMessage(params).Marshal() message, err = hidrpc.NewKeyboardLedMessage(params).Marshal()
case usbgadget.KeysDownState: case usbgadget.KeysDownState:
message, err = hidrpc.NewKeydownStateMessage(params).Marshal() message, err = hidrpc.NewKeydownStateMessage(params).Marshal()
case hidrpc.KeyboardMacroStateReport: case hidrpc.KeyboardMacroState:
message, err = hidrpc.NewKeyboardMacroStateMessage(params.State, params.IsPaste).Marshal() message, err = hidrpc.NewKeyboardMacroStateMessage(params.State, params.IsPaste).Marshal()
default: default:
err = fmt.Errorf("unknown HID RPC message type: %T", params) err = fmt.Errorf("unknown HID RPC message type: %T", params)
@ -179,7 +179,7 @@ func (s *Session) reportHidRPCKeysDownState(state usbgadget.KeysDownState) {
reportHidRPC(state, s) reportHidRPC(state, s)
} }
func (s *Session) reportHidRPCKeyboardMacroState(state hidrpc.KeyboardMacroStateReport) { func (s *Session) reportHidRPCKeyboardMacroState(state hidrpc.KeyboardMacroState) {
if !s.hidRPCAvailable { if !s.hidRPCAvailable {
writeJSONRPCEvent("keyboardMacroState", state, s) writeJSONRPCEvent("keyboardMacroState", state, s)
} }

View File

@ -20,7 +20,7 @@ const (
TypeCancelKeyboardMacroReport MessageType = 0x08 TypeCancelKeyboardMacroReport MessageType = 0x08
TypeKeyboardLedState MessageType = 0x32 TypeKeyboardLedState MessageType = 0x32
TypeKeydownState MessageType = 0x33 TypeKeydownState MessageType = 0x33
TypeKeyboardMacroStateReport MessageType = 0x34 TypeKeyboardMacroState MessageType = 0x34
) )
const ( const (
@ -32,7 +32,7 @@ func GetQueueIndex(messageType MessageType) int {
switch messageType { switch messageType {
case TypeHandshake: case TypeHandshake:
return 0 return 0
case TypeKeyboardReport, TypeKeypressReport, TypeKeyboardMacroReport, TypeKeyboardLedState, TypeKeydownState, TypeKeyboardMacroStateReport: case TypeKeyboardReport, TypeKeypressReport, TypeKeyboardMacroReport, TypeKeyboardLedState, TypeKeydownState, TypeKeyboardMacroState:
return 1 return 1
case TypePointerReport, TypeMouseReport, TypeWheelReport: case TypePointerReport, TypeMouseReport, TypeWheelReport:
return 2 return 2
@ -116,7 +116,7 @@ func NewKeyboardMacroStateMessage(state bool, isPaste bool) *Message {
} }
return &Message{ return &Message{
t: TypeKeyboardMacroStateReport, t: TypeKeyboardMacroState,
d: data, d: data,
} }
} }

View File

@ -102,7 +102,8 @@ type KeyboardMacroReport struct {
Steps []KeyboardMacroStep Steps []KeyboardMacroStep
} }
const hidKeyBufferSize = 6 // HidKeyBufferSize is the size of the keys buffer in the keyboard report.
const HidKeyBufferSize = 6
// KeyboardMacroReport returns the keyboard macro report from the message. // KeyboardMacroReport returns the keyboard macro report from the message.
func (m *Message) KeyboardMacroReport() (KeyboardMacroReport, error) { func (m *Message) KeyboardMacroReport() (KeyboardMacroReport, error) {
@ -128,7 +129,7 @@ func (m *Message) KeyboardMacroReport() (KeyboardMacroReport, error) {
Delay: binary.BigEndian.Uint16(m.d[offset+7 : offset+9]), Delay: binary.BigEndian.Uint16(m.d[offset+7 : offset+9]),
}) })
offset += 1 + hidKeyBufferSize + 2 offset += 1 + HidKeyBufferSize + 2
} }
return KeyboardMacroReport{ return KeyboardMacroReport{
@ -186,18 +187,18 @@ func (m *Message) MouseReport() (MouseReport, error) {
}, nil }, nil
} }
type KeyboardMacroStateReport struct { type KeyboardMacroState struct {
State bool State bool
IsPaste bool IsPaste bool
} }
// KeyboardMacroStateReport returns the keyboard macro state report from the message. // KeyboardMacroState returns the keyboard macro state report from the message.
func (m *Message) KeyboardMacroStateReport() (KeyboardMacroStateReport, error) { func (m *Message) KeyboardMacroState() (KeyboardMacroState, error) {
if m.t != TypeKeyboardMacroStateReport { if m.t != TypeKeyboardMacroState {
return KeyboardMacroStateReport{}, fmt.Errorf("invalid message type: %d", m.t) return KeyboardMacroState{}, fmt.Errorf("invalid message type: %d", m.t)
} }
return KeyboardMacroStateReport{ return KeyboardMacroState{
State: m.d[0] == uint8(1), State: m.d[0] == uint8(1),
IsPaste: m.d[1] == uint8(1), IsPaste: m.d[1] == uint8(1),
}, nil }, nil

View File

@ -1082,7 +1082,7 @@ func rpcExecuteKeyboardMacro(macro []hidrpc.KeyboardMacroStep) (usbgadget.KeysDo
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
setKeyboardMacroCancel(cancel) setKeyboardMacroCancel(cancel)
s := hidrpc.KeyboardMacroStateReport{ s := hidrpc.KeyboardMacroState{
State: true, State: true,
IsPaste: true, IsPaste: true,
} }
@ -1107,7 +1107,7 @@ func rpcCancelKeyboardMacro() {
cancelKeyboardMacro() cancelKeyboardMacro()
} }
var keyboardClearStateKeys = make([]byte, 6) var keyboardClearStateKeys = make([]byte, hidrpc.HidKeyBufferSize)
func isClearKeyStep(step hidrpc.KeyboardMacroStep) bool { func isClearKeyStep(step hidrpc.KeyboardMacroStep) bool {
return step.Modifier == 0 && bytes.Equal(step.Keys, keyboardClearStateKeys) return step.Modifier == 0 && bytes.Equal(step.Keys, keyboardClearStateKeys)

View File

@ -27,7 +27,7 @@ export default function InfoBar() {
const { rpcDataChannel } = useRTCStore(); const { rpcDataChannel } = useRTCStore();
const { debugMode, mouseMode, showPressedKeys } = useSettingsStore(); const { debugMode, mouseMode, showPressedKeys } = useSettingsStore();
const { isPasteModeEnabled } = useHidStore(); const { isPasteInProgress } = useHidStore();
useEffect(() => { useEffect(() => {
if (!rpcDataChannel) return; if (!rpcDataChannel) return;
@ -109,7 +109,7 @@ export default function InfoBar() {
<span className="text-xs">{rpcHidStatus}</span> <span className="text-xs">{rpcHidStatus}</span>
</div> </div>
)} )}
{isPasteModeEnabled && ( {isPasteInProgress && (
<div className="flex w-[156px] items-center gap-x-1"> <div className="flex w-[156px] items-center gap-x-1">
<span className="text-xs font-semibold">Paste Mode:</span> <span className="text-xs font-semibold">Paste Mode:</span>
<span className="text-xs">Enabled</span> <span className="text-xs">Enabled</span>

View File

@ -17,7 +17,7 @@ import { TextAreaWithLabel } from "@components/TextArea";
export default function PasteModal() { export default function PasteModal() {
const TextAreaRef = useRef<HTMLTextAreaElement>(null); const TextAreaRef = useRef<HTMLTextAreaElement>(null);
const { isPasteModeEnabled } = useHidStore(); const { isPasteInProgress } = useHidStore();
const { setDisableVideoFocusTrap } = useUiStore(); const { setDisableVideoFocusTrap } = useUiStore();
const { send } = useJsonRpc(); const { send } = useJsonRpc();
@ -133,7 +133,8 @@ export default function PasteModal() {
<div <div
className="w-full" className="w-full"
onKeyUp={e => e.stopPropagation()} onKeyUp={e => e.stopPropagation()}
onKeyDown={e => e.stopPropagation()} onKeyDown={e => e.stopPropagation()} onKeyDownCapture={e => e.stopPropagation()}
onKeyUpCapture={e => e.stopPropagation()}
> >
<TextAreaWithLabel <TextAreaWithLabel
ref={TextAreaRef} ref={TextAreaRef}
@ -227,7 +228,7 @@ export default function PasteModal() {
size="SM" size="SM"
theme="primary" theme="primary"
text="Confirm Paste" text="Confirm Paste"
disabled={isPasteModeEnabled} disabled={isPasteInProgress}
onClick={onConfirmPaste} onClick={onConfirmPaste}
LeadingIcon={LuCornerDownLeft} LeadingIcon={LuCornerDownLeft}
/> />

View File

@ -1,4 +1,4 @@
import { KeyboardLedState, KeysDownState } from "./stores"; import { hidKeyBufferSize, KeyboardLedState, KeysDownState } from "./stores";
export const HID_RPC_MESSAGE_TYPES = { export const HID_RPC_MESSAGE_TYPES = {
Handshake: 0x01, Handshake: 0x01,
@ -11,7 +11,7 @@ export const HID_RPC_MESSAGE_TYPES = {
CancelKeyboardMacroReport: 0x08, CancelKeyboardMacroReport: 0x08,
KeyboardLedState: 0x32, KeyboardLedState: 0x32,
KeysDownState: 0x33, KeysDownState: 0x33,
KeyboardMacroStateReport: 0x34, KeyboardMacroState: 0x34,
} }
export type HidRpcMessageType = typeof HID_RPC_MESSAGE_TYPES[keyof typeof HID_RPC_MESSAGE_TYPES]; export type HidRpcMessageType = typeof HID_RPC_MESSAGE_TYPES[keyof typeof HID_RPC_MESSAGE_TYPES];
@ -31,7 +31,7 @@ const fromInt32toUint8 = (n: number) => {
(n >> 24) & 0xFF, (n >> 24) & 0xFF,
(n >> 16) & 0xFF, (n >> 16) & 0xFF,
(n >> 8) & 0xFF, (n >> 8) & 0xFF,
(n >> 0) & 0xFF, n & 0xFF,
]); ]);
}; };
@ -42,7 +42,7 @@ const fromUint16toUint8 = (n: number) => {
return new Uint8Array([ return new Uint8Array([
(n >> 8) & 0xFF, (n >> 8) & 0xFF,
(n >> 0) & 0xFF, n & 0xFF,
]); ]);
}; };
@ -55,7 +55,7 @@ const fromUint32toUint8 = (n: number) => {
(n >> 24) & 0xFF, (n >> 24) & 0xFF,
(n >> 16) & 0xFF, (n >> 16) & 0xFF,
(n >> 8) & 0xFF, (n >> 8) & 0xFF,
(n >> 0) & 0xFF, n & 0xFF,
]); ]);
}; };
@ -64,7 +64,7 @@ const fromInt8ToUint8 = (n: number) => {
throw new Error(`Number ${n} is not within the int8 range`); throw new Error(`Number ${n} is not within the int8 range`);
} }
return (n >> 0) & 0xFF; return n & 0xFF;
}; };
const keyboardLedStateMasks = { const keyboardLedStateMasks = {
@ -222,7 +222,7 @@ export class KeyboardMacroReportMessage extends RpcMessage {
stepCount: number; stepCount: number;
steps: KeyboardMacroStep[]; steps: KeyboardMacroStep[];
KEYS_LENGTH = 6; KEYS_LENGTH = hidKeyBufferSize;
constructor(isPaste: boolean, stepCount: number, steps: KeyboardMacroStep[]) { constructor(isPaste: boolean, stepCount: number, steps: KeyboardMacroStep[]) {
super(HID_RPC_MESSAGE_TYPES.KeyboardMacroReport); super(HID_RPC_MESSAGE_TYPES.KeyboardMacroReport);
@ -284,7 +284,7 @@ export class KeyboardMacroStateMessage extends RpcMessage {
isPaste: boolean; isPaste: boolean;
constructor(state: boolean, isPaste: boolean) { constructor(state: boolean, isPaste: boolean) {
super(HID_RPC_MESSAGE_TYPES.KeyboardMacroStateReport); super(HID_RPC_MESSAGE_TYPES.KeyboardMacroState);
this.state = state; this.state = state;
this.isPaste = isPaste; this.isPaste = isPaste;
} }
@ -417,7 +417,7 @@ export const messageRegistry = {
[HID_RPC_MESSAGE_TYPES.KeypressReport]: KeypressReportMessage, [HID_RPC_MESSAGE_TYPES.KeypressReport]: KeypressReportMessage,
[HID_RPC_MESSAGE_TYPES.KeyboardMacroReport]: KeyboardMacroReportMessage, [HID_RPC_MESSAGE_TYPES.KeyboardMacroReport]: KeyboardMacroReportMessage,
[HID_RPC_MESSAGE_TYPES.CancelKeyboardMacroReport]: CancelKeyboardMacroReportMessage, [HID_RPC_MESSAGE_TYPES.CancelKeyboardMacroReport]: CancelKeyboardMacroReportMessage,
[HID_RPC_MESSAGE_TYPES.KeyboardMacroStateReport]: KeyboardMacroStateMessage, [HID_RPC_MESSAGE_TYPES.KeyboardMacroState]: KeyboardMacroStateMessage,
} }
export const unmarshalHidRpcMessage = (data: Uint8Array): RpcMessage | undefined => { export const unmarshalHidRpcMessage = (data: Uint8Array): RpcMessage | undefined => {

View File

@ -470,7 +470,7 @@ export interface HidState {
isVirtualKeyboardEnabled: boolean; isVirtualKeyboardEnabled: boolean;
setVirtualKeyboardEnabled: (enabled: boolean) => void; setVirtualKeyboardEnabled: (enabled: boolean) => void;
isPasteModeEnabled: boolean; isPasteInProgress: boolean;
setPasteModeEnabled: (enabled: boolean) => void; setPasteModeEnabled: (enabled: boolean) => void;
usbState: USBStates; usbState: USBStates;
@ -487,8 +487,8 @@ export const useHidStore = create<HidState>(set => ({
isVirtualKeyboardEnabled: false, isVirtualKeyboardEnabled: false,
setVirtualKeyboardEnabled: (enabled: boolean): void => set({ isVirtualKeyboardEnabled: enabled }), setVirtualKeyboardEnabled: (enabled: boolean): void => set({ isVirtualKeyboardEnabled: enabled }),
isPasteModeEnabled: false, isPasteInProgress: false,
setPasteModeEnabled: (enabled: boolean): void => set({ isPasteModeEnabled: enabled }), setPasteModeEnabled: (enabled: boolean): void => set({ isPasteInProgress: enabled }),
// Add these new properties for USB state // Add these new properties for USB state
usbState: "not attached", usbState: "not attached",