diff --git a/src/enums/pref-keys.ts b/src/enums/pref-keys.ts index b0eae9e..56ad2c2 100644 --- a/src/enums/pref-keys.ts +++ b/src/enums/pref-keys.ts @@ -41,6 +41,7 @@ export enum PrefKey { CONTROLLER_DEVICE_VIBRATION = 'controller_device_vibration', CONTROLLER_VIBRATION_INTENSITY = 'controller_vibration_intensity', CONTROLLER_SHOW_CONNECTION_STATUS = 'controller_show_connection_status', + CONTROLLER_POLLING_RATE = 'controller_polling_rate', NATIVE_MKB_ENABLED = 'native_mkb_enabled', NATIVE_MKB_SCROLL_HORIZONTAL_SENSITIVITY = 'native_mkb_scroll_x_sensitivity', diff --git a/src/index.ts b/src/index.ts index 643b905..d4a4b0c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,7 @@ import { BxExposed } from "@utils/bx-exposed"; import { t } from "@utils/translation"; import { interceptHttpRequests } from "@utils/network"; import { CE } from "@utils/html"; -import { showGamepadToast } from "@utils/gamepad"; +import { showGamepadToast, updatePollingRate } from "@utils/gamepad"; import { EmulatedMkbHandler } from "@modules/mkb/mkb-handler"; import { StreamBadges } from "@modules/stream/stream-badges"; import { StreamStats } from "@modules/stream/stream-stats"; @@ -360,6 +360,7 @@ function main() { StreamStats.setupEvents(); if (isFullVersion()) { + updatePollingRate(); STATES.userAgent.capabilities.touch && TouchController.updateCustomList(); overridePreloadState(); diff --git a/src/modules/patcher.ts b/src/modules/patcher.ts index 4558c76..bd7b741 100644 --- a/src/modules/patcher.ts +++ b/src/modules/patcher.ts @@ -202,12 +202,17 @@ const PATCHES = { return false; } - const nextIndex = str.indexOf('setTimeout(this.pollGamepads', index); - if (nextIndex === -1) { + const setTimeoutIndex = str.indexOf('setTimeout(this.pollGamepads', index); + if (setTimeoutIndex < 0) { return false; } - let codeBlock = str.substring(index, nextIndex); + let codeBlock = str.substring(index, setTimeoutIndex); + + // Patch polling rate + const tmp = str.substring(setTimeoutIndex, setTimeoutIndex + 150); + const tmpPatched = tmp.replaceAll('Math.max(0,4-', 'Math.max(0,window.BX_CONTROLLER_POLLING_RATE-'); + str = PatcherUtils.replaceWith(str, setTimeoutIndex, tmp, tmpPatched); // Block gamepad stats collecting if (getPref(PrefKey.BLOCK_TRACKING)) { @@ -226,7 +231,8 @@ const PATCHES = { codeBlock = codeBlock.replace('this.gamepadTimestamps.set', newCode + 'this.gamepadTimestamps.set'); } - return str.substring(0, index) + codeBlock + str.substring(nextIndex); + str = str.substring(0, index) + codeBlock + str.substring(setTimeoutIndex); + return str; }, enableXcloudLogger(str: string) { diff --git a/src/modules/ui/dialog/settings-dialog.ts b/src/modules/ui/dialog/settings-dialog.ts index a75632f..e407fcf 100644 --- a/src/modules/ui/dialog/settings-dialog.ts +++ b/src/modules/ui/dialog/settings-dialog.ts @@ -28,6 +28,7 @@ import { SettingElement, type BxHtmlSettingElement } from "@/utils/setting-eleme import type { RecommendedSettings, SettingDefinition, SuggestedSettingCategory as SuggestedSettingProfile } from "@/types/setting-definition"; import { FullscreenText } from "../fullscreen-text"; import { BxLogger } from "@/utils/bx-logger"; +import { updatePollingRate } from "@/utils/gamepad"; type SettingTabContentItem = Partial<{ @@ -460,6 +461,9 @@ export class SettingsNavigationDialog extends NavigationDialog { pref: PrefKey.CONTROLLER_VIBRATION_INTENSITY, unsupported: !VibrationManager.supportDeviceVibration(), onChange: () => VibrationManager.updateGlobalVars(), + }, isFullVersion() && { + pref: PrefKey.CONTROLLER_POLLING_RATE, + onChange: () => updatePollingRate(), }], }, diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 8d719ec..02d5a88 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -12,6 +12,7 @@ interface Window { BX_EXPOSED: any; BX_VIBRATION_INTENSITY: number; + BX_CONTROLLER_POLLING_RATE: number; BX_ENABLE_CONTROLLER_VIBRATION: boolean; BX_ENABLE_DEVICE_VIBRATION: boolean; diff --git a/src/types/setting-definition.d.ts b/src/types/setting-definition.d.ts index dae1e0d..a6989dc 100644 --- a/src/types/setting-definition.d.ts +++ b/src/types/setting-definition.d.ts @@ -59,4 +59,5 @@ export type NumberStepperParams = Partial<{ exactTicks: number; customTextValue: (value: any) => string | null; + reverse: boolean; }> diff --git a/src/utils/gamepad.ts b/src/utils/gamepad.ts index dd4c2ef..74d56a3 100644 --- a/src/utils/gamepad.ts +++ b/src/utils/gamepad.ts @@ -33,3 +33,7 @@ export function showGamepadToast(gamepad: Gamepad) { Toast.show(text, status, {instant: false}); } + +export function updatePollingRate() { + window.BX_CONTROLLER_POLLING_RATE = getPref(PrefKey.CONTROLLER_POLLING_RATE); +} diff --git a/src/utils/setting-element.ts b/src/utils/setting-element.ts index a7a9f93..79c98ba 100644 --- a/src/utils/setting-element.ts +++ b/src/utils/setting-element.ts @@ -160,8 +160,8 @@ export class SettingElement { let controlValue = value; - const MIN = setting.min!; - const MAX = setting.max!; + const MIN = options.reverse ? -setting.max! : setting.min!; + const MAX = options.reverse ? -setting.min! : setting.max!; const STEPS = Math.max(setting.steps || 1, 1); const renderTextValue = (value: any) => { @@ -216,7 +216,7 @@ export class SettingElement { type: 'range', min: MIN, max: MAX, - value: value, + value: options.reverse ? -value : value, step: STEPS, tabindex: 0, }); @@ -225,13 +225,16 @@ export class SettingElement { $range.addEventListener('input', e => { value = parseInt((e.target as HTMLInputElement).value); - const valueChanged = controlValue !== value; + if (options.reverse) { + value *= -1; + } + const valueChanged = controlValue !== value; if (!valueChanged) { return; } - controlValue = value; + controlValue = options.reverse ? -value : value; updateButtonsVisibility(); $text.textContent = renderTextValue(value); @@ -324,7 +327,7 @@ export class SettingElement { // Custom method $wrapper.setValue = (value: any) => { $text.textContent = renderTextValue(value); - $range.value = value; + $range.value = options.reverse ? -value : value; }; $btnDec.addEventListener('click', onClick); diff --git a/src/utils/settings-storages/global-settings-storage.ts b/src/utils/settings-storages/global-settings-storage.ts index 0bccfce..76f6f0b 100644 --- a/src/utils/settings-storages/global-settings-storage.ts +++ b/src/utils/settings-storages/global-settings-storage.ts @@ -388,6 +388,29 @@ export class GlobalSettingsStorage extends BaseSettingsStorage { }, }, + [PrefKey.CONTROLLER_POLLING_RATE]: { + requiredVariants: 'full', + label: t('polling-rate'), + type: SettingElementType.NUMBER_STEPPER, + default: 4, + min: 4, + max: 40, + steps: 4, + params: { + reverse: true, + customTextValue(value: any) { + value = parseInt(value); + + let text = +(1000 / value).toFixed(2) + ' Hz'; + if (value === 4) { + text = `${t('default')} (${text})`; + } + + return text; + }, + }, + }, + [PrefKey.MKB_ENABLED]: { requiredVariants: 'full', label: t('enable-mkb'), diff --git a/src/utils/translation.ts b/src/utils/translation.ts index 1cf273c..779bf89 100644 --- a/src/utils/translation.ts +++ b/src/utils/translation.ts @@ -188,6 +188,7 @@ const Texts = { "playing": "Playing", "playtime": "Playtime", "poland": "Poland", + "polling-rate": "Polling rate", "position": "Position", "powered-off": "Powered off", "powered-on": "Powered on",