Compare commits

..

No commits in common. "8e00b3d581c24ba29d126f8716dd591ea0741d10" and "f9dcee1377cafcf378522b4629778b3aad5bdd85" have entirely different histories.

19 changed files with 41 additions and 39 deletions

View File

@ -42,17 +42,16 @@ const (
func GetQueueIndex(messageType MessageType) (int, time.Duration) {
switch messageType {
case TypeHandshake:
return HandshakeQueue, 1 * time.Second
return HandshakeQueue, 1
case TypeKeyboardReport, TypeKeypressReport, TypeKeyboardLedState, TypeKeydownState, TypeKeyboardMacroState:
return KeyboardQueue, 1 * time.Second
return KeyboardQueue, 1
case TypePointerReport, TypeMouseReport, TypeWheelReport:
return MouseQueue, 1 * time.Second
return MouseQueue, 1
// we don't want to block the queue for these messages
case TypeKeyboardMacroReport, TypeCancelKeyboardMacroReport, TypeKeyboardMacroTokenState:
return MacroQueue, 60 * time.Second
return MacroQueue, 60 // 1 minute timeout
default:
return OtherQueue, 5 * time.Second
return OtherQueue, 5
}
}

View File

@ -5,7 +5,6 @@ import (
"fmt"
"github.com/google/uuid"
"github.com/jetkvm/kvm/internal/usbgadget"
)
// Message ..
@ -136,16 +135,18 @@ func (m *Message) KeyboardReport() (KeyboardReport, error) {
// Macro ..
type KeyboardMacroStep struct {
Modifier byte // 1 byte
Keys []byte // 6 bytes: usbgadget.HidKeyBufferSize
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 int = 6
// KeyboardMacroReport returns the keyboard macro report from the message.
func (m *Message) KeyboardMacroReport() (KeyboardMacroReport, error) {
if m.t != TypeKeyboardMacroReport {
@ -170,7 +171,7 @@ func (m *Message) KeyboardMacroReport() (KeyboardMacroReport, error) {
Delay: binary.BigEndian.Uint16(m.d[offset+7 : offset+9]),
})
offset += 1 + usbgadget.HidKeyBufferSize + 2
offset += 1 + HidKeyBufferSize + 2
}
return KeyboardMacroReport{

View File

@ -76,7 +76,7 @@ var keyboardReportDesc = []byte{
const (
hidReadBufferSize = 8
HidKeyBufferSize = 6
hidKeyBufferSize = 6
hidErrorRollOver = 0x01
// https://www.usb.org/sites/default/files/documents/hid1_11.pdf
// https://www.usb.org/sites/default/files/hut1_2.pdf
@ -161,18 +161,13 @@ func (u *UsbGadget) SetOnKeysDownChange(f func(state KeysDownState)) {
}
var suspendedKeyDownMessages bool = false
var suspendedKeyDownMessagesLock sync.Mutex
func (u *UsbGadget) SuspendKeyDownMessages() {
suspendedKeyDownMessagesLock.Lock()
suspendedKeyDownMessages = true
suspendedKeyDownMessagesLock.Unlock()
}
func (u *UsbGadget) ResumeSuspendKeyDownMessages() {
suspendedKeyDownMessagesLock.Lock()
suspendedKeyDownMessages = false
suspendedKeyDownMessagesLock.Unlock()
}
func (u *UsbGadget) SetOnKeepAliveReset(f func()) {
@ -342,7 +337,7 @@ func (u *UsbGadget) keyboardWriteHidFile(modifier byte, keys []byte) error {
return err
}
_, err := u.writeWithTimeout(u.keyboardHidFile, append([]byte{modifier, 0x00}, keys[:HidKeyBufferSize]...))
_, err := u.writeWithTimeout(u.keyboardHidFile, append([]byte{modifier, 0x00}, keys[:hidKeyBufferSize]...))
if err != nil {
u.logWithSuppression("keyboardWriteHidFile", 100, u.log, err, "failed to write to hidg0")
u.keyboardHidFile.Close()
@ -386,11 +381,11 @@ func (u *UsbGadget) UpdateKeysDown(modifier byte, keys []byte) KeysDownState {
func (u *UsbGadget) KeyboardReport(modifier byte, keys []byte) error {
defer u.resetUserInputTime()
if len(keys) > HidKeyBufferSize {
keys = keys[:HidKeyBufferSize]
if len(keys) > hidKeyBufferSize {
keys = keys[:hidKeyBufferSize]
}
if len(keys) < HidKeyBufferSize {
keys = append(keys, make([]byte, HidKeyBufferSize-len(keys))...)
if len(keys) < hidKeyBufferSize {
keys = append(keys, make([]byte, hidKeyBufferSize-len(keys))...)
}
err := u.keyboardWriteHidFile(modifier, keys)
@ -473,7 +468,7 @@ func (u *UsbGadget) keypressReport(key byte, press bool) (KeysDownState, error)
// handle other keys that are not modifier keys by placing or removing them
// from the key buffer since the buffer tracks currently pressed keys
overrun := true
for i := range HidKeyBufferSize {
for i := range hidKeyBufferSize {
// If we find the key in the buffer the buffer, we either remove it (if press is false)
// or do nothing (if down is true) because the buffer tracks currently pressed keys
// and if we find a zero byte, we can place the key there (if press is true)
@ -484,7 +479,7 @@ func (u *UsbGadget) keypressReport(key byte, press bool) (KeysDownState, error)
// we are releasing the key, remove it from the buffer
if keys[i] != 0 {
copy(keys[i:], keys[i+1:])
keys[HidKeyBufferSize-1] = 0 // Clear the last byte
keys[hidKeyBufferSize-1] = 0 // Clear the last byte
}
}
overrun = false // We found a slot for the key

View File

@ -135,7 +135,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 usbgadget.HidKeyBufferSize (6) zero bytes
keysDownState: KeysDownState{Modifier: 0, Keys: []byte{0, 0, 0, 0, 0, 0}}, // must be initialized to hidKeyBufferSize (6) zero bytes
kbdAutoReleaseTimers: make(map[byte]*time.Timer),
enabledDevices: *enabledDevices,
lastUserInput: time.Now(),

View File

@ -1210,7 +1210,7 @@ func executeKeyboardMacro(ctx context.Context, isPaste bool, macro []hidrpc.Keyb
case <-ctx.Done():
// make sure keyboard state is reset and the client gets notified
gadget.ResumeSuspendKeyDownMessages()
err := rpcKeyboardReport(0, make([]byte, usbgadget.HidKeyBufferSize))
err := rpcKeyboardReport(0, make([]byte, hidrpc.HidKeyBufferSize))
if err != nil {
logger.Warn().Err(err).Msg("failed to reset keyboard state")
}

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "Videresendt af Cloudflare",
"info_resolution": "Opløsning:",
"info_scroll_lock": "Scroll Lock",
"info_shift": "Flytte",
"info_usb_state": "USB-tilstand:",
"info_video_size": "Videostørrelse:",
"input_disabled": "Input deaktiveret",

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "Weitergeleitet von Cloudflare",
"info_resolution": "Auflösung:",
"info_scroll_lock": "Rollen-Taste",
"info_shift": "Schicht",
"info_usb_state": "USB-Status:",
"info_video_size": "Videogröße:",
"input_disabled": "Eingabe deaktiviert",

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "Relayed by Cloudflare",
"info_resolution": "Resolution:",
"info_scroll_lock": "Scroll Lock",
"info_shift": "Shift",
"info_usb_state": "USB State:",
"info_video_size": "Video Size:",
"input_disabled": "Input disabled",

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "Retransmitido por Cloudflare",
"info_resolution": "Resolución:",
"info_scroll_lock": "Bloq Despl",
"info_shift": "Cambio",
"info_usb_state": "Estado USB:",
"info_video_size": "Tamaño del vídeo:",
"input_disabled": "Entrada deshabilitada",

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "Relayé par Cloudflare",
"info_resolution": "Résolution :",
"info_scroll_lock": "Verrouillage du défilement",
"info_shift": "Maj",
"info_usb_state": "État USB :",
"info_video_size": "Taille de la vidéo :",
"input_disabled": "Entrée désactivée",

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "Rilasciato da Cloudflare",
"info_resolution": "Risoluzione:",
"info_scroll_lock": "Blocco scorrimento",
"info_shift": "Spostare",
"info_usb_state": "Stato USB:",
"info_video_size": "Dimensioni video:",
"input_disabled": "Input disabilitato",

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "Videresendt av Cloudflare",
"info_resolution": "Oppløsning:",
"info_scroll_lock": "Scroll Lock",
"info_shift": "Skifte",
"info_usb_state": "USB-tilstand:",
"info_video_size": "Videostørrelse:",
"input_disabled": "Inndata deaktivert",

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "Vidarebefordras av Cloudflare",
"info_resolution": "Upplösning:",
"info_scroll_lock": "Scroll Lock",
"info_shift": "Flytta",
"info_usb_state": "USB-status:",
"info_video_size": "Videostorlek:",
"input_disabled": "Inmatning inaktiverad",

View File

@ -331,6 +331,7 @@
"info_relayed_by_cloudflare": "由 Cloudflare 转发",
"info_resolution": "分辨率:",
"info_scroll_lock": "滚动锁定",
"info_shift": "Shift",
"info_usb_state": "USB 状态:",
"info_video_size": "视频大小:",
"input_disabled": "输入禁用",

View File

@ -19,8 +19,6 @@ import { TextAreaWithLabel } from "@components/TextArea";
// uint32 max value / 4
const pasteMaxLength = 1073741824;
const defaultDelay = 20;
const minimumDelay = 10;
const maximumDelay = 65534;
export default function PasteModal() {
const TextAreaRef = useRef<HTMLTextAreaElement>(null);
@ -33,7 +31,7 @@ export default function PasteModal() {
const [invalidChars, setInvalidChars] = useState<string[]>([]);
const [delayValue, setDelayValue] = useState(defaultDelay);
const delay = useMemo(() => {
if (delayValue < minimumDelay || delayValue > maximumDelay) {
if (delayValue < 0 || delayValue > 65534) {
return defaultDelay;
}
return delayValue;
@ -191,18 +189,18 @@ export default function PasteModal() {
type="number"
label={m.paste_modal_delay_between_keys()}
placeholder={m.paste_modal_delay_between_keys()}
min={minimumDelay}
max={maximumDelay}
min={50}
max={65534}
value={delayValue}
onChange={e => {
setDelayValue(parseInt(e.target.value, 10));
}}
/>
{(delayValue < minimumDelay || delayValue > maximumDelay) && (
{(delayValue < defaultDelay || delayValue > 65534) && (
<div className="mt-2 flex items-center gap-x-2">
<ExclamationCircleIcon className="h-4 w-4 text-red-500 dark:text-red-400" />
<span className="text-xs text-red-500 dark:text-red-400">
{m.paste_modal_delay_out_of_range({ min: minimumDelay, max: maximumDelay })}
{m.paste_modal_delay_out_of_range({ min: 50, max: 65534 })}
</span>
</div>
)}

View File

@ -386,7 +386,7 @@ export class CancelKeyboardMacroReportMessage extends RpcMessage {
constructor(token: string) {
super(HID_RPC_MESSAGE_TYPES.CancelKeyboardMacroReport);
this.token = (token == null || token === "")
this.token = (token == null || token === undefined || token === "")
? "00000000-0000-0000-0000-000000000000"
: token;
}
@ -397,11 +397,11 @@ export class CancelKeyboardMacroReportMessage extends RpcMessage {
}
public static unmarshal(data: Uint8Array): CancelKeyboardMacroReportMessage | undefined {
if (data.length === 0) {
if (data.length == 0) {
return new CancelKeyboardMacroReportMessage("00000000-0000-0000-0000-000000000000");
}
if (data.length !== 16) {
if (data.length != 16) {
throw new Error(`Invalid cancel message length: ${data.length}`);
}

View File

@ -89,7 +89,7 @@ def main(argv):
)
report = {
"generated_at": datetime.now().isoformat(),
"generated_at": datetime.utcnow().isoformat() + "Z",
"en_json": str(en_path),
"total_string_keys": total_keys,
"duplicate_groups": sorted(

View File

@ -82,7 +82,7 @@ def main():
print(f"Generating report for {len(usages)} usages ...")
report = {
"generated_at": datetime.now().isoformat(),
"generated_at": datetime.utcnow().isoformat() + "Z",
"en_json": str(en_path),
"src_root": args.src,
"total_keys": len(keys),

View File

@ -261,8 +261,8 @@ func newSession(config SessionConfig) (*Session, error) {
}
}()
for queueIndex := range session.hidQueues {
go session.handleQueue(session.hidQueues[queueIndex])
for queue := range session.hidQueues {
go session.handleQueue(session.hidQueues[queue])
}
peerConnection.OnDataChannel(func(d *webrtc.DataChannel) {