From 54c963e8b3164dccb175dd99509fefa73fc21811 Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Thu, 18 Jun 2026 11:02:32 +0800 Subject: [PATCH 1/8] feat(input): add gamepad vibration gain --- entry/src/main/ets/model/StreamConfig.ets | 7 +++++ entry/src/main/ets/pages/SettingsPageV2.ets | 26 +++++++++++++++- .../src/main/ets/service/SettingsService.ets | 8 ++++- .../main/ets/service/input/GamepadManager.ets | 11 +++++-- .../service/input/GamepadVibrationService.ets | 31 +++++++++++++++++-- .../service/usbdriver/NativeHidController.ets | 8 ++--- .../main/ets/viewmodel/StreamViewModel.ets | 3 +- 7 files changed, 82 insertions(+), 12 deletions(-) diff --git a/entry/src/main/ets/model/StreamConfig.ets b/entry/src/main/ets/model/StreamConfig.ets index ed0144f..63b9de4 100644 --- a/entry/src/main/ets/model/StreamConfig.ets +++ b/entry/src/main/ets/model/StreamConfig.ets @@ -13,6 +13,11 @@ * * 参考 Android 版本 StreamConfiguration.java */ +export const GAMEPAD_VIBRATION_GAIN_MIN = 50; +export const GAMEPAD_VIBRATION_GAIN_MAX = 200; +export const GAMEPAD_VIBRATION_GAIN_DEFAULT = 100; +export const GAMEPAD_VIBRATION_GAIN_STEP = 10; + export interface StreamConfig { // 视频设置 width: number; @@ -47,6 +52,7 @@ export interface StreamConfig { enableVibration: boolean; vibrationMode: string; // 震动模式:自动/仅手柄/仅设备/同时 vibrateFallbackStrength: number; + gamepadVibrationGain: number; // 手柄震动增益百分比(默认 100,最高不突破硬件上限) enableAudioVibration: boolean; // 音频振动(低频驱动) audioVibrationStrength: number; // 音频振动强度 (0-100) audioVibrationSceneMode: string; // 音频振动场景模式: 游戏/电影, 音乐/节奏, 自动 @@ -230,6 +236,7 @@ export function getDefaultStreamConfig(): StreamConfig { enableVibration: true, vibrationMode: '自动', vibrateFallbackStrength: 100, + gamepadVibrationGain: GAMEPAD_VIBRATION_GAIN_DEFAULT, enableAudioVibration: false, audioVibrationStrength: 60, audioVibrationSceneMode: '游戏/电影', diff --git a/entry/src/main/ets/pages/SettingsPageV2.ets b/entry/src/main/ets/pages/SettingsPageV2.ets index 9cb9d72..9e60938 100644 --- a/entry/src/main/ets/pages/SettingsPageV2.ets +++ b/entry/src/main/ets/pages/SettingsPageV2.ets @@ -15,7 +15,13 @@ import { pasteboard } from '@kit.BasicServicesKit'; import { PreferencesUtil } from '../utils/PreferencesUtil'; import { AppColors, AppSizes, AppSpacing, AppAnimation, AppShadows } from '../common/Theme'; import { StreamingSession, DecoderCapabilities } from '../service/streaming/StreamingSession'; -import { getRecommendedBitrate } from '../model/StreamConfig'; +import { + getRecommendedBitrate, + GAMEPAD_VIBRATION_GAIN_DEFAULT, + GAMEPAD_VIBRATION_GAIN_MAX, + GAMEPAD_VIBRATION_GAIN_MIN, + GAMEPAD_VIBRATION_GAIN_STEP +} from '../model/StreamConfig'; import { PerfLabels } from '../components/PerformanceOverlayManager'; import { SettingSlider, SettingSliderConfig, LogarithmicSlider } from '../components/SettingSlider'; import { SettingsBackupService } from '../service/SettingsBackupService'; @@ -176,6 +182,7 @@ struct SettingsPageV2 { @State enableVibration: boolean = true; @State vibrationMode: string = '自动'; // 自动/仅手柄/仅设备/同时 @State vibrateFallbackStrength: number = 100; + @State gamepadVibrationGain: number = GAMEPAD_VIBRATION_GAIN_DEFAULT; @State enableAudioVibration: boolean = false; @State audioVibrationStrength: number = 60; @State audioVibrationSceneMode: string = '游戏/电影'; @@ -519,6 +526,8 @@ struct SettingsPageV2 { this.enableVibration = await this.loadBoolean(SettingsKeys.ENABLE_VIBRATION, true); this.vibrationMode = await PreferencesUtil.get(SettingsKeys.VIBRATION_MODE, '自动'); this.vibrateFallbackStrength = await PreferencesUtil.get(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100); + this.gamepadVibrationGain = + await PreferencesUtil.get(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT); this.enableAudioVibration = await this.loadBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); this.audioVibrationStrength = await PreferencesUtil.get(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60); this.audioVibrationSceneMode = await PreferencesUtil.get(SettingsKeys.AUDIO_VIBRATION_SCENE_MODE, '游戏/电影'); @@ -1360,6 +1369,21 @@ struct SettingsPageV2 { this.saveSetting(SettingsKeys.VIBRATION_MODE, value); } }, + { + title: '手柄震动增益', + subtitle: '放大发往外接手柄的震动,仍受硬件上限限制', + type: 'slider', + visible: this.enableVibration, + value: this.gamepadVibrationGain, + min: GAMEPAD_VIBRATION_GAIN_MIN, + max: GAMEPAD_VIBRATION_GAIN_MAX, + step: GAMEPAD_VIBRATION_GAIN_STEP, + unit: '%', + onSliderChange: (value: number) => { + this.gamepadVibrationGain = value; + this.saveSetting(SettingsKeys.GAMEPAD_VIBRATION_GAIN, value); + } + }, { title: '设备振动强度', subtitle: '使用设备震动时的强度', diff --git a/entry/src/main/ets/service/SettingsService.ets b/entry/src/main/ets/service/SettingsService.ets index 352fc9d..d0f235a 100644 --- a/entry/src/main/ets/service/SettingsService.ets +++ b/entry/src/main/ets/service/SettingsService.ets @@ -25,7 +25,8 @@ import { ScreenCombinationMode, PerfOverlayOrientation, PerfOverlayPosition, - getRecommendedBitrate + getRecommendedBitrate, + GAMEPAD_VIBRATION_GAIN_DEFAULT } from '../model/StreamConfig'; /** @@ -68,6 +69,7 @@ export class SettingsKeys { static readonly ENABLE_VIBRATION: string = 'settings_enable_vibration'; static readonly VIBRATION_MODE: string = 'settings_vibration_mode'; // 震动模式:自动/仅手柄/仅设备/同时 static readonly VIBRATE_FALLBACK_STRENGTH: string = 'settings_vibrate_fallback_strength'; + static readonly GAMEPAD_VIBRATION_GAIN: string = 'settings_gamepad_vibration_gain'; static readonly ENABLE_AUDIO_VIBRATION: string = 'settings_enable_audio_vibration'; // 音频振动(低频驱动) static readonly AUDIO_VIBRATION_STRENGTH: string = 'settings_audio_vibration_strength'; // 音频振动强度 (0-100) static readonly AUDIO_VIBRATION_SCENE_MODE: string = 'settings_audio_vibration_scene_mode'; // 音频振动场景模式 @@ -184,6 +186,7 @@ export interface InputSettings { enableVibration: boolean; vibrationMode: string; // 自动/仅手柄/仅设备/同时 vibrateFallbackStrength: number; + gamepadVibrationGain: number; enableAudioVibration: boolean; // 音频振动(低频驱动) audioVibrationStrength: number; // 音频振动强度 (0-100) audioVibrationSceneMode: string; // 音频振动场景模式 @@ -599,6 +602,7 @@ export class SettingsService { const enableVibration = await this.getBoolean(SettingsKeys.ENABLE_VIBRATION, true); const vibrationMode = await this.getString(SettingsKeys.VIBRATION_MODE, '自动'); const vibrateFallbackStrength = await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100); + const gamepadVibrationGain = await this.getNumber(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT); const enableAudioVibration = await this.getBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); const audioVibrationStrength = await this.getNumber(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60); const audioVibrationSceneMode = await this.getString(SettingsKeys.AUDIO_VIBRATION_SCENE_MODE, '游戏/电影'); @@ -680,6 +684,7 @@ export class SettingsService { enableVibration: enableVibration, vibrationMode: vibrationMode, vibrateFallbackStrength: vibrateFallbackStrength, + gamepadVibrationGain: gamepadVibrationGain, enableAudioVibration: enableAudioVibration, audioVibrationStrength: audioVibrationStrength, audioVibrationSceneMode: audioVibrationSceneMode, @@ -742,6 +747,7 @@ export class SettingsService { enableVibration: await this.getBoolean(SettingsKeys.ENABLE_VIBRATION, true), vibrationMode: await this.getString(SettingsKeys.VIBRATION_MODE, '自动'), vibrateFallbackStrength: await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100), + gamepadVibrationGain: await this.getNumber(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT), enableAudioVibration: await this.getBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false), audioVibrationStrength: await this.getNumber(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60), audioVibrationSceneMode: await this.getString(SettingsKeys.AUDIO_VIBRATION_SCENE_MODE, '游戏/电影'), diff --git a/entry/src/main/ets/service/input/GamepadManager.ets b/entry/src/main/ets/service/input/GamepadManager.ets index 1a91b10..664eaa1 100644 --- a/entry/src/main/ets/service/input/GamepadManager.ets +++ b/entry/src/main/ets/service/input/GamepadManager.ets @@ -16,6 +16,7 @@ import { GameControllerDeviceInfo } from './GameControllerService'; import { SettingsService, SettingsKeys } from '../SettingsService'; +import { GAMEPAD_VIBRATION_GAIN_DEFAULT } from '../../model/StreamConfig'; import { PreferencesUtil } from '../../utils/PreferencesUtil'; import { DeviceSensorService, LI_MOTION_TYPE_ACCEL, LI_MOTION_TYPE_GYRO } from './DeviceSensorService'; import { MoonBridge } from '../streaming/MoonBridge'; @@ -649,9 +650,15 @@ export class GamepadManager implements UsbDriverListener { * @param enabled 是否启用震动 * @param strength 设备震动强度 (0-100) * @param mode 震动模式:自动/仅手柄/仅设备/同时 + * @param gamepadGain 手柄震动增益 (100=原始强度) */ - setDeviceVibrate(enabled: boolean, strength: number, mode: string): void { - this.vibrationService.setSettings(enabled, strength, mode); + setDeviceVibrate( + enabled: boolean, + strength: number, + mode: string, + gamepadGain: number = GAMEPAD_VIBRATION_GAIN_DEFAULT + ): void { + this.vibrationService.setSettings(enabled, strength, mode, gamepadGain); } /** diff --git a/entry/src/main/ets/service/input/GamepadVibrationService.ets b/entry/src/main/ets/service/input/GamepadVibrationService.ets index 310f892..7d26fe0 100644 --- a/entry/src/main/ets/service/input/GamepadVibrationService.ets +++ b/entry/src/main/ets/service/input/GamepadVibrationService.ets @@ -20,6 +20,11 @@ import { vibrator } from '@kit.SensorServiceKit'; import { UsbDriverService, AbstractController } from '../usbdriver/index'; import { RUMBLE_MAX } from './GamepadTypes'; +import { + GAMEPAD_VIBRATION_GAIN_DEFAULT, + GAMEPAD_VIBRATION_GAIN_MAX, + GAMEPAD_VIBRATION_GAIN_MIN +} from '../../model/StreamConfig'; // ==================== 震动服务 ==================== @@ -29,6 +34,7 @@ export class GamepadVibrationService { // 设置 private deviceVibrateEnabled = false; private deviceVibrateStrength = 100; + private gamepadVibrationGain = GAMEPAD_VIBRATION_GAIN_DEFAULT; private vibrationMode = '自动'; // 槽位→设备键的查找函数(由 GamepadManager 提供) @@ -58,9 +64,15 @@ export class GamepadVibrationService { /** * 更新震动设置 */ - setSettings(enabled: boolean, strength: number, mode: string): void { + setSettings( + enabled: boolean, + strength: number, + mode: string, + gamepadGain: number = GAMEPAD_VIBRATION_GAIN_DEFAULT + ): void { this.deviceVibrateEnabled = enabled; this.deviceVibrateStrength = strength; + this.gamepadVibrationGain = Math.max(GAMEPAD_VIBRATION_GAIN_MIN, Math.min(GAMEPAD_VIBRATION_GAIN_MAX, gamepadGain)); this.vibrationMode = mode; } @@ -136,7 +148,7 @@ export class GamepadVibrationService { handleRumbleTriggers(controllerNumber: number, leftTrigger: number, rightTrigger: number): void { const controllers = this.usbDriverService.getControllers(); const controller = this.findControllerBySlot(controllers, controllerNumber); - controller?.rumbleTriggers(leftTrigger, rightTrigger); + controller?.rumbleTriggers(this.applyGamepadGain(leftTrigger), this.applyGamepadGain(rightTrigger)); } /** @@ -215,7 +227,20 @@ export class GamepadVibrationService { */ private rumbleUsbControllers(controllers: AbstractController[], controllerNumber: number, lowFreqMotor: number, highFreqMotor: number): void { const controller = this.findControllerBySlot(controllers, controllerNumber); - controller?.rumble(lowFreqMotor, highFreqMotor); + controller?.rumble(this.applyGamepadGain(lowFreqMotor), this.applyGamepadGain(highFreqMotor)); + } + + private applyGamepadGain(value: number): number { + if (value <= 0) return 0; + if (this.gamepadVibrationGain === GAMEPAD_VIBRATION_GAIN_DEFAULT) { + return this.clampRumbleValue(value); + } + const gained = Math.floor(value * this.gamepadVibrationGain / 100); + return this.clampRumbleValue(gained); + } + + private clampRumbleValue(value: number): number { + return Math.max(0, Math.min(RUMBLE_MAX, Math.floor(value))); } /** diff --git a/entry/src/main/ets/service/usbdriver/NativeHidController.ets b/entry/src/main/ets/service/usbdriver/NativeHidController.ets index ae24f65..8cc15b0 100644 --- a/entry/src/main/ets/service/usbdriver/NativeHidController.ets +++ b/entry/src/main/ets/service/usbdriver/NativeHidController.ets @@ -19,7 +19,7 @@ import { usbManager } from '@kit.BasicServicesKit'; import { AbstractController } from './AbstractController'; import { UsbDriverListener } from './UsbDriverListener'; import { ButtonFlags, UsbClass, ControllerType, ControllerCapabilities } from './ControllerConstants'; -import { AXIS_MAX, TRIGGER_MAX, RUMBLE_MAX } from '../input/GamepadTypes'; +import { AXIS_MAX, TRIGGER_MAX } from '../input/GamepadTypes'; import { NativeHidParserService, NativeGamepadState, NativeGamepadType, NativeButtonFlags } from './NativeHidParserService'; import { createUsbError, UsbError } from './UsbErrorCodes'; @@ -664,12 +664,12 @@ export class NativeHidController extends AbstractController { return; } - // 获取震动命令 + // Native parser expects Moonlight rumble values in the same 0..65535 range as AbstractController. const cmd = this.nativeParser.createRumbleCommand( this.vendorId, this.productId, - Math.round(lowFreqMotor * RUMBLE_MAX), - Math.round(highFreqMotor * RUMBLE_MAX) + Math.round(lowFreqMotor), + Math.round(highFreqMotor) ); if (cmd) { diff --git a/entry/src/main/ets/viewmodel/StreamViewModel.ets b/entry/src/main/ets/viewmodel/StreamViewModel.ets index 4763d58..95a67b5 100644 --- a/entry/src/main/ets/viewmodel/StreamViewModel.ets +++ b/entry/src/main/ets/viewmodel/StreamViewModel.ets @@ -275,7 +275,8 @@ export class StreamViewModel { GamepadManager.getInstance().setDeviceVibrate( deviceVibrateEnabled, this.streamConfig.vibrateFallbackStrength, - this.streamConfig.vibrationMode + this.streamConfig.vibrationMode, + this.streamConfig.gamepadVibrationGain ); } From e3f198ab809de5a1b8a1a0e97c5ce4764ec231ca Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Thu, 18 Jun 2026 11:13:39 +0800 Subject: [PATCH 2/8] fix(input): normalize vibration gain bounds --- entry/src/main/ets/model/StreamConfig.ets | 8 ++++++++ entry/src/main/ets/pages/SettingsPageV2.ets | 9 +++++++-- entry/src/main/ets/service/SettingsService.ets | 11 ++++++++--- .../ets/service/input/GamepadVibrationService.ets | 6 +++--- .../ets/service/usbdriver/NativeHidController.ets | 9 +++++++-- 5 files changed, 33 insertions(+), 10 deletions(-) diff --git a/entry/src/main/ets/model/StreamConfig.ets b/entry/src/main/ets/model/StreamConfig.ets index 63b9de4..aaddede 100644 --- a/entry/src/main/ets/model/StreamConfig.ets +++ b/entry/src/main/ets/model/StreamConfig.ets @@ -18,6 +18,14 @@ export const GAMEPAD_VIBRATION_GAIN_MAX = 200; export const GAMEPAD_VIBRATION_GAIN_DEFAULT = 100; export const GAMEPAD_VIBRATION_GAIN_STEP = 10; +export function normalizeGamepadVibrationGain(value: number): number { + if (!Number.isFinite(value)) { + return GAMEPAD_VIBRATION_GAIN_DEFAULT; + } + const roundedValue = Math.round(value); + return Math.max(GAMEPAD_VIBRATION_GAIN_MIN, Math.min(GAMEPAD_VIBRATION_GAIN_MAX, roundedValue)); +} + export interface StreamConfig { // 视频设置 width: number; diff --git a/entry/src/main/ets/pages/SettingsPageV2.ets b/entry/src/main/ets/pages/SettingsPageV2.ets index 9e60938..356f08c 100644 --- a/entry/src/main/ets/pages/SettingsPageV2.ets +++ b/entry/src/main/ets/pages/SettingsPageV2.ets @@ -20,7 +20,8 @@ import { GAMEPAD_VIBRATION_GAIN_DEFAULT, GAMEPAD_VIBRATION_GAIN_MAX, GAMEPAD_VIBRATION_GAIN_MIN, - GAMEPAD_VIBRATION_GAIN_STEP + GAMEPAD_VIBRATION_GAIN_STEP, + normalizeGamepadVibrationGain } from '../model/StreamConfig'; import { PerfLabels } from '../components/PerformanceOverlayManager'; import { SettingSlider, SettingSliderConfig, LogarithmicSlider } from '../components/SettingSlider'; @@ -526,8 +527,12 @@ struct SettingsPageV2 { this.enableVibration = await this.loadBoolean(SettingsKeys.ENABLE_VIBRATION, true); this.vibrationMode = await PreferencesUtil.get(SettingsKeys.VIBRATION_MODE, '自动'); this.vibrateFallbackStrength = await PreferencesUtil.get(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100); - this.gamepadVibrationGain = + const rawGamepadVibrationGain = await PreferencesUtil.get(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT); + this.gamepadVibrationGain = normalizeGamepadVibrationGain(rawGamepadVibrationGain); + if (this.gamepadVibrationGain !== rawGamepadVibrationGain) { + this.saveSetting(SettingsKeys.GAMEPAD_VIBRATION_GAIN, this.gamepadVibrationGain); + } this.enableAudioVibration = await this.loadBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); this.audioVibrationStrength = await PreferencesUtil.get(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60); this.audioVibrationSceneMode = await PreferencesUtil.get(SettingsKeys.AUDIO_VIBRATION_SCENE_MODE, '游戏/电影'); diff --git a/entry/src/main/ets/service/SettingsService.ets b/entry/src/main/ets/service/SettingsService.ets index d0f235a..af58b9b 100644 --- a/entry/src/main/ets/service/SettingsService.ets +++ b/entry/src/main/ets/service/SettingsService.ets @@ -26,7 +26,8 @@ import { PerfOverlayOrientation, PerfOverlayPosition, getRecommendedBitrate, - GAMEPAD_VIBRATION_GAIN_DEFAULT + GAMEPAD_VIBRATION_GAIN_DEFAULT, + normalizeGamepadVibrationGain } from '../model/StreamConfig'; /** @@ -602,7 +603,9 @@ export class SettingsService { const enableVibration = await this.getBoolean(SettingsKeys.ENABLE_VIBRATION, true); const vibrationMode = await this.getString(SettingsKeys.VIBRATION_MODE, '自动'); const vibrateFallbackStrength = await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100); - const gamepadVibrationGain = await this.getNumber(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT); + const gamepadVibrationGain = normalizeGamepadVibrationGain( + await this.getNumber(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT) + ); const enableAudioVibration = await this.getBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); const audioVibrationStrength = await this.getNumber(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60); const audioVibrationSceneMode = await this.getString(SettingsKeys.AUDIO_VIBRATION_SCENE_MODE, '游戏/电影'); @@ -747,7 +750,9 @@ export class SettingsService { enableVibration: await this.getBoolean(SettingsKeys.ENABLE_VIBRATION, true), vibrationMode: await this.getString(SettingsKeys.VIBRATION_MODE, '自动'), vibrateFallbackStrength: await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100), - gamepadVibrationGain: await this.getNumber(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT), + gamepadVibrationGain: normalizeGamepadVibrationGain( + await this.getNumber(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT) + ), enableAudioVibration: await this.getBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false), audioVibrationStrength: await this.getNumber(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60), audioVibrationSceneMode: await this.getString(SettingsKeys.AUDIO_VIBRATION_SCENE_MODE, '游戏/电影'), diff --git a/entry/src/main/ets/service/input/GamepadVibrationService.ets b/entry/src/main/ets/service/input/GamepadVibrationService.ets index 7d26fe0..b29ed82 100644 --- a/entry/src/main/ets/service/input/GamepadVibrationService.ets +++ b/entry/src/main/ets/service/input/GamepadVibrationService.ets @@ -22,8 +22,7 @@ import { UsbDriverService, AbstractController } from '../usbdriver/index'; import { RUMBLE_MAX } from './GamepadTypes'; import { GAMEPAD_VIBRATION_GAIN_DEFAULT, - GAMEPAD_VIBRATION_GAIN_MAX, - GAMEPAD_VIBRATION_GAIN_MIN + normalizeGamepadVibrationGain } from '../../model/StreamConfig'; // ==================== 震动服务 ==================== @@ -72,7 +71,7 @@ export class GamepadVibrationService { ): void { this.deviceVibrateEnabled = enabled; this.deviceVibrateStrength = strength; - this.gamepadVibrationGain = Math.max(GAMEPAD_VIBRATION_GAIN_MIN, Math.min(GAMEPAD_VIBRATION_GAIN_MAX, gamepadGain)); + this.gamepadVibrationGain = normalizeGamepadVibrationGain(gamepadGain); this.vibrationMode = mode; } @@ -240,6 +239,7 @@ export class GamepadVibrationService { } private clampRumbleValue(value: number): number { + if (!Number.isFinite(value)) return 0; return Math.max(0, Math.min(RUMBLE_MAX, Math.floor(value))); } diff --git a/entry/src/main/ets/service/usbdriver/NativeHidController.ets b/entry/src/main/ets/service/usbdriver/NativeHidController.ets index 8cc15b0..369f65f 100644 --- a/entry/src/main/ets/service/usbdriver/NativeHidController.ets +++ b/entry/src/main/ets/service/usbdriver/NativeHidController.ets @@ -668,8 +668,8 @@ export class NativeHidController extends AbstractController { const cmd = this.nativeParser.createRumbleCommand( this.vendorId, this.productId, - Math.round(lowFreqMotor), - Math.round(highFreqMotor) + this.clampRumbleValue(lowFreqMotor), + this.clampRumbleValue(highFreqMotor) ); if (cmd) { @@ -677,6 +677,11 @@ export class NativeHidController extends AbstractController { } } + private clampRumbleValue(value: number): number { + if (!Number.isFinite(value)) return 0; + return Math.max(0, Math.min(65535, Math.round(value))); + } + private async sendOutputReport(data: Uint8Array): Promise { if (this.outputEndpoint === 0) { return; From c90e900a0ed52a4a1b21fa2110e6a0bc31100062 Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Thu, 18 Jun 2026 11:26:01 +0800 Subject: [PATCH 3/8] fix(input): clarify game vibration controls --- entry/src/main/ets/pages/SettingsPageV2.ets | 6 ++-- .../main/ets/service/input/GamepadManager.ets | 8 ++--- .../service/input/GamepadVibrationService.ets | 29 +++++++++++++++---- .../main/ets/viewmodel/StreamViewModel.ets | 5 ++-- 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/entry/src/main/ets/pages/SettingsPageV2.ets b/entry/src/main/ets/pages/SettingsPageV2.ets index 356f08c..8b15a8d 100644 --- a/entry/src/main/ets/pages/SettingsPageV2.ets +++ b/entry/src/main/ets/pages/SettingsPageV2.ets @@ -1355,7 +1355,7 @@ struct SettingsPageV2 { items: [ { title: '振动反馈', - subtitle: '手柄振动反馈', + subtitle: '串流游戏震动反馈', type: 'toggle', value: this.enableVibration, action: () => { @@ -1376,7 +1376,7 @@ struct SettingsPageV2 { }, { title: '手柄震动增益', - subtitle: '放大发往外接手柄的震动,仍受硬件上限限制', + subtitle: '放大串流游戏发往外接手柄的震动,仍受硬件上限限制', type: 'slider', visible: this.enableVibration, value: this.gamepadVibrationGain, @@ -1391,7 +1391,7 @@ struct SettingsPageV2 { }, { title: '设备振动强度', - subtitle: '使用设备震动时的强度', + subtitle: '无外接手柄或同时模式下的设备震动强度', type: 'slider', visible: this.enableVibration, value: this.vibrateFallbackStrength, diff --git a/entry/src/main/ets/service/input/GamepadManager.ets b/entry/src/main/ets/service/input/GamepadManager.ets index 664eaa1..8461911 100644 --- a/entry/src/main/ets/service/input/GamepadManager.ets +++ b/entry/src/main/ets/service/input/GamepadManager.ets @@ -646,11 +646,11 @@ export class GamepadManager implements UsbDriverListener { } /** - * 设置设备模拟震动 - * @param enabled 是否启用震动 - * @param strength 设备震动强度 (0-100) + * 设置串流游戏震动 + * @param enabled 是否启用串流游戏震动反馈 + * @param strength 设备马达回退强度 (0-100) * @param mode 震动模式:自动/仅手柄/仅设备/同时 - * @param gamepadGain 手柄震动增益 (100=原始强度) + * @param gamepadGain 外接手柄震动增益 (100=原始强度) */ setDeviceVibrate( enabled: boolean, diff --git a/entry/src/main/ets/service/input/GamepadVibrationService.ets b/entry/src/main/ets/service/input/GamepadVibrationService.ets index b29ed82..203e26e 100644 --- a/entry/src/main/ets/service/input/GamepadVibrationService.ets +++ b/entry/src/main/ets/service/input/GamepadVibrationService.ets @@ -31,7 +31,7 @@ export class GamepadVibrationService { private usbDriverService: UsbDriverService; // 设置 - private deviceVibrateEnabled = false; + private vibrationFeedbackEnabled = true; private deviceVibrateStrength = 100; private gamepadVibrationGain = GAMEPAD_VIBRATION_GAIN_DEFAULT; private vibrationMode = '自动'; @@ -69,10 +69,14 @@ export class GamepadVibrationService { mode: string, gamepadGain: number = GAMEPAD_VIBRATION_GAIN_DEFAULT ): void { - this.deviceVibrateEnabled = enabled; + const wasEnabled = this.vibrationFeedbackEnabled; + this.vibrationFeedbackEnabled = enabled; this.deviceVibrateStrength = strength; this.gamepadVibrationGain = normalizeGamepadVibrationGain(gamepadGain); this.vibrationMode = mode; + if (wasEnabled && !enabled) { + this.stopAll(); + } } // ==================== 公开 API ==================== @@ -91,6 +95,8 @@ export class GamepadVibrationService { clearTimeout(this.stopConfirmTimer); this.stopConfirmTimer = -1; } + if (!this.vibrationFeedbackEnabled) return; + if (lowFreqMotor !== 0 || highFreqMotor !== 0) { this.lastRumbleControllerNumber = controllerNumber; this.rumbleWatchdogTimer = setTimeout(() => { @@ -145,6 +151,8 @@ export class GamepadVibrationService { * 处理扳机震动 */ handleRumbleTriggers(controllerNumber: number, leftTrigger: number, rightTrigger: number): void { + if (!this.vibrationFeedbackEnabled) return; + const controllers = this.usbDriverService.getControllers(); const controller = this.findControllerBySlot(controllers, controllerNumber); controller?.rumbleTriggers(this.applyGamepadGain(leftTrigger), this.applyGamepadGain(rightTrigger)); @@ -158,7 +166,7 @@ export class GamepadVibrationService { rumbleUsbControllersOnly(controllerNumber: number, lowFreqMotor: number, highFreqMotor: number): void { const controllers = this.usbDriverService.getControllers(); if (controllers.length > 0) { - this.rumbleUsbControllers(controllers, controllerNumber, lowFreqMotor, highFreqMotor); + this.rumbleUsbControllers(controllers, controllerNumber, lowFreqMotor, highFreqMotor, false); } } @@ -196,6 +204,7 @@ export class GamepadVibrationService { const controllers = this.usbDriverService.getControllers(); for (const controller of controllers) { controller.rumble(0, 0); + controller.rumbleTriggers(0, 0); } } catch (_) { /* ignore */ } } @@ -224,9 +233,17 @@ export class GamepadVibrationService { /** * 向 USB 控制器发送震动 */ - private rumbleUsbControllers(controllers: AbstractController[], controllerNumber: number, lowFreqMotor: number, highFreqMotor: number): void { + private rumbleUsbControllers( + controllers: AbstractController[], + controllerNumber: number, + lowFreqMotor: number, + highFreqMotor: number, + applyGain: boolean = true + ): void { const controller = this.findControllerBySlot(controllers, controllerNumber); - controller?.rumble(this.applyGamepadGain(lowFreqMotor), this.applyGamepadGain(highFreqMotor)); + const lowValue = applyGain ? this.applyGamepadGain(lowFreqMotor) : this.clampRumbleValue(lowFreqMotor); + const highValue = applyGain ? this.applyGamepadGain(highFreqMotor) : this.clampRumbleValue(highFreqMotor); + controller?.rumble(lowValue, highValue); } private applyGamepadGain(value: number): number { @@ -252,7 +269,7 @@ export class GamepadVibrationService { * 3. 使用 stopVibrationSync 同步停止确保即时性 */ private triggerDeviceVibrate(lowFreqMotor: number, highFreqMotor: number): void { - if (!this.deviceVibrateEnabled) return; + if (!this.vibrationFeedbackEnabled || this.deviceVibrateStrength <= 0) return; // 停止震动 if (lowFreqMotor === 0 && highFreqMotor === 0) { diff --git a/entry/src/main/ets/viewmodel/StreamViewModel.ets b/entry/src/main/ets/viewmodel/StreamViewModel.ets index 95a67b5..481fbb7 100644 --- a/entry/src/main/ets/viewmodel/StreamViewModel.ets +++ b/entry/src/main/ets/viewmodel/StreamViewModel.ets @@ -270,10 +270,9 @@ export class StreamViewModel { console.info(`StreamViewModel: 触摸模式=${this.touchMode}`); console.info(`StreamViewModel: 性能覆盖层=${this.showOverlay}, 虚拟控制器=${this.showController}`); - // 配置震动设置 - const deviceVibrateEnabled = this.streamConfig.enableVibration && this.streamConfig.vibrateFallbackStrength > 0; + // 配置串流游戏震动设置;设备强度为 0 时仅关闭设备马达回退,不影响外接手柄。 GamepadManager.getInstance().setDeviceVibrate( - deviceVibrateEnabled, + this.streamConfig.enableVibration, this.streamConfig.vibrateFallbackStrength, this.streamConfig.vibrationMode, this.streamConfig.gamepadVibrationGain From 0a73b81b94e8adc2f7d843fa7534439835cdae43 Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Thu, 18 Jun 2026 11:38:04 +0800 Subject: [PATCH 4/8] refactor(input): fold vibration gain into strength --- entry/src/main/ets/model/StreamConfig.ets | 20 +++---- entry/src/main/ets/pages/SettingsPageV2.ets | 55 +++++++------------ .../src/main/ets/service/SettingsService.ets | 17 ++---- .../main/ets/service/input/GamepadManager.ets | 11 ++-- .../service/input/GamepadVibrationService.ets | 32 +++++------ .../main/ets/viewmodel/StreamViewModel.ets | 5 +- 6 files changed, 57 insertions(+), 83 deletions(-) diff --git a/entry/src/main/ets/model/StreamConfig.ets b/entry/src/main/ets/model/StreamConfig.ets index aaddede..2c3655f 100644 --- a/entry/src/main/ets/model/StreamConfig.ets +++ b/entry/src/main/ets/model/StreamConfig.ets @@ -13,17 +13,17 @@ * * 参考 Android 版本 StreamConfiguration.java */ -export const GAMEPAD_VIBRATION_GAIN_MIN = 50; -export const GAMEPAD_VIBRATION_GAIN_MAX = 200; -export const GAMEPAD_VIBRATION_GAIN_DEFAULT = 100; -export const GAMEPAD_VIBRATION_GAIN_STEP = 10; +export const GAME_VIBRATION_STRENGTH_MIN = 0; +export const GAME_VIBRATION_STRENGTH_MAX = 200; +export const GAME_VIBRATION_STRENGTH_DEFAULT = 100; +export const GAME_VIBRATION_STRENGTH_STEP = 5; -export function normalizeGamepadVibrationGain(value: number): number { +export function normalizeGameVibrationStrength(value: number): number { if (!Number.isFinite(value)) { - return GAMEPAD_VIBRATION_GAIN_DEFAULT; + return GAME_VIBRATION_STRENGTH_DEFAULT; } const roundedValue = Math.round(value); - return Math.max(GAMEPAD_VIBRATION_GAIN_MIN, Math.min(GAMEPAD_VIBRATION_GAIN_MAX, roundedValue)); + return Math.max(GAME_VIBRATION_STRENGTH_MIN, Math.min(GAME_VIBRATION_STRENGTH_MAX, roundedValue)); } export interface StreamConfig { @@ -59,8 +59,7 @@ export interface StreamConfig { attachedGamepadMask: number; enableVibration: boolean; vibrationMode: string; // 震动模式:自动/仅手柄/仅设备/同时 - vibrateFallbackStrength: number; - gamepadVibrationGain: number; // 手柄震动增益百分比(默认 100,最高不突破硬件上限) + vibrateFallbackStrength: number; // 串流游戏震动强度百分比(100=原始强度,100 以上为 app 增益) enableAudioVibration: boolean; // 音频振动(低频驱动) audioVibrationStrength: number; // 音频振动强度 (0-100) audioVibrationSceneMode: string; // 音频振动场景模式: 游戏/电影, 音乐/节奏, 自动 @@ -243,8 +242,7 @@ export function getDefaultStreamConfig(): StreamConfig { attachedGamepadMask: 0, enableVibration: true, vibrationMode: '自动', - vibrateFallbackStrength: 100, - gamepadVibrationGain: GAMEPAD_VIBRATION_GAIN_DEFAULT, + vibrateFallbackStrength: GAME_VIBRATION_STRENGTH_DEFAULT, enableAudioVibration: false, audioVibrationStrength: 60, audioVibrationSceneMode: '游戏/电影', diff --git a/entry/src/main/ets/pages/SettingsPageV2.ets b/entry/src/main/ets/pages/SettingsPageV2.ets index 8b15a8d..42c1647 100644 --- a/entry/src/main/ets/pages/SettingsPageV2.ets +++ b/entry/src/main/ets/pages/SettingsPageV2.ets @@ -17,11 +17,11 @@ import { AppColors, AppSizes, AppSpacing, AppAnimation, AppShadows } from '../co import { StreamingSession, DecoderCapabilities } from '../service/streaming/StreamingSession'; import { getRecommendedBitrate, - GAMEPAD_VIBRATION_GAIN_DEFAULT, - GAMEPAD_VIBRATION_GAIN_MAX, - GAMEPAD_VIBRATION_GAIN_MIN, - GAMEPAD_VIBRATION_GAIN_STEP, - normalizeGamepadVibrationGain + GAME_VIBRATION_STRENGTH_DEFAULT, + GAME_VIBRATION_STRENGTH_MAX, + GAME_VIBRATION_STRENGTH_MIN, + GAME_VIBRATION_STRENGTH_STEP, + normalizeGameVibrationStrength } from '../model/StreamConfig'; import { PerfLabels } from '../components/PerformanceOverlayManager'; import { SettingSlider, SettingSliderConfig, LogarithmicSlider } from '../components/SettingSlider'; @@ -182,8 +182,7 @@ struct SettingsPageV2 { // 输入 - 手柄设置 @State enableVibration: boolean = true; @State vibrationMode: string = '自动'; // 自动/仅手柄/仅设备/同时 - @State vibrateFallbackStrength: number = 100; - @State gamepadVibrationGain: number = GAMEPAD_VIBRATION_GAIN_DEFAULT; + @State vibrateFallbackStrength: number = GAME_VIBRATION_STRENGTH_DEFAULT; @State enableAudioVibration: boolean = false; @State audioVibrationStrength: number = 60; @State audioVibrationSceneMode: string = '游戏/电影'; @@ -526,12 +525,11 @@ struct SettingsPageV2 { // 输入 - 手柄设置 this.enableVibration = await this.loadBoolean(SettingsKeys.ENABLE_VIBRATION, true); this.vibrationMode = await PreferencesUtil.get(SettingsKeys.VIBRATION_MODE, '自动'); - this.vibrateFallbackStrength = await PreferencesUtil.get(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100); - const rawGamepadVibrationGain = - await PreferencesUtil.get(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT); - this.gamepadVibrationGain = normalizeGamepadVibrationGain(rawGamepadVibrationGain); - if (this.gamepadVibrationGain !== rawGamepadVibrationGain) { - this.saveSetting(SettingsKeys.GAMEPAD_VIBRATION_GAIN, this.gamepadVibrationGain); + const rawVibrationStrength = + await PreferencesUtil.get(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, GAME_VIBRATION_STRENGTH_DEFAULT); + this.vibrateFallbackStrength = normalizeGameVibrationStrength(rawVibrationStrength); + if (this.vibrateFallbackStrength !== rawVibrationStrength) { + this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, this.vibrateFallbackStrength); } this.enableAudioVibration = await this.loadBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); this.audioVibrationStrength = await PreferencesUtil.get(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60); @@ -1375,33 +1373,20 @@ struct SettingsPageV2 { } }, { - title: '手柄震动增益', - subtitle: '放大串流游戏发往外接手柄的震动,仍受硬件上限限制', - type: 'slider', - visible: this.enableVibration, - value: this.gamepadVibrationGain, - min: GAMEPAD_VIBRATION_GAIN_MIN, - max: GAMEPAD_VIBRATION_GAIN_MAX, - step: GAMEPAD_VIBRATION_GAIN_STEP, - unit: '%', - onSliderChange: (value: number) => { - this.gamepadVibrationGain = value; - this.saveSetting(SettingsKeys.GAMEPAD_VIBRATION_GAIN, value); - } - }, - { - title: '设备振动强度', - subtitle: '无外接手柄或同时模式下的设备震动强度', + title: '震动强度', + subtitle: this.vibrateFallbackStrength > 100 ? + '超过 100% 为 app 增益,仍受硬件上限限制' : + '串流游戏震动强度,100% 为原始强度', type: 'slider', visible: this.enableVibration, value: this.vibrateFallbackStrength, - min: 0, - max: 100, - step: 5, + min: GAME_VIBRATION_STRENGTH_MIN, + max: GAME_VIBRATION_STRENGTH_MAX, + step: GAME_VIBRATION_STRENGTH_STEP, unit: '%', onSliderChange: (value: number) => { - this.vibrateFallbackStrength = value; - this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, value); + this.vibrateFallbackStrength = normalizeGameVibrationStrength(value); + this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, this.vibrateFallbackStrength); } }, { diff --git a/entry/src/main/ets/service/SettingsService.ets b/entry/src/main/ets/service/SettingsService.ets index af58b9b..babc50a 100644 --- a/entry/src/main/ets/service/SettingsService.ets +++ b/entry/src/main/ets/service/SettingsService.ets @@ -26,8 +26,8 @@ import { PerfOverlayOrientation, PerfOverlayPosition, getRecommendedBitrate, - GAMEPAD_VIBRATION_GAIN_DEFAULT, - normalizeGamepadVibrationGain + GAME_VIBRATION_STRENGTH_DEFAULT, + normalizeGameVibrationStrength } from '../model/StreamConfig'; /** @@ -70,7 +70,6 @@ export class SettingsKeys { static readonly ENABLE_VIBRATION: string = 'settings_enable_vibration'; static readonly VIBRATION_MODE: string = 'settings_vibration_mode'; // 震动模式:自动/仅手柄/仅设备/同时 static readonly VIBRATE_FALLBACK_STRENGTH: string = 'settings_vibrate_fallback_strength'; - static readonly GAMEPAD_VIBRATION_GAIN: string = 'settings_gamepad_vibration_gain'; static readonly ENABLE_AUDIO_VIBRATION: string = 'settings_enable_audio_vibration'; // 音频振动(低频驱动) static readonly AUDIO_VIBRATION_STRENGTH: string = 'settings_audio_vibration_strength'; // 音频振动强度 (0-100) static readonly AUDIO_VIBRATION_SCENE_MODE: string = 'settings_audio_vibration_scene_mode'; // 音频振动场景模式 @@ -187,7 +186,6 @@ export interface InputSettings { enableVibration: boolean; vibrationMode: string; // 自动/仅手柄/仅设备/同时 vibrateFallbackStrength: number; - gamepadVibrationGain: number; enableAudioVibration: boolean; // 音频振动(低频驱动) audioVibrationStrength: number; // 音频振动强度 (0-100) audioVibrationSceneMode: string; // 音频振动场景模式 @@ -602,9 +600,8 @@ export class SettingsService { // 获取输入设置 const enableVibration = await this.getBoolean(SettingsKeys.ENABLE_VIBRATION, true); const vibrationMode = await this.getString(SettingsKeys.VIBRATION_MODE, '自动'); - const vibrateFallbackStrength = await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100); - const gamepadVibrationGain = normalizeGamepadVibrationGain( - await this.getNumber(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT) + const vibrateFallbackStrength = normalizeGameVibrationStrength( + await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, GAME_VIBRATION_STRENGTH_DEFAULT) ); const enableAudioVibration = await this.getBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); const audioVibrationStrength = await this.getNumber(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60); @@ -687,7 +684,6 @@ export class SettingsService { enableVibration: enableVibration, vibrationMode: vibrationMode, vibrateFallbackStrength: vibrateFallbackStrength, - gamepadVibrationGain: gamepadVibrationGain, enableAudioVibration: enableAudioVibration, audioVibrationStrength: audioVibrationStrength, audioVibrationSceneMode: audioVibrationSceneMode, @@ -749,9 +745,8 @@ export class SettingsService { // 手柄 enableVibration: await this.getBoolean(SettingsKeys.ENABLE_VIBRATION, true), vibrationMode: await this.getString(SettingsKeys.VIBRATION_MODE, '自动'), - vibrateFallbackStrength: await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, 100), - gamepadVibrationGain: normalizeGamepadVibrationGain( - await this.getNumber(SettingsKeys.GAMEPAD_VIBRATION_GAIN, GAMEPAD_VIBRATION_GAIN_DEFAULT) + vibrateFallbackStrength: normalizeGameVibrationStrength( + await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, GAME_VIBRATION_STRENGTH_DEFAULT) ), enableAudioVibration: await this.getBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false), audioVibrationStrength: await this.getNumber(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60), diff --git a/entry/src/main/ets/service/input/GamepadManager.ets b/entry/src/main/ets/service/input/GamepadManager.ets index 8461911..4ac1251 100644 --- a/entry/src/main/ets/service/input/GamepadManager.ets +++ b/entry/src/main/ets/service/input/GamepadManager.ets @@ -10,13 +10,12 @@ import { inputDevice } from '@kit.InputKit'; import { UsbDriverService, UsbDriverListener, AbstractController, ButtonFlags, KnownUsbGamepadInfo } from '../usbdriver/index'; -import { +import { gameControllerService, AxisType, GameControllerDeviceInfo } from './GameControllerService'; import { SettingsService, SettingsKeys } from '../SettingsService'; -import { GAMEPAD_VIBRATION_GAIN_DEFAULT } from '../../model/StreamConfig'; import { PreferencesUtil } from '../../utils/PreferencesUtil'; import { DeviceSensorService, LI_MOTION_TYPE_ACCEL, LI_MOTION_TYPE_GYRO } from './DeviceSensorService'; import { MoonBridge } from '../streaming/MoonBridge'; @@ -648,17 +647,15 @@ export class GamepadManager implements UsbDriverListener { /** * 设置串流游戏震动 * @param enabled 是否启用串流游戏震动反馈 - * @param strength 设备马达回退强度 (0-100) + * @param strength 串流游戏震动强度 (0-200, 100=原始强度) * @param mode 震动模式:自动/仅手柄/仅设备/同时 - * @param gamepadGain 外接手柄震动增益 (100=原始强度) */ setDeviceVibrate( enabled: boolean, strength: number, - mode: string, - gamepadGain: number = GAMEPAD_VIBRATION_GAIN_DEFAULT + mode: string ): void { - this.vibrationService.setSettings(enabled, strength, mode, gamepadGain); + this.vibrationService.setSettings(enabled, strength, mode); } /** diff --git a/entry/src/main/ets/service/input/GamepadVibrationService.ets b/entry/src/main/ets/service/input/GamepadVibrationService.ets index 203e26e..70577dc 100644 --- a/entry/src/main/ets/service/input/GamepadVibrationService.ets +++ b/entry/src/main/ets/service/input/GamepadVibrationService.ets @@ -21,8 +21,8 @@ import { vibrator } from '@kit.SensorServiceKit'; import { UsbDriverService, AbstractController } from '../usbdriver/index'; import { RUMBLE_MAX } from './GamepadTypes'; import { - GAMEPAD_VIBRATION_GAIN_DEFAULT, - normalizeGamepadVibrationGain + GAME_VIBRATION_STRENGTH_DEFAULT, + normalizeGameVibrationStrength } from '../../model/StreamConfig'; // ==================== 震动服务 ==================== @@ -32,8 +32,7 @@ export class GamepadVibrationService { // 设置 private vibrationFeedbackEnabled = true; - private deviceVibrateStrength = 100; - private gamepadVibrationGain = GAMEPAD_VIBRATION_GAIN_DEFAULT; + private gameVibrationStrength = GAME_VIBRATION_STRENGTH_DEFAULT; private vibrationMode = '自动'; // 槽位→设备键的查找函数(由 GamepadManager 提供) @@ -66,13 +65,11 @@ export class GamepadVibrationService { setSettings( enabled: boolean, strength: number, - mode: string, - gamepadGain: number = GAMEPAD_VIBRATION_GAIN_DEFAULT + mode: string ): void { const wasEnabled = this.vibrationFeedbackEnabled; this.vibrationFeedbackEnabled = enabled; - this.deviceVibrateStrength = strength; - this.gamepadVibrationGain = normalizeGamepadVibrationGain(gamepadGain); + this.gameVibrationStrength = normalizeGameVibrationStrength(strength); this.vibrationMode = mode; if (wasEnabled && !enabled) { this.stopAll(); @@ -155,7 +152,10 @@ export class GamepadVibrationService { const controllers = this.usbDriverService.getControllers(); const controller = this.findControllerBySlot(controllers, controllerNumber); - controller?.rumbleTriggers(this.applyGamepadGain(leftTrigger), this.applyGamepadGain(rightTrigger)); + controller?.rumbleTriggers( + this.applyGameVibrationStrength(leftTrigger), + this.applyGameVibrationStrength(rightTrigger) + ); } /** @@ -241,17 +241,17 @@ export class GamepadVibrationService { applyGain: boolean = true ): void { const controller = this.findControllerBySlot(controllers, controllerNumber); - const lowValue = applyGain ? this.applyGamepadGain(lowFreqMotor) : this.clampRumbleValue(lowFreqMotor); - const highValue = applyGain ? this.applyGamepadGain(highFreqMotor) : this.clampRumbleValue(highFreqMotor); + const lowValue = applyGain ? this.applyGameVibrationStrength(lowFreqMotor) : this.clampRumbleValue(lowFreqMotor); + const highValue = applyGain ? this.applyGameVibrationStrength(highFreqMotor) : this.clampRumbleValue(highFreqMotor); controller?.rumble(lowValue, highValue); } - private applyGamepadGain(value: number): number { + private applyGameVibrationStrength(value: number): number { if (value <= 0) return 0; - if (this.gamepadVibrationGain === GAMEPAD_VIBRATION_GAIN_DEFAULT) { + if (this.gameVibrationStrength === GAME_VIBRATION_STRENGTH_DEFAULT) { return this.clampRumbleValue(value); } - const gained = Math.floor(value * this.gamepadVibrationGain / 100); + const gained = Math.floor(value * this.gameVibrationStrength / 100); return this.clampRumbleValue(gained); } @@ -269,7 +269,7 @@ export class GamepadVibrationService { * 3. 使用 stopVibrationSync 同步停止确保即时性 */ private triggerDeviceVibrate(lowFreqMotor: number, highFreqMotor: number): void { - if (!this.vibrationFeedbackEnabled || this.deviceVibrateStrength <= 0) return; + if (!this.vibrationFeedbackEnabled || this.gameVibrationStrength <= 0) return; // 停止震动 if (lowFreqMotor === 0 && highFreqMotor === 0) { @@ -294,7 +294,7 @@ export class GamepadVibrationService { this.lastHighFreq = highFreqMotor; // 计算用户强度系数 - const userStrength = this.deviceVibrateStrength / 100; + const userStrength = Math.min(this.gameVibrationStrength, 100) / 100; // 计算低频和高频马达的强度 (0-100) const lowIntensity = Math.floor((lowFreqMotor / RUMBLE_MAX) * userStrength * 100); diff --git a/entry/src/main/ets/viewmodel/StreamViewModel.ets b/entry/src/main/ets/viewmodel/StreamViewModel.ets index 481fbb7..5cbd289 100644 --- a/entry/src/main/ets/viewmodel/StreamViewModel.ets +++ b/entry/src/main/ets/viewmodel/StreamViewModel.ets @@ -270,12 +270,11 @@ export class StreamViewModel { console.info(`StreamViewModel: 触摸模式=${this.touchMode}`); console.info(`StreamViewModel: 性能覆盖层=${this.showOverlay}, 虚拟控制器=${this.showController}`); - // 配置串流游戏震动设置;设备强度为 0 时仅关闭设备马达回退,不影响外接手柄。 + // 配置串流游戏震动;100% 以上作为外接手柄 app 增益,设备马达仍按 100% 封顶。 GamepadManager.getInstance().setDeviceVibrate( this.streamConfig.enableVibration, this.streamConfig.vibrateFallbackStrength, - this.streamConfig.vibrationMode, - this.streamConfig.gamepadVibrationGain + this.streamConfig.vibrationMode ); } From f908dcd32bdac327887e4969e36ce28a9283479f Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Thu, 18 Jun 2026 11:46:42 +0800 Subject: [PATCH 5/8] docs(input): clarify vibration strength gain --- entry/src/main/ets/model/StreamConfig.ets | 2 +- entry/src/main/ets/pages/SettingsPageV2.ets | 2 +- entry/src/main/ets/viewmodel/StreamViewModel.ets | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/entry/src/main/ets/model/StreamConfig.ets b/entry/src/main/ets/model/StreamConfig.ets index 2c3655f..dc85248 100644 --- a/entry/src/main/ets/model/StreamConfig.ets +++ b/entry/src/main/ets/model/StreamConfig.ets @@ -59,7 +59,7 @@ export interface StreamConfig { attachedGamepadMask: number; enableVibration: boolean; vibrationMode: string; // 震动模式:自动/仅手柄/仅设备/同时 - vibrateFallbackStrength: number; // 串流游戏震动强度百分比(100=原始强度,100 以上为 app 增益) + vibrateFallbackStrength: number; // 串流游戏震动强度百分比(100=原始强度,100 以上为 app 侧放大) enableAudioVibration: boolean; // 音频振动(低频驱动) audioVibrationStrength: number; // 音频振动强度 (0-100) audioVibrationSceneMode: string; // 音频振动场景模式: 游戏/电影, 音乐/节奏, 自动 diff --git a/entry/src/main/ets/pages/SettingsPageV2.ets b/entry/src/main/ets/pages/SettingsPageV2.ets index 42c1647..94e6a06 100644 --- a/entry/src/main/ets/pages/SettingsPageV2.ets +++ b/entry/src/main/ets/pages/SettingsPageV2.ets @@ -1375,7 +1375,7 @@ struct SettingsPageV2 { { title: '震动强度', subtitle: this.vibrateFallbackStrength > 100 ? - '超过 100% 为 app 增益,仍受硬件上限限制' : + '超过 100% 为 app 侧放大,不突破系统/硬件上限' : '串流游戏震动强度,100% 为原始强度', type: 'slider', visible: this.enableVibration, diff --git a/entry/src/main/ets/viewmodel/StreamViewModel.ets b/entry/src/main/ets/viewmodel/StreamViewModel.ets index 5cbd289..78524cd 100644 --- a/entry/src/main/ets/viewmodel/StreamViewModel.ets +++ b/entry/src/main/ets/viewmodel/StreamViewModel.ets @@ -270,7 +270,7 @@ export class StreamViewModel { console.info(`StreamViewModel: 触摸模式=${this.touchMode}`); console.info(`StreamViewModel: 性能覆盖层=${this.showOverlay}, 虚拟控制器=${this.showController}`); - // 配置串流游戏震动;100% 以上作为外接手柄 app 增益,设备马达仍按 100% 封顶。 + // 配置串流游戏震动;100% 以上作为外接手柄 app 侧放大,设备马达仍按 100% 封顶。 GamepadManager.getInstance().setDeviceVibrate( this.streamConfig.enableVibration, this.streamConfig.vibrateFallbackStrength, From 48c849c16d719fdf5f6b05e5a32231a0c1c194e7 Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Thu, 18 Jun 2026 12:13:12 +0800 Subject: [PATCH 6/8] refactor(input): clarify game vibration strength naming --- entry/src/main/ets/model/StreamConfig.ets | 7 ++++--- entry/src/main/ets/pages/SettingsPageV2.ets | 17 +++++++++-------- entry/src/main/ets/service/SettingsService.ets | 10 +++++----- .../service/input/GamepadVibrationService.ets | 6 ++++-- .../src/main/ets/viewmodel/StreamViewModel.ets | 2 +- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/entry/src/main/ets/model/StreamConfig.ets b/entry/src/main/ets/model/StreamConfig.ets index dc85248..b0d8d30 100644 --- a/entry/src/main/ets/model/StreamConfig.ets +++ b/entry/src/main/ets/model/StreamConfig.ets @@ -15,7 +15,8 @@ */ export const GAME_VIBRATION_STRENGTH_MIN = 0; export const GAME_VIBRATION_STRENGTH_MAX = 200; -export const GAME_VIBRATION_STRENGTH_DEFAULT = 100; +export const GAME_VIBRATION_STRENGTH_ORIGINAL = 100; +export const GAME_VIBRATION_STRENGTH_DEFAULT = GAME_VIBRATION_STRENGTH_ORIGINAL; export const GAME_VIBRATION_STRENGTH_STEP = 5; export function normalizeGameVibrationStrength(value: number): number { @@ -59,7 +60,7 @@ export interface StreamConfig { attachedGamepadMask: number; enableVibration: boolean; vibrationMode: string; // 震动模式:自动/仅手柄/仅设备/同时 - vibrateFallbackStrength: number; // 串流游戏震动强度百分比(100=原始强度,100 以上为 app 侧放大) + gameVibrationStrength: number; // 串流游戏震动强度百分比(100=原始强度,100 以上为 app 侧放大) enableAudioVibration: boolean; // 音频振动(低频驱动) audioVibrationStrength: number; // 音频振动强度 (0-100) audioVibrationSceneMode: string; // 音频振动场景模式: 游戏/电影, 音乐/节奏, 自动 @@ -242,7 +243,7 @@ export function getDefaultStreamConfig(): StreamConfig { attachedGamepadMask: 0, enableVibration: true, vibrationMode: '自动', - vibrateFallbackStrength: GAME_VIBRATION_STRENGTH_DEFAULT, + gameVibrationStrength: GAME_VIBRATION_STRENGTH_DEFAULT, enableAudioVibration: false, audioVibrationStrength: 60, audioVibrationSceneMode: '游戏/电影', diff --git a/entry/src/main/ets/pages/SettingsPageV2.ets b/entry/src/main/ets/pages/SettingsPageV2.ets index 94e6a06..1eacabb 100644 --- a/entry/src/main/ets/pages/SettingsPageV2.ets +++ b/entry/src/main/ets/pages/SettingsPageV2.ets @@ -20,6 +20,7 @@ import { GAME_VIBRATION_STRENGTH_DEFAULT, GAME_VIBRATION_STRENGTH_MAX, GAME_VIBRATION_STRENGTH_MIN, + GAME_VIBRATION_STRENGTH_ORIGINAL, GAME_VIBRATION_STRENGTH_STEP, normalizeGameVibrationStrength } from '../model/StreamConfig'; @@ -182,7 +183,7 @@ struct SettingsPageV2 { // 输入 - 手柄设置 @State enableVibration: boolean = true; @State vibrationMode: string = '自动'; // 自动/仅手柄/仅设备/同时 - @State vibrateFallbackStrength: number = GAME_VIBRATION_STRENGTH_DEFAULT; + @State gameVibrationStrength: number = GAME_VIBRATION_STRENGTH_DEFAULT; @State enableAudioVibration: boolean = false; @State audioVibrationStrength: number = 60; @State audioVibrationSceneMode: string = '游戏/电影'; @@ -527,9 +528,9 @@ struct SettingsPageV2 { this.vibrationMode = await PreferencesUtil.get(SettingsKeys.VIBRATION_MODE, '自动'); const rawVibrationStrength = await PreferencesUtil.get(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, GAME_VIBRATION_STRENGTH_DEFAULT); - this.vibrateFallbackStrength = normalizeGameVibrationStrength(rawVibrationStrength); - if (this.vibrateFallbackStrength !== rawVibrationStrength) { - this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, this.vibrateFallbackStrength); + this.gameVibrationStrength = normalizeGameVibrationStrength(rawVibrationStrength); + if (this.gameVibrationStrength !== rawVibrationStrength) { + this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, this.gameVibrationStrength); } this.enableAudioVibration = await this.loadBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); this.audioVibrationStrength = await PreferencesUtil.get(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60); @@ -1374,19 +1375,19 @@ struct SettingsPageV2 { }, { title: '震动强度', - subtitle: this.vibrateFallbackStrength > 100 ? + subtitle: this.gameVibrationStrength > GAME_VIBRATION_STRENGTH_ORIGINAL ? '超过 100% 为 app 侧放大,不突破系统/硬件上限' : '串流游戏震动强度,100% 为原始强度', type: 'slider', visible: this.enableVibration, - value: this.vibrateFallbackStrength, + value: this.gameVibrationStrength, min: GAME_VIBRATION_STRENGTH_MIN, max: GAME_VIBRATION_STRENGTH_MAX, step: GAME_VIBRATION_STRENGTH_STEP, unit: '%', onSliderChange: (value: number) => { - this.vibrateFallbackStrength = normalizeGameVibrationStrength(value); - this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, this.vibrateFallbackStrength); + this.gameVibrationStrength = normalizeGameVibrationStrength(value); + this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, this.gameVibrationStrength); } }, { diff --git a/entry/src/main/ets/service/SettingsService.ets b/entry/src/main/ets/service/SettingsService.ets index babc50a..7cb65d0 100644 --- a/entry/src/main/ets/service/SettingsService.ets +++ b/entry/src/main/ets/service/SettingsService.ets @@ -69,7 +69,7 @@ export class SettingsKeys { // 输入 - 手柄设置 static readonly ENABLE_VIBRATION: string = 'settings_enable_vibration'; static readonly VIBRATION_MODE: string = 'settings_vibration_mode'; // 震动模式:自动/仅手柄/仅设备/同时 - static readonly VIBRATE_FALLBACK_STRENGTH: string = 'settings_vibrate_fallback_strength'; + static readonly VIBRATE_FALLBACK_STRENGTH: string = 'settings_vibrate_fallback_strength'; // 历史存储键,现用于游戏震动强度 static readonly ENABLE_AUDIO_VIBRATION: string = 'settings_enable_audio_vibration'; // 音频振动(低频驱动) static readonly AUDIO_VIBRATION_STRENGTH: string = 'settings_audio_vibration_strength'; // 音频振动强度 (0-100) static readonly AUDIO_VIBRATION_SCENE_MODE: string = 'settings_audio_vibration_scene_mode'; // 音频振动场景模式 @@ -185,7 +185,7 @@ export interface InputSettings { // 手柄 enableVibration: boolean; vibrationMode: string; // 自动/仅手柄/仅设备/同时 - vibrateFallbackStrength: number; + gameVibrationStrength: number; enableAudioVibration: boolean; // 音频振动(低频驱动) audioVibrationStrength: number; // 音频振动强度 (0-100) audioVibrationSceneMode: string; // 音频振动场景模式 @@ -600,7 +600,7 @@ export class SettingsService { // 获取输入设置 const enableVibration = await this.getBoolean(SettingsKeys.ENABLE_VIBRATION, true); const vibrationMode = await this.getString(SettingsKeys.VIBRATION_MODE, '自动'); - const vibrateFallbackStrength = normalizeGameVibrationStrength( + const gameVibrationStrength = normalizeGameVibrationStrength( await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, GAME_VIBRATION_STRENGTH_DEFAULT) ); const enableAudioVibration = await this.getBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); @@ -683,7 +683,7 @@ export class SettingsService { attachedGamepadMask: 0, enableVibration: enableVibration, vibrationMode: vibrationMode, - vibrateFallbackStrength: vibrateFallbackStrength, + gameVibrationStrength: gameVibrationStrength, enableAudioVibration: enableAudioVibration, audioVibrationStrength: audioVibrationStrength, audioVibrationSceneMode: audioVibrationSceneMode, @@ -745,7 +745,7 @@ export class SettingsService { // 手柄 enableVibration: await this.getBoolean(SettingsKeys.ENABLE_VIBRATION, true), vibrationMode: await this.getString(SettingsKeys.VIBRATION_MODE, '自动'), - vibrateFallbackStrength: normalizeGameVibrationStrength( + gameVibrationStrength: normalizeGameVibrationStrength( await this.getNumber(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, GAME_VIBRATION_STRENGTH_DEFAULT) ), enableAudioVibration: await this.getBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false), diff --git a/entry/src/main/ets/service/input/GamepadVibrationService.ets b/entry/src/main/ets/service/input/GamepadVibrationService.ets index 70577dc..b21d39f 100644 --- a/entry/src/main/ets/service/input/GamepadVibrationService.ets +++ b/entry/src/main/ets/service/input/GamepadVibrationService.ets @@ -22,6 +22,7 @@ import { UsbDriverService, AbstractController } from '../usbdriver/index'; import { RUMBLE_MAX } from './GamepadTypes'; import { GAME_VIBRATION_STRENGTH_DEFAULT, + GAME_VIBRATION_STRENGTH_ORIGINAL, normalizeGameVibrationStrength } from '../../model/StreamConfig'; @@ -251,7 +252,7 @@ export class GamepadVibrationService { if (this.gameVibrationStrength === GAME_VIBRATION_STRENGTH_DEFAULT) { return this.clampRumbleValue(value); } - const gained = Math.floor(value * this.gameVibrationStrength / 100); + const gained = Math.floor(value * this.gameVibrationStrength / GAME_VIBRATION_STRENGTH_ORIGINAL); return this.clampRumbleValue(gained); } @@ -294,7 +295,8 @@ export class GamepadVibrationService { this.lastHighFreq = highFreqMotor; // 计算用户强度系数 - const userStrength = Math.min(this.gameVibrationStrength, 100) / 100; + const userStrength = Math.min(this.gameVibrationStrength, GAME_VIBRATION_STRENGTH_ORIGINAL) / + GAME_VIBRATION_STRENGTH_ORIGINAL; // 计算低频和高频马达的强度 (0-100) const lowIntensity = Math.floor((lowFreqMotor / RUMBLE_MAX) * userStrength * 100); diff --git a/entry/src/main/ets/viewmodel/StreamViewModel.ets b/entry/src/main/ets/viewmodel/StreamViewModel.ets index 78524cd..3b04474 100644 --- a/entry/src/main/ets/viewmodel/StreamViewModel.ets +++ b/entry/src/main/ets/viewmodel/StreamViewModel.ets @@ -273,7 +273,7 @@ export class StreamViewModel { // 配置串流游戏震动;100% 以上作为外接手柄 app 侧放大,设备马达仍按 100% 封顶。 GamepadManager.getInstance().setDeviceVibrate( this.streamConfig.enableVibration, - this.streamConfig.vibrateFallbackStrength, + this.streamConfig.gameVibrationStrength, this.streamConfig.vibrationMode ); } From 5ea1050b5805e270dec4637205dec034140dc307 Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Thu, 18 Jun 2026 12:41:18 +0800 Subject: [PATCH 7/8] fix(input): preserve zero vibration strength --- entry/src/main/ets/service/SettingsService.ets | 9 +++++++-- .../main/ets/service/input/GamepadVibrationService.ets | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/entry/src/main/ets/service/SettingsService.ets b/entry/src/main/ets/service/SettingsService.ets index 7cb65d0..f6a6531 100644 --- a/entry/src/main/ets/service/SettingsService.ets +++ b/entry/src/main/ets/service/SettingsService.ets @@ -529,9 +529,14 @@ export class SettingsService { private async getNumber(key: string, defaultValue: number): Promise { const value = await PreferencesUtil.get(key, defaultValue.toString()); if (typeof value === 'number') { - return value; + return Number.isFinite(value) ? value : defaultValue; + } + const trimmedValue = value.trim(); + if (trimmedValue.length === 0) { + return defaultValue; } - return parseInt(value) || defaultValue; + const parsed = Number(trimmedValue); + return Number.isFinite(parsed) ? parsed : defaultValue; } /** diff --git a/entry/src/main/ets/service/input/GamepadVibrationService.ets b/entry/src/main/ets/service/input/GamepadVibrationService.ets index b21d39f..67c5c6b 100644 --- a/entry/src/main/ets/service/input/GamepadVibrationService.ets +++ b/entry/src/main/ets/service/input/GamepadVibrationService.ets @@ -69,10 +69,11 @@ export class GamepadVibrationService { mode: string ): void { const wasEnabled = this.vibrationFeedbackEnabled; + const previousStrength = this.gameVibrationStrength; this.vibrationFeedbackEnabled = enabled; this.gameVibrationStrength = normalizeGameVibrationStrength(strength); this.vibrationMode = mode; - if (wasEnabled && !enabled) { + if ((wasEnabled && !enabled) || (previousStrength > 0 && this.gameVibrationStrength === 0)) { this.stopAll(); } } From 43e3bb3ec6bb48ba0829a5dbdd7e69c89428685f Mon Sep 17 00:00:00 2001 From: qiin <414382190@qq.com> Date: Thu, 18 Jun 2026 13:06:50 +0800 Subject: [PATCH 8/8] fix(input): harden game vibration path --- entry/src/main/ets/pages/SettingsPageV2.ets | 39 ++++++++++++++++--- .../main/ets/service/input/GamepadManager.ets | 2 +- .../service/input/GamepadVibrationService.ets | 17 +++++--- .../main/ets/viewmodel/StreamViewModel.ets | 2 +- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/entry/src/main/ets/pages/SettingsPageV2.ets b/entry/src/main/ets/pages/SettingsPageV2.ets index 1eacabb..2c2310d 100644 --- a/entry/src/main/ets/pages/SettingsPageV2.ets +++ b/entry/src/main/ets/pages/SettingsPageV2.ets @@ -526,12 +526,7 @@ struct SettingsPageV2 { // 输入 - 手柄设置 this.enableVibration = await this.loadBoolean(SettingsKeys.ENABLE_VIBRATION, true); this.vibrationMode = await PreferencesUtil.get(SettingsKeys.VIBRATION_MODE, '自动'); - const rawVibrationStrength = - await PreferencesUtil.get(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, GAME_VIBRATION_STRENGTH_DEFAULT); - this.gameVibrationStrength = normalizeGameVibrationStrength(rawVibrationStrength); - if (this.gameVibrationStrength !== rawVibrationStrength) { - this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, this.gameVibrationStrength); - } + this.gameVibrationStrength = await this.loadGameVibrationStrength(); this.enableAudioVibration = await this.loadBoolean(SettingsKeys.ENABLE_AUDIO_VIBRATION, false); this.audioVibrationStrength = await PreferencesUtil.get(SettingsKeys.AUDIO_VIBRATION_STRENGTH, 60); this.audioVibrationSceneMode = await PreferencesUtil.get(SettingsKeys.AUDIO_VIBRATION_SCENE_MODE, '游戏/电影'); @@ -654,6 +649,38 @@ struct SettingsPageV2 { return String(val) === 'true'; } + private async loadGameVibrationStrength(): Promise { + const rawValue = await PreferencesUtil.get( + SettingsKeys.VIBRATE_FALLBACK_STRENGTH, + GAME_VIBRATION_STRENGTH_DEFAULT.toString() + ); + let parsedValue = GAME_VIBRATION_STRENGTH_DEFAULT; + let shouldRepair = false; + + if (typeof rawValue === 'number') { + parsedValue = Number.isFinite(rawValue) ? rawValue : GAME_VIBRATION_STRENGTH_DEFAULT; + shouldRepair = parsedValue !== rawValue; + } else { + const trimmedValue = rawValue.trim(); + if (trimmedValue.length === 0) { + shouldRepair = true; + } else { + const numberValue = Number(trimmedValue); + if (Number.isFinite(numberValue)) { + parsedValue = numberValue; + } else { + shouldRepair = true; + } + } + } + + const normalizedValue = normalizeGameVibrationStrength(parsedValue); + if (shouldRepair || normalizedValue !== parsedValue) { + this.saveSetting(SettingsKeys.VIBRATE_FALLBACK_STRENGTH, normalizedValue); + } + return normalizedValue; + } + private async saveSetting(key: string, value: string | boolean | number): Promise { try { await PreferencesUtil.put(key, value); diff --git a/entry/src/main/ets/service/input/GamepadManager.ets b/entry/src/main/ets/service/input/GamepadManager.ets index 4ac1251..2ba8de3 100644 --- a/entry/src/main/ets/service/input/GamepadManager.ets +++ b/entry/src/main/ets/service/input/GamepadManager.ets @@ -650,7 +650,7 @@ export class GamepadManager implements UsbDriverListener { * @param strength 串流游戏震动强度 (0-200, 100=原始强度) * @param mode 震动模式:自动/仅手柄/仅设备/同时 */ - setDeviceVibrate( + setGameVibration( enabled: boolean, strength: number, mode: string diff --git a/entry/src/main/ets/service/input/GamepadVibrationService.ets b/entry/src/main/ets/service/input/GamepadVibrationService.ets index 67c5c6b..0742082 100644 --- a/entry/src/main/ets/service/input/GamepadVibrationService.ets +++ b/entry/src/main/ets/service/input/GamepadVibrationService.ets @@ -138,11 +138,7 @@ export class GamepadVibrationService { // USB 停止确认: 100ms 后重发 stop(0,0),防止首次 USB 传输被覆盖或丢失 if (lowFreqMotor === 0 && highFreqMotor === 0 && hasUsbController) { - this.stopConfirmTimer = setTimeout(() => { - this.stopConfirmTimer = -1; - const ctrls = this.usbDriverService.getControllers(); - this.rumbleUsbControllers(ctrls, controllerNumber, 0, 0); - }, 100); + this.scheduleUsbStopConfirm(controllerNumber); } } @@ -208,6 +204,9 @@ export class GamepadVibrationService { controller.rumble(0, 0); controller.rumbleTriggers(0, 0); } + if (controllers.length > 0) { + this.scheduleUsbStopConfirm(this.lastRumbleControllerNumber); + } } catch (_) { /* ignore */ } } @@ -262,6 +261,14 @@ export class GamepadVibrationService { return Math.max(0, Math.min(RUMBLE_MAX, Math.floor(value))); } + private scheduleUsbStopConfirm(controllerNumber: number): void { + this.stopConfirmTimer = setTimeout(() => { + this.stopConfirmTimer = -1; + const controllers = this.usbDriverService.getControllers(); + this.rumbleUsbControllers(controllers, controllerNumber, 0, 0); + }, 100); + } + /** * 触发设备震动(后备方案) * diff --git a/entry/src/main/ets/viewmodel/StreamViewModel.ets b/entry/src/main/ets/viewmodel/StreamViewModel.ets index 3b04474..fade3d7 100644 --- a/entry/src/main/ets/viewmodel/StreamViewModel.ets +++ b/entry/src/main/ets/viewmodel/StreamViewModel.ets @@ -271,7 +271,7 @@ export class StreamViewModel { console.info(`StreamViewModel: 性能覆盖层=${this.showOverlay}, 虚拟控制器=${this.showController}`); // 配置串流游戏震动;100% 以上作为外接手柄 app 侧放大,设备马达仍按 100% 封顶。 - GamepadManager.getInstance().setDeviceVibrate( + GamepadManager.getInstance().setGameVibration( this.streamConfig.enableVibration, this.streamConfig.gameVibrationStrength, this.streamConfig.vibrationMode