diff --git a/internal/usbgadget/config.go b/internal/usbgadget/config.go index 0a9b3caa..97464a4a 100644 --- a/internal/usbgadget/config.go +++ b/internal/usbgadget/config.go @@ -134,6 +134,13 @@ func (u *UsbGadget) SetGadgetDevices(devices *Devices) { u.enabledDevices = *devices } +func (u *UsbGadget) GetGadgetDevices() Devices { + u.configLock.Lock() + defer u.configLock.Unlock() + + return u.enabledDevices +} + // GetConfigPath returns the path to the config item. func (u *UsbGadget) GetConfigPath(itemKey string) (string, error) { item, ok := u.configMap[itemKey] diff --git a/internal/usbgadget/usbgadget.go b/internal/usbgadget/usbgadget.go index c7c86d23..ecdbc0db 100644 --- a/internal/usbgadget/usbgadget.go +++ b/internal/usbgadget/usbgadget.go @@ -22,6 +22,15 @@ type Devices struct { Audio bool `json:"audio"` } +// Equals checks if two Devices structs are equal. +func (d Devices) Equals(other Devices) bool { + return d.AbsoluteMouse == other.AbsoluteMouse && + d.RelativeMouse == other.RelativeMouse && + d.Keyboard == other.Keyboard && + d.MassStorage == other.MassStorage && + d.Audio == other.Audio +} + // Config is a struct that represents the customizations for a USB gadget. // TODO: rename to something else that won't confuse with the USB gadget configuration type Config struct { diff --git a/jsonrpc.go b/jsonrpc.go index 9c8cfd04..8a66570d 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -961,13 +961,24 @@ func updateUsbRelatedConfig(wasAudioEnabled bool) error { func rpcSetUsbDevices(usbDevices usbgadget.Devices) error { wasAudioEnabled := config.UsbDevices != nil && config.UsbDevices.Audio + currentDevices := gadget.GetGadgetDevices() + + // Skip reconfiguration if devices haven't changed to avoid HID disruption + if currentDevices.Equals(usbDevices) { + logger.Debug().Msg("USB devices unchanged, skipping gadget reconfiguration") + config.UsbDevices = &usbDevices + return nil + } + config.UsbDevices = &usbDevices gadget.SetGadgetDevices(config.UsbDevices) + return updateUsbRelatedConfig(wasAudioEnabled) } func rpcSetUsbDeviceState(device string, enabled bool) error { wasAudioEnabled := config.UsbDevices != nil && config.UsbDevices.Audio + currentDevices := gadget.GetGadgetDevices() switch device { case "absoluteMouse": @@ -983,6 +994,13 @@ func rpcSetUsbDeviceState(device string, enabled bool) error { default: return fmt.Errorf("invalid device: %s", device) } + + // Skip reconfiguration if devices haven't changed to avoid HID disruption + if currentDevices.Equals(*config.UsbDevices) { + logger.Debug().Msg("USB device state unchanged, skipping gadget reconfiguration") + return nil + } + gadget.SetGadgetDevices(config.UsbDevices) return updateUsbRelatedConfig(wasAudioEnabled) } diff --git a/ui/localization/messages/da.json b/ui/localization/messages/da.json index aa9341f5..a5bf65fa 100644 --- a/ui/localization/messages/da.json +++ b/ui/localization/messages/da.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "Opdater TLS-indstillinger", "action_bar_audio": "Lyd", "action_bar_connection_stats": "Forbindelsesstatistik", - "audio_disable": "Deaktiver", - "audio_enable": "Aktiver", - "audio_input_description": "Aktiver mikrofonindgang til målet", "audio_input_disabled": "Lydindgang deaktiveret", "audio_input_enabled": "Lydindgang aktiveret", "audio_input_failed_disable": "Kunne ikke deaktivere lydindgang: {error}", "audio_input_failed_enable": "Kunne ikke aktivere lydindgang: {error}", - "audio_input_title": "Lydindgang (Mikrofon)", "audio_input_auto_enable_disabled": "Automatisk aktivering af mikrofon deaktiveret", "audio_input_auto_enable_enabled": "Automatisk aktivering af mikrofon aktiveret", - "audio_output_description": "Aktiver lyd fra mål til højttalere", "audio_output_disabled": "Lydudgang deaktiveret", "audio_output_enabled": "Lydudgang aktiveret", "audio_output_failed_disable": "Kunne ikke deaktivere lydudgang: {error}", "audio_output_failed_enable": "Kunne ikke aktivere lydudgang: {error}", - "audio_output_title": "Lydudgang", "audio_popover_title": "Lyd", "audio_popover_description": "Hurtige lydkontroller til højttalere og mikrofon", "audio_speakers_title": "Højttalere", diff --git a/ui/localization/messages/de.json b/ui/localization/messages/de.json index 18eeb4f7..d11bf4b4 100644 --- a/ui/localization/messages/de.json +++ b/ui/localization/messages/de.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "TLS-Einstellungen aktualisieren", "action_bar_audio": "Audio", "action_bar_connection_stats": "Verbindungsstatistiken", - "audio_disable": "Deaktivieren", - "audio_enable": "Aktivieren", - "audio_input_description": "Mikrofoneingang zum Ziel aktivieren", "audio_input_disabled": "Audioeingang deaktiviert", "audio_input_enabled": "Audioeingang aktiviert", "audio_input_failed_disable": "Fehler beim Deaktivieren des Audioeingangs: {error}", "audio_input_failed_enable": "Fehler beim Aktivieren des Audioeingangs: {error}", - "audio_input_title": "Audioeingang (Mikrofon)", "audio_input_auto_enable_disabled": "Automatische Mikrofonaktivierung deaktiviert", "audio_input_auto_enable_enabled": "Automatische Mikrofonaktivierung aktiviert", - "audio_output_description": "Audio vom Ziel zu Lautsprechern aktivieren", "audio_output_disabled": "Audioausgang deaktiviert", "audio_output_enabled": "Audioausgang aktiviert", "audio_output_failed_disable": "Fehler beim Deaktivieren des Audioausgangs: {error}", "audio_output_failed_enable": "Fehler beim Aktivieren des Audioausgangs: {error}", - "audio_output_title": "Audioausgang", "audio_popover_title": "Audio", "audio_popover_description": "Schnelle Audiosteuerung für Lautsprecher und Mikrofon", "audio_speakers_title": "Lautsprecher", diff --git a/ui/localization/messages/en.json b/ui/localization/messages/en.json index 4424dec0..da1bf054 100644 --- a/ui/localization/messages/en.json +++ b/ui/localization/messages/en.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "Update TLS Settings", "action_bar_audio": "Audio", "action_bar_connection_stats": "Connection Stats", - "audio_disable": "Disable", - "audio_enable": "Enable", - "audio_input_description": "Enable microphone input to target", "audio_input_disabled": "Audio input disabled", "audio_input_enabled": "Audio input enabled", "audio_input_failed_disable": "Failed to disable audio input: {error}", "audio_input_failed_enable": "Failed to enable audio input: {error}", - "audio_input_title": "Audio Input (Microphone)", "audio_input_auto_enable_disabled": "Auto-enable microphone disabled", "audio_input_auto_enable_enabled": "Auto-enable microphone enabled", - "audio_output_description": "Enable audio from target to speakers", "audio_output_disabled": "Audio output disabled", "audio_output_enabled": "Audio output enabled", "audio_output_failed_disable": "Failed to disable audio output: {error}", "audio_output_failed_enable": "Failed to enable audio output: {error}", - "audio_output_title": "Audio Output", "audio_popover_title": "Audio", "audio_popover_description": "Quick audio controls for speakers and microphone", "audio_speakers_title": "Speakers", diff --git a/ui/localization/messages/es.json b/ui/localization/messages/es.json index cc578ef5..265528bc 100644 --- a/ui/localization/messages/es.json +++ b/ui/localization/messages/es.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "Actualizar la configuración de TLS", "action_bar_audio": "Audio", "action_bar_connection_stats": "Estadísticas de conexión", - "audio_disable": "Desactivar", - "audio_enable": "Activar", - "audio_input_description": "Habilitar entrada de micrófono al objetivo", "audio_input_disabled": "Entrada de audio desactivada", "audio_input_enabled": "Entrada de audio activada", "audio_input_failed_disable": "Error al desactivar la entrada de audio: {error}", "audio_input_failed_enable": "Error al activar la entrada de audio: {error}", - "audio_input_title": "Entrada de audio (Micrófono)", "audio_input_auto_enable_disabled": "Habilitación automática de micrófono desactivada", "audio_input_auto_enable_enabled": "Habilitación automática de micrófono activada", - "audio_output_description": "Habilitar audio del objetivo a los altavoces", "audio_output_disabled": "Salida de audio desactivada", "audio_output_enabled": "Salida de audio activada", "audio_output_failed_disable": "Error al desactivar la salida de audio: {error}", "audio_output_failed_enable": "Error al activar la salida de audio: {error}", - "audio_output_title": "Salida de audio", "audio_popover_title": "Audio", "audio_popover_description": "Controles de audio rápidos para altavoces y micrófono", "audio_speakers_title": "Altavoces", diff --git a/ui/localization/messages/fr.json b/ui/localization/messages/fr.json index 9c13908c..22056299 100644 --- a/ui/localization/messages/fr.json +++ b/ui/localization/messages/fr.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "Mettre à jour les paramètres TLS", "action_bar_audio": "Audio", "action_bar_connection_stats": "Statistiques de connexion", - "audio_disable": "Désactiver", - "audio_enable": "Activer", - "audio_input_description": "Activer l'entrée microphone vers la cible", "audio_input_disabled": "Entrée audio désactivée", "audio_input_enabled": "Entrée audio activée", "audio_input_failed_disable": "Échec de la désactivation de l'entrée audio : {error}", "audio_input_failed_enable": "Échec de l'activation de l'entrée audio : {error}", - "audio_input_title": "Entrée audio (Microphone)", "audio_input_auto_enable_disabled": "Activation automatique du microphone désactivée", "audio_input_auto_enable_enabled": "Activation automatique du microphone activée", - "audio_output_description": "Activer l'audio de la cible vers les haut-parleurs", "audio_output_disabled": "Sortie audio désactivée", "audio_output_enabled": "Sortie audio activée", "audio_output_failed_disable": "Échec de la désactivation de la sortie audio : {error}", "audio_output_failed_enable": "Échec de l'activation de la sortie audio : {error}", - "audio_output_title": "Sortie audio", "audio_popover_title": "Audio", "audio_popover_description": "Contrôles audio rapides pour haut-parleurs et microphone", "audio_speakers_title": "Haut-parleurs", diff --git a/ui/localization/messages/it.json b/ui/localization/messages/it.json index 9dd2c03f..6663b7f2 100644 --- a/ui/localization/messages/it.json +++ b/ui/localization/messages/it.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "Aggiorna le impostazioni TLS", "action_bar_audio": "Audio", "action_bar_connection_stats": "Statistiche di connessione", - "audio_disable": "Disabilita", - "audio_enable": "Abilita", - "audio_input_description": "Abilita l'ingresso del microfono al target", "audio_input_disabled": "Ingresso audio disabilitato", "audio_input_enabled": "Ingresso audio abilitato", "audio_input_failed_disable": "Impossibile disabilitare l'ingresso audio: {error}", "audio_input_failed_enable": "Impossibile abilitare l'ingresso audio: {error}", - "audio_input_title": "Ingresso audio (Microfono)", "audio_input_auto_enable_disabled": "Abilitazione automatica microfono disabilitata", "audio_input_auto_enable_enabled": "Abilitazione automatica microfono abilitata", - "audio_output_description": "Abilita l'audio dal target agli altoparlanti", "audio_output_disabled": "Uscita audio disabilitata", "audio_output_enabled": "Uscita audio abilitata", "audio_output_failed_disable": "Impossibile disabilitare l'uscita audio: {error}", "audio_output_failed_enable": "Impossibile abilitare l'uscita audio: {error}", - "audio_output_title": "Uscita audio", "audio_popover_title": "Audio", "audio_popover_description": "Controlli audio rapidi per altoparlanti e microfono", "audio_speakers_title": "Altoparlanti", diff --git a/ui/localization/messages/nb.json b/ui/localization/messages/nb.json index 6ecf22d7..1f1c414f 100644 --- a/ui/localization/messages/nb.json +++ b/ui/localization/messages/nb.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "Oppdater TLS-innstillinger", "action_bar_audio": "Lyd", "action_bar_connection_stats": "Tilkoblingsstatistikk", - "audio_disable": "Deaktiver", - "audio_enable": "Aktiver", - "audio_input_description": "Aktiver mikrofoninngang til målet", "audio_input_disabled": "Lydinngang deaktivert", "audio_input_enabled": "Lydinngang aktivert", "audio_input_failed_disable": "Kunne ikke deaktivere lydinngang: {error}", "audio_input_failed_enable": "Kunne ikke aktivere lydinngang: {error}", - "audio_input_title": "Lydinngang (Mikrofon)", "audio_input_auto_enable_disabled": "Automatisk aktivering av mikrofon deaktivert", "audio_input_auto_enable_enabled": "Automatisk aktivering av mikrofon aktivert", - "audio_output_description": "Aktiver lyd fra mål til høyttalere", "audio_output_disabled": "Lydutgang deaktivert", "audio_output_enabled": "Lydutgang aktivert", "audio_output_failed_disable": "Kunne ikke deaktivere lydutgang: {error}", "audio_output_failed_enable": "Kunne ikke aktivere lydutgang: {error}", - "audio_output_title": "Lydutgang", "audio_popover_title": "Lyd", "audio_popover_description": "Raske lydkontroller for høyttalere og mikrofon", "audio_speakers_title": "Høyttalere", diff --git a/ui/localization/messages/sv.json b/ui/localization/messages/sv.json index a16446d8..4f5cb1b0 100644 --- a/ui/localization/messages/sv.json +++ b/ui/localization/messages/sv.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "Uppdatera TLS-inställningar", "action_bar_audio": "Ljud", "action_bar_connection_stats": "Anslutningsstatistik", - "audio_disable": "Inaktivera", - "audio_enable": "Aktivera", - "audio_input_description": "Aktivera mikrofoningång till målet", "audio_input_disabled": "Ljudingång inaktiverad", "audio_input_enabled": "Ljudingång aktiverad", "audio_input_failed_disable": "Det gick inte att inaktivera ljudingången: {error}", "audio_input_failed_enable": "Det gick inte att aktivera ljudingången: {error}", - "audio_input_title": "Ljudingång (Mikrofon)", "audio_input_auto_enable_disabled": "Automatisk aktivering av mikrofon inaktiverad", "audio_input_auto_enable_enabled": "Automatisk aktivering av mikrofon aktiverad", - "audio_output_description": "Aktivera ljud från mål till högtalare", "audio_output_disabled": "Ljudutgång inaktiverad", "audio_output_enabled": "Ljudutgång aktiverad", "audio_output_failed_disable": "Det gick inte att inaktivera ljudutgången: {error}", "audio_output_failed_enable": "Det gick inte att aktivera ljudutgången: {error}", - "audio_output_title": "Ljudutgång", "audio_popover_title": "Ljud", "audio_popover_description": "Snabba ljudkontroller för högtalare och mikrofon", "audio_speakers_title": "Högtalare", diff --git a/ui/localization/messages/zh.json b/ui/localization/messages/zh.json index 73d4c101..268a2877 100644 --- a/ui/localization/messages/zh.json +++ b/ui/localization/messages/zh.json @@ -49,22 +49,16 @@ "access_update_tls_settings": "更新 TLS 设置", "action_bar_audio": "音频", "action_bar_connection_stats": "连接统计", - "audio_disable": "禁用", - "audio_enable": "启用", - "audio_input_description": "启用麦克风输入到目标设备", "audio_input_disabled": "音频输入已禁用", "audio_input_enabled": "音频输入已启用", "audio_input_failed_disable": "禁用音频输入失败:{error}", "audio_input_failed_enable": "启用音频输入失败:{error}", - "audio_input_title": "音频输入(麦克风)", "audio_input_auto_enable_disabled": "自动启用麦克风已禁用", "audio_input_auto_enable_enabled": "自动启用麦克风已启用", - "audio_output_description": "启用从目标设备到扬声器的音频", "audio_output_disabled": "音频输出已禁用", "audio_output_enabled": "音频输出已启用", "audio_output_failed_disable": "禁用音频输出失败:{error}", "audio_output_failed_enable": "启用音频输出失败:{error}", - "audio_output_title": "音频输出", "audio_popover_title": "音频", "audio_popover_description": "扬声器和麦克风的快速音频控制", "audio_speakers_title": "扬声器",