Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions entry/src/main/ets/model/StreamConfig.ets
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export interface StreamConfig {
// 鼠标/触控设置
showLocalCursor: boolean;
touchscreenTrackpad: boolean;
lowLatencyTouch: boolean;
enableDoubleClickDrag: boolean;
doubleTapTimeThreshold: number;

Expand Down Expand Up @@ -253,6 +254,7 @@ export function getDefaultStreamConfig(): StreamConfig {
// 鼠标/触控设置
showLocalCursor: false,
touchscreenTrackpad: false,
lowLatencyTouch: false,
enableDoubleClickDrag: false,
doubleTapTimeThreshold: 125,

Expand Down
12 changes: 12 additions & 0 deletions entry/src/main/ets/pages/SettingsPageV2.ets
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ struct SettingsPageV2 {
// 输入 - 鼠标/触控
@State showLocalCursor: boolean = false; // 显示本地指针(双光标模式)
@State touchscreenTrackpad: boolean = false;
@State lowLatencyTouch: boolean = false;
@State enableDoubleClickDrag: boolean = false;
@State doubleTapTimeThreshold: number = 125;
@State mouseNavButtons: boolean = false;
Expand Down Expand Up @@ -561,6 +562,7 @@ struct SettingsPageV2 {
// 输入 - 鼠标/触控
this.showLocalCursor = await this.loadBoolean(SettingsKeys.SHOW_LOCAL_CURSOR, false);
this.touchscreenTrackpad = await this.loadBoolean(SettingsKeys.TOUCHSCREEN_TRACKPAD, false);
this.lowLatencyTouch = await this.loadBoolean(SettingsKeys.LOW_LATENCY_TOUCH, false);
this.enableDoubleClickDrag = await this.loadBoolean(SettingsKeys.ENABLE_DOUBLE_CLICK_DRAG, false);
this.doubleTapTimeThreshold = await PreferencesUtil.get<number>(SettingsKeys.DOUBLE_TAP_TIME_THRESHOLD, 125);
this.mouseNavButtons = await this.loadBoolean(SettingsKeys.MOUSE_NAV_BUTTONS, false);
Expand Down Expand Up @@ -1697,6 +1699,16 @@ struct SettingsPageV2 {
this.saveSetting(SettingsKeys.LAST_TOUCH_MODE, '');
}
},
{
title: '低延迟触摸参数',
subtitle: '缩短触摸点击确认和释放等待,响应更快但更敏感',
type: 'toggle',
value: this.lowLatencyTouch,
action: () => {
this.lowLatencyTouch = !this.lowLatencyTouch;
this.saveSetting(SettingsKeys.LOW_LATENCY_TOUCH, this.lowLatencyTouch);
}
},
{
title: '双击拖动',
subtitle: '双击并按住可拖动',
Expand Down
1 change: 1 addition & 0 deletions entry/src/main/ets/pages/StreamPage.ets
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,7 @@ struct StreamPage {
if (streamConfig) {
this.touchInputHandler.setDoubleTapTimeThreshold(streamConfig.doubleTapTimeThreshold);
this.touchInputHandler.setEnableDoubleClickDrag(streamConfig.enableDoubleClickDrag);
this.touchInputHandler.setLowLatencyTouch(streamConfig.lowLatencyTouch);
}

// 设置连接终止回调
Expand Down
5 changes: 5 additions & 0 deletions entry/src/main/ets/service/SettingsService.ets
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export class SettingsKeys {
// 输入 - 鼠标/触控
static readonly SHOW_LOCAL_CURSOR: string = 'settings_show_local_cursor';
static readonly TOUCHSCREEN_TRACKPAD: string = 'settings_touchscreen_trackpad';
static readonly LOW_LATENCY_TOUCH: string = 'settings_low_latency_touch';
static readonly ENABLE_DOUBLE_CLICK_DRAG: string = 'settings_enable_double_click_drag';
static readonly DOUBLE_TAP_TIME_THRESHOLD: string = 'settings_double_tap_time_threshold';
static readonly MOUSE_NAV_BUTTONS: string = 'settings_mouse_nav_buttons';
Expand Down Expand Up @@ -221,6 +222,7 @@ export interface InputSettings {
// 鼠标/触控
showLocalCursor: boolean;
touchscreenTrackpad: boolean;
lowLatencyTouch: boolean;
enableDoubleClickDrag: boolean;
doubleTapTimeThreshold: number;
mouseNavButtons: boolean;
Expand Down Expand Up @@ -617,6 +619,7 @@ export class SettingsService {
// 获取鼠标/触控设置
const showLocalCursor = await this.getBoolean(SettingsKeys.SHOW_LOCAL_CURSOR, false); // 默认不显示本地光标
const touchscreenTrackpad = await this.getBoolean(SettingsKeys.TOUCHSCREEN_TRACKPAD, false);
const lowLatencyTouch = await this.getBoolean(SettingsKeys.LOW_LATENCY_TOUCH, false);
const enableDoubleClickDrag = await this.getBoolean(SettingsKeys.ENABLE_DOUBLE_CLICK_DRAG, false);
const doubleTapTimeThreshold = await this.getNumber(SettingsKeys.DOUBLE_TAP_TIME_THRESHOLD, 125);

Expand Down Expand Up @@ -698,6 +701,7 @@ export class SettingsService {
// 鼠标/触控设置
showLocalCursor: showLocalCursor,
touchscreenTrackpad: touchscreenTrackpad,
lowLatencyTouch: lowLatencyTouch,
enableDoubleClickDrag: enableDoubleClickDrag,
doubleTapTimeThreshold: doubleTapTimeThreshold,

Expand Down Expand Up @@ -788,6 +792,7 @@ export class SettingsService {
// 鼠标/触控
showLocalCursor: await this.getBoolean(SettingsKeys.SHOW_LOCAL_CURSOR, false),
touchscreenTrackpad: await this.getBoolean(SettingsKeys.TOUCHSCREEN_TRACKPAD, false),
lowLatencyTouch: await this.getBoolean(SettingsKeys.LOW_LATENCY_TOUCH, false),
enableDoubleClickDrag: await this.getBoolean(SettingsKeys.ENABLE_DOUBLE_CLICK_DRAG, false),
doubleTapTimeThreshold: await this.getNumber(SettingsKeys.DOUBLE_TAP_TIME_THRESHOLD, 125),
mouseNavButtons: await this.getBoolean(SettingsKeys.MOUSE_NAV_BUTTONS, false),
Expand Down
52 changes: 41 additions & 11 deletions entry/src/main/ets/service/input/TouchInputHandler.ets
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,13 @@ export class TouchInputHandler {
private mouseCancelled: boolean = false;
/** 是否已确认为点击(死区时间/距离超过后) */
private mouseConfirmedTap: boolean = false;
/** 是否已确认为长按(650ms 后切换为右键) */
/** 是否已确认为长按(默认 650ms 后切换为右键) */
private mouseConfirmedLongPress: boolean = false;
/** 长按定时器 */
private mouseLongPressTimer: number = -1;
/** 死区定时器(100ms 后确认点击) */
/** 死区定时器(默认 100ms 后确认点击) */
private mouseTapDownTimer: number = -1;
/** 左键释放延迟定时器(快速点击时延迟 100ms 释放) */
/** 左键释放延迟定时器(快速点击时默认延迟 100ms 释放) */
private mouseLeftButtonUpTimer: number = -1;
/** 主手指 ID */
private mousePrimaryFingerId: number = -1;
Expand All @@ -184,14 +184,22 @@ export class TouchInputHandler {
private coordinateTransform: ((x: number, y: number) => PointXY) | null = null;

// 鼠标模式常量(与 Android AbsoluteTouchContext 一致)
/** 长按时间阈值(ms) */
private static readonly MOUSE_LONG_PRESS_TIME = 650;
/** 标准长按时间阈值(ms) */
private static readonly MOUSE_LONG_PRESS_TIME_NORMAL = 650;
/** 低延迟长按时间阈值(ms) */
private static readonly MOUSE_LONG_PRESS_TIME_LOW_LATENCY = 500;
/** 长按移动距离阈值(px)—— 超过后取消长按 */
private static readonly MOUSE_LONG_PRESS_DISTANCE = 30;
/** 死区时间阈值(ms)—— 按下后此时间内不响应移动 */
private static readonly MOUSE_DEADZONE_TIME = 100;
/** 标准死区时间阈值(ms)—— 按下后此时间内不响应移动 */
private static readonly MOUSE_DEADZONE_TIME_NORMAL = 100;
/** 低延迟死区时间阈值(ms) */
private static readonly MOUSE_DEADZONE_TIME_LOW_LATENCY = 50;
/** 死区距离阈值(px)—— 移动超过此距离立即确认点击 */
private static readonly MOUSE_DEADZONE_DISTANCE = 20;
/** 标准点击释放延迟(ms) */
private static readonly MOUSE_CLICK_RELEASE_DELAY_NORMAL = 100;
/** 低延迟点击释放延迟(ms) */
private static readonly MOUSE_CLICK_RELEASE_DELAY_LOW_LATENCY = 40;
/** 双击时间阈值(ms)—— 两次点击间隔小于此值视为双击 */
private mouseDoubleTapTime: number = 250;
/** 双击距离阈值(px)—— 两次点击位置距离小于此值视为双击 */
Expand All @@ -200,6 +208,12 @@ export class TouchInputHandler {
private static readonly MOUSE_SCROLL_SPEED_FACTOR = 3;
/** 是否启用双击拖动 */
private enableDoubleClickDrag: boolean = false;
/** 当前长按时间阈值(ms) */
private mouseLongPressTime: number = TouchInputHandler.MOUSE_LONG_PRESS_TIME_NORMAL;
/** 当前死区时间阈值(ms) */
private mouseDeadzoneTime: number = TouchInputHandler.MOUSE_DEADZONE_TIME_NORMAL;
/** 当前点击释放延迟(ms) */
private mouseClickReleaseDelay: number = TouchInputHandler.MOUSE_CLICK_RELEASE_DELAY_NORMAL;

// 默认配置
private static readonly DEFAULT_SENSITIVITY = 1.5;
Expand Down Expand Up @@ -235,6 +249,22 @@ export class TouchInputHandler {
this.enableDoubleClickDrag = enable;
}

/**
* 配置低延迟触摸参数(从设置读取后调用)
*/
setLowLatencyTouch(enable: boolean): void {
this.mouseLongPressTime = enable
? TouchInputHandler.MOUSE_LONG_PRESS_TIME_LOW_LATENCY
: TouchInputHandler.MOUSE_LONG_PRESS_TIME_NORMAL;
this.mouseDeadzoneTime = enable
? TouchInputHandler.MOUSE_DEADZONE_TIME_LOW_LATENCY
: TouchInputHandler.MOUSE_DEADZONE_TIME_NORMAL;
this.mouseClickReleaseDelay = enable
? TouchInputHandler.MOUSE_CLICK_RELEASE_DELAY_LOW_LATENCY
: TouchInputHandler.MOUSE_CLICK_RELEASE_DELAY_NORMAL;
this.trackpad.updateLatencyMode(enable);
}

/**
* 设置坐标变换函数(用于画面缩放/平移状态下的坐标修正)
* 传入 null 清除变换
Expand Down Expand Up @@ -574,7 +604,7 @@ export class TouchInputHandler {
this.nativeInput.sendMouseButton(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
this.nativeInput.sendMouseButton(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
}, TouchInputHandler.MOUSE_LONG_PRESS_TIME);
}, this.mouseLongPressTime);
}

private cancelMouseLongPressTimer(): void {
Expand All @@ -588,7 +618,7 @@ export class TouchInputHandler {
this.cancelMouseTapDownTimer();
this.mouseTapDownTimer = setTimeout(() => {
this.mouseTapConfirmed();
}, TouchInputHandler.MOUSE_DEADZONE_TIME);
}, this.mouseDeadzoneTime);
}

private cancelMouseTapDownTimer(): void {
Expand Down Expand Up @@ -738,15 +768,15 @@ export class TouchInputHandler {
} else if (this.mouseConfirmedTap) {
this.nativeInput.sendMouseButton(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
} else {
// 死区时间内完成的快速点击:立即按下,延迟 100ms 释放
// 死区时间内完成的快速点击:立即按下,按当前触摸参数延迟释放
this.mouseTapConfirmed();
if (this.mouseLeftButtonUpTimer !== -1) {
clearTimeout(this.mouseLeftButtonUpTimer);
}
this.mouseLeftButtonUpTimer = setTimeout(() => {
this.nativeInput.sendMouseButton(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
this.mouseLeftButtonUpTimer = -1;
}, 100);
}, this.mouseClickReleaseDelay);
}
}

Expand Down
33 changes: 25 additions & 8 deletions entry/src/main/ets/service/input/TrackpadGestureHandler.ets
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,26 @@ const TAP_MOVEMENT_THRESHOLD = 40;
const TAP_DISTANCE_THRESHOLD = 50;
/** 轻触最大时长 (ms) */
const TAP_TIME_THRESHOLD = 250;
/** 长按拖拽时间 (ms) */
const DRAG_TIME_THRESHOLD = 650;
/** 标准长按拖拽时间 (ms) */
const DRAG_TIME_THRESHOLD_NORMAL = 650;
/** 低延迟长按拖拽时间 (ms) */
const DRAG_TIME_THRESHOLD_LOW_LATENCY = 500;
/** 双击待定态下开始拖拽的移动阈值 (px) */
const DRAG_START_THRESHOLD = 10;
/** 双击按住确认拖拽时间 (ms) */
const DOUBLE_TAP_HOLD_THRESHOLD = 200;
/** 标准双击按住确认拖拽时间 (ms) */
const DOUBLE_TAP_HOLD_THRESHOLD_NORMAL = 200;
/** 低延迟双击按住确认拖拽时间 (ms) */
const DOUBLE_TAP_HOLD_THRESHOLD_LOW_LATENCY = 120;
/** 双击两次位置最大偏差 (px) */
const DOUBLE_TAP_MOVEMENT_THRESHOLD = 40;
/** 双指移动阈值 — 超过后视为滚轮 (px) */
const TWO_FINGER_MOVE_THRESHOLD = 30;
/** 滚轮速度因子 */
const SCROLL_SPEED_FACTOR = 5;
/** 标准点击释放延迟 (ms) */
const CLICK_RELEASE_DELAY_NORMAL = 100;
/** 低延迟点击释放延迟 (ms) */
const CLICK_RELEASE_DELAY_LOW_LATENCY = 40;

export class TrackpadGestureHandler {
private sink: TrackpadInputSink;
Expand Down Expand Up @@ -106,6 +114,9 @@ export class TrackpadGestureHandler {
private twoFingerStartX = 0;
private twoFingerStartY = 0;
private confirmedScroll = false;
private dragTimeThreshold: number = DRAG_TIME_THRESHOLD_NORMAL;
private doubleTapHoldThreshold: number = DOUBLE_TAP_HOLD_THRESHOLD_NORMAL;
private clickReleaseDelay: number = CLICK_RELEASE_DELAY_NORMAL;

constructor(sink: TrackpadInputSink, config: TrackpadConfig) {
this.sink = sink;
Expand All @@ -120,6 +131,12 @@ export class TrackpadGestureHandler {
if (enableDoubleClickDrag !== undefined) this.config.enableDoubleClickDrag = enableDoubleClickDrag;
}

updateLatencyMode(enable: boolean): void {
this.dragTimeThreshold = enable ? DRAG_TIME_THRESHOLD_LOW_LATENCY : DRAG_TIME_THRESHOLD_NORMAL;
this.doubleTapHoldThreshold = enable ? DOUBLE_TAP_HOLD_THRESHOLD_LOW_LATENCY : DOUBLE_TAP_HOLD_THRESHOLD_NORMAL;
this.clickReleaseDelay = enable ? CLICK_RELEASE_DELAY_LOW_LATENCY : CLICK_RELEASE_DELAY_NORMAL;
}

// ==================== 事件入口 ====================

handleEvent(event: TouchEvent): void {
Expand Down Expand Up @@ -437,7 +454,7 @@ export class TrackpadGestureHandler {

private sendClick(button: number): void {
this.sink.sendMouseButton(BUTTON_ACTION_PRESS, button);
setTimeout(() => this.sink.sendMouseButton(BUTTON_ACTION_RELEASE, button), 100);
setTimeout(() => this.sink.sendMouseButton(BUTTON_ACTION_RELEASE, button), this.clickReleaseDelay);
}

private sendRightClick(): void {
Expand All @@ -449,7 +466,7 @@ export class TrackpadGestureHandler {
this.sink.sendMouseButton(BUTTON_ACTION_PRESS, BUTTON_LEFT);
this.sink.sendMouseButton(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
this.sink.sendMouseButton(BUTTON_ACTION_PRESS, BUTTON_LEFT);
setTimeout(() => this.sink.sendMouseButton(BUTTON_ACTION_RELEASE, BUTTON_LEFT), 100);
setTimeout(() => this.sink.sendMouseButton(BUTTON_ACTION_RELEASE, BUTTON_LEFT), this.clickReleaseDelay);
}

// ---- 手指管理 ----
Expand All @@ -472,7 +489,7 @@ export class TrackpadGestureHandler {
if (this.confirmedMove || this.maxCountInGesture !== 1) return;
this.confirmedDrag = true;
this.sink.sendMouseButton(BUTTON_ACTION_PRESS, BUTTON_LEFT);
}, DRAG_TIME_THRESHOLD);
}, this.dragTimeThreshold);
}

private cancelDragTimer(): void {
Expand All @@ -490,7 +507,7 @@ export class TrackpadGestureHandler {
this.isDoubleClickDrag = true;
this.confirmedMove = true;
this.sink.sendMouseButton(BUTTON_ACTION_PRESS, BUTTON_LEFT);
}, DOUBLE_TAP_HOLD_THRESHOLD);
}, this.doubleTapHoldThreshold);
}

private cancelDoubleTapHoldTimer(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,6 @@ export class StreamInputHandler {
// 归一化后的值 / scrollStep 为每格原始值,× 8 = 120 units(Windows WHEEL_DELTA)
if (vertical !== 0) {
const scrollAmount = Math.round(-vertical / scrollStep * 8);
console.info(`滚轮: vertical=${vertical.toFixed(2)}, scrollStep=${scrollStep}, send=${scrollAmount}`);
MoonBridge.sendMouseHighResScroll(scrollAmount);
}

Expand Down
Loading