mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-31 18:11:54 +08:00
fix: 修复适配全志平台 OTG 低端点情况
This commit is contained in:
@@ -220,12 +220,14 @@ interface DeviceConfig {
|
||||
}>
|
||||
serial: Array<{ path: string; name: string }>
|
||||
audio: Array<{ name: string; description: string }>
|
||||
udc: Array<{ name: string }>
|
||||
}
|
||||
|
||||
const devices = ref<DeviceConfig>({
|
||||
video: [],
|
||||
serial: [],
|
||||
audio: [],
|
||||
udc: [],
|
||||
})
|
||||
|
||||
const config = ref({
|
||||
@@ -237,6 +239,7 @@ const config = ref({
|
||||
hid_backend: 'ch9329',
|
||||
hid_serial_device: '',
|
||||
hid_serial_baudrate: 9600,
|
||||
hid_otg_udc: '',
|
||||
hid_otg_profile: 'full' as OtgHidProfile,
|
||||
hid_otg_functions: {
|
||||
keyboard: true,
|
||||
@@ -257,6 +260,39 @@ const config = ref({
|
||||
|
||||
// 跟踪服务器是否已配置 TURN 密码
|
||||
const hasTurnPassword = ref(false)
|
||||
const configLoaded = ref(false)
|
||||
const devicesLoaded = ref(false)
|
||||
const hidProfileAligned = ref(false)
|
||||
|
||||
const isLowEndpointUdc = computed(() => {
|
||||
if (config.value.hid_otg_udc) {
|
||||
return /musb/i.test(config.value.hid_otg_udc)
|
||||
}
|
||||
return devices.value.udc.some((udc) => /musb/i.test(udc.name))
|
||||
})
|
||||
|
||||
const showLowEndpointHint = computed(() =>
|
||||
config.value.hid_backend === 'otg' && isLowEndpointUdc.value
|
||||
)
|
||||
|
||||
function alignHidProfileForLowEndpoint() {
|
||||
if (hidProfileAligned.value) return
|
||||
if (!configLoaded.value || !devicesLoaded.value) return
|
||||
if (config.value.hid_backend !== 'otg') {
|
||||
hidProfileAligned.value = true
|
||||
return
|
||||
}
|
||||
if (!isLowEndpointUdc.value) {
|
||||
hidProfileAligned.value = true
|
||||
return
|
||||
}
|
||||
if (config.value.hid_otg_profile === 'full') {
|
||||
config.value.hid_otg_profile = 'full_no_consumer' as OtgHidProfile
|
||||
} else if (config.value.hid_otg_profile === 'full_no_msd') {
|
||||
config.value.hid_otg_profile = 'full_no_consumer_no_msd' as OtgHidProfile
|
||||
}
|
||||
hidProfileAligned.value = true
|
||||
}
|
||||
|
||||
const isHidFunctionSelectionValid = computed(() => {
|
||||
if (config.value.hid_backend !== 'otg') return true
|
||||
@@ -550,6 +586,10 @@ async function saveConfig() {
|
||||
desiredMsdEnabled = true
|
||||
} else if (config.value.hid_otg_profile === 'full_no_msd') {
|
||||
desiredMsdEnabled = false
|
||||
} else if (config.value.hid_otg_profile === 'full_no_consumer') {
|
||||
desiredMsdEnabled = true
|
||||
} else if (config.value.hid_otg_profile === 'full_no_consumer_no_msd') {
|
||||
desiredMsdEnabled = false
|
||||
} else if (
|
||||
config.value.hid_otg_profile === 'legacy_keyboard'
|
||||
|| config.value.hid_otg_profile === 'legacy_mouse_relative'
|
||||
@@ -624,6 +664,7 @@ async function loadConfig() {
|
||||
hid_backend: hid.backend || 'none',
|
||||
hid_serial_device: hid.ch9329_port || '',
|
||||
hid_serial_baudrate: hid.ch9329_baudrate || 9600,
|
||||
hid_otg_udc: hid.otg_udc || '',
|
||||
hid_otg_profile: (hid.otg_profile || 'full') as OtgHidProfile,
|
||||
hid_otg_functions: {
|
||||
keyboard: hid.otg_functions?.keyboard ?? true,
|
||||
@@ -664,6 +705,9 @@ async function loadConfig() {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to load config:', e)
|
||||
} finally {
|
||||
configLoaded.value = true
|
||||
alignHidProfileForLowEndpoint()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,6 +716,9 @@ async function loadDevices() {
|
||||
devices.value = await configApi.listDevices()
|
||||
} catch (e) {
|
||||
console.error('Failed to load devices:', e)
|
||||
} finally {
|
||||
devicesLoaded.value = true
|
||||
alignHidProfileForLowEndpoint()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1492,6 +1539,8 @@ onMounted(async () => {
|
||||
<select id="otg-profile" v-model="config.hid_otg_profile" class="w-full h-9 px-3 rounded-md border border-input bg-background text-sm">
|
||||
<option value="full">{{ t('settings.otgProfileFull') }}</option>
|
||||
<option value="full_no_msd">{{ t('settings.otgProfileFullNoMsd') }}</option>
|
||||
<option value="full_no_consumer">{{ t('settings.otgProfileFullNoConsumer') }}</option>
|
||||
<option value="full_no_consumer_no_msd">{{ t('settings.otgProfileFullNoConsumerNoMsd') }}</option>
|
||||
<option value="legacy_keyboard">{{ t('settings.otgProfileLegacyKeyboard') }}</option>
|
||||
<option value="legacy_mouse_relative">{{ t('settings.otgProfileLegacyMouseRelative') }}</option>
|
||||
<option value="custom">{{ t('settings.otgProfileCustom') }}</option>
|
||||
@@ -1541,6 +1590,9 @@ onMounted(async () => {
|
||||
<p class="text-xs text-amber-600 dark:text-amber-400">
|
||||
{{ t('settings.otgProfileWarning') }}
|
||||
</p>
|
||||
<p v-if="showLowEndpointHint" class="text-xs text-amber-600 dark:text-amber-400">
|
||||
{{ t('settings.otgLowEndpointHint') }}
|
||||
</p>
|
||||
</div>
|
||||
<Separator class="my-4" />
|
||||
<div class="space-y-4">
|
||||
|
||||
@@ -96,6 +96,9 @@ const hidBackend = ref('ch9329')
|
||||
const ch9329Port = ref('')
|
||||
const ch9329Baudrate = ref(9600)
|
||||
const otgUdc = ref('')
|
||||
const hidOtgProfile = ref('full')
|
||||
const otgProfileTouched = ref(false)
|
||||
const showAdvancedOtg = ref(false)
|
||||
|
||||
// Extension settings
|
||||
const ttydEnabled = ref(false)
|
||||
@@ -200,6 +203,26 @@ const availableFps = computed(() => {
|
||||
return resolution?.fps || []
|
||||
})
|
||||
|
||||
const isLowEndpointUdc = computed(() => {
|
||||
if (otgUdc.value) {
|
||||
return /musb/i.test(otgUdc.value)
|
||||
}
|
||||
return devices.value.udc.some((udc) => /musb/i.test(udc.name))
|
||||
})
|
||||
|
||||
function applyOtgProfileDefault() {
|
||||
if (otgProfileTouched.value) return
|
||||
if (hidBackend.value !== 'otg') return
|
||||
const preferred = isLowEndpointUdc.value ? 'full_no_consumer' : 'full'
|
||||
if (hidOtgProfile.value === preferred) return
|
||||
hidOtgProfile.value = preferred
|
||||
}
|
||||
|
||||
function onOtgProfileChange(value: unknown) {
|
||||
hidOtgProfile.value = typeof value === 'string' ? value : 'full'
|
||||
otgProfileTouched.value = true
|
||||
}
|
||||
|
||||
// Common baud rates for CH9329
|
||||
const baudRates = [9600, 19200, 38400, 57600, 115200]
|
||||
|
||||
@@ -315,6 +338,17 @@ watch(hidBackend, (newBackend) => {
|
||||
if (newBackend === 'otg' && !otgUdc.value && devices.value.udc.length > 0) {
|
||||
otgUdc.value = devices.value.udc[0]?.name || ''
|
||||
}
|
||||
applyOtgProfileDefault()
|
||||
})
|
||||
|
||||
watch(otgUdc, () => {
|
||||
applyOtgProfileDefault()
|
||||
})
|
||||
|
||||
watch(showAdvancedOtg, (open) => {
|
||||
if (open) {
|
||||
applyOtgProfileDefault()
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -336,6 +370,7 @@ onMounted(async () => {
|
||||
if (result.udc.length > 0 && result.udc[0]) {
|
||||
otgUdc.value = result.udc[0].name
|
||||
}
|
||||
applyOtgProfileDefault()
|
||||
|
||||
// Auto-select audio device if available (and no video device to trigger watch)
|
||||
if (result.audio.length > 0 && !audioDevice.value) {
|
||||
@@ -487,6 +522,7 @@ async function handleSetup() {
|
||||
}
|
||||
if (hidBackend.value === 'otg' && otgUdc.value) {
|
||||
setupData.hid_otg_udc = otgUdc.value
|
||||
setupData.hid_otg_profile = hidOtgProfile.value
|
||||
}
|
||||
|
||||
// Encoder backend setting
|
||||
@@ -924,6 +960,46 @@ const stepIcons = [User, Video, Keyboard, Puzzle]
|
||||
{{ t('setup.noUdcDevices') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 border rounded-lg">
|
||||
<button
|
||||
type="button"
|
||||
class="w-full flex items-center justify-between p-3 text-left hover:bg-muted/50 rounded-lg transition-colors"
|
||||
@click="showAdvancedOtg = !showAdvancedOtg"
|
||||
>
|
||||
<span class="text-sm font-medium">
|
||||
{{ t('setup.otgAdvanced') }} ({{ t('common.optional') }})
|
||||
</span>
|
||||
<ChevronRight
|
||||
class="h-4 w-4 transition-transform duration-200"
|
||||
:class="{ 'rotate-90': showAdvancedOtg }"
|
||||
/>
|
||||
</button>
|
||||
<div v-if="showAdvancedOtg" class="px-3 pb-3 space-y-3">
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ t('setup.otgProfileDesc') }}
|
||||
</p>
|
||||
<div class="space-y-2">
|
||||
<Label for="otgProfile">{{ t('setup.otgProfile') }}</Label>
|
||||
<Select :model-value="hidOtgProfile" @update:modelValue="onOtgProfileChange">
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="full">{{ t('settings.otgProfileFull') }}</SelectItem>
|
||||
<SelectItem value="full_no_msd">{{ t('settings.otgProfileFullNoMsd') }}</SelectItem>
|
||||
<SelectItem value="full_no_consumer">{{ t('settings.otgProfileFullNoConsumer') }}</SelectItem>
|
||||
<SelectItem value="full_no_consumer_no_msd">{{ t('settings.otgProfileFullNoConsumerNoMsd') }}</SelectItem>
|
||||
<SelectItem value="legacy_keyboard">{{ t('settings.otgProfileLegacyKeyboard') }}</SelectItem>
|
||||
<SelectItem value="legacy_mouse_relative">{{ t('settings.otgProfileLegacyMouseRelative') }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<p v-if="isLowEndpointUdc" class="text-xs text-amber-600 dark:text-amber-400">
|
||||
{{ t('setup.otgLowEndpointHint') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user