Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed #17866: [bug] EventTouch.getUIDelta return wrong delta values on native platforms #17895

Merged
merged 4 commits into from
Nov 21, 2024
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
3 changes: 3 additions & 0 deletions @types/pal/input.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ declare module 'pal/input' {
* Register the touch event callback.
*/
public on (eventType: import('cocos/input/types/event-enum').InputEventType, callback: TouchCallback, target?: any);
public dispatchEventsInCache (): void;
}

type MouseCallback = (res: import('cocos/input/types').EventMouse) => void;
Expand All @@ -30,6 +31,8 @@ declare module 'pal/input' {
public dispatchMouseMoveEvent? (nativeMouseEvent: any);
public dispatchMouseUpEvent? (nativeMouseEvent: any);
public dispatchScrollEvent? (nativeMouseEvent: any);

public dispatchEventsInCache (): void
}

type KeyboardCallback = (res: import('cocos/input/types').EventKeyboard) => void;
Expand Down
71 changes: 24 additions & 47 deletions cocos/input/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
*/

import { EDITOR_NOT_IN_PREVIEW, NATIVE } from 'internal:constants';
import { AccelerometerInputSource, GamepadInputDevice, HMDInputDevice, HandheldInputDevice, HandleInputDevice, KeyboardInputSource, MouseInputSource, TouchInputSource } from 'pal/input';

Check warning on line 28 in cocos/input/input.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 186. Maximum allowed is 150
import { touchManager } from '../../pal/input/touch-manager';
import { EventTarget, error, sys } from '../core';
import { Event, EventAcceleration, EventGamepad, EventHandle, EventHandheld, EventHMD, EventKeyboard, EventMouse, EventTouch, Touch } from './types';
Expand Down Expand Up @@ -142,8 +142,6 @@
private _hmdInput$ = new HMDInputDevice();
private _handheldInput$ = new HandheldInputDevice();

private _eventTouchList$: EventTouch[] = [];
private _eventMouseList$: EventMouse[] = [];
private _eventKeyboardList$: EventKeyboard[] = [];
private _eventAccelerationList$: EventAcceleration[] = [];
private _eventGamepadList$: EventGamepad[] = [];
Expand Down Expand Up @@ -324,7 +322,7 @@
if (eventType === InputEventType.TOUCH_END) {
touchManager.releaseTouch(touchID);
}
this._dispatchOrPushEventTouch$(eventTouch, this._eventTouchList$);
this._dispatchEventTouch$(eventTouch);
}

/**
Expand Down Expand Up @@ -353,47 +351,45 @@

private _registerEvent$ (): void {
if (sys.hasFeature(sys.Feature.INPUT_TOUCH)) {
const eventTouchList = this._eventTouchList$;
this._touchInput$.on(InputEventType.TOUCH_START, (event): void => {
this._dispatchOrPushEventTouch$(event, eventTouchList);
this._dispatchEventTouch$(event);
});
this._touchInput$.on(InputEventType.TOUCH_MOVE, (event): void => {
this._dispatchOrPushEventTouch$(event, eventTouchList);
this._dispatchEventTouch$(event);
});
this._touchInput$.on(InputEventType.TOUCH_END, (event): void => {
this._dispatchOrPushEventTouch$(event, eventTouchList);
this._dispatchEventTouch$(event);
});
this._touchInput$.on(InputEventType.TOUCH_CANCEL, (event): void => {
this._dispatchOrPushEventTouch$(event, eventTouchList);
this._dispatchEventTouch$(event);
});
}

if (sys.hasFeature(sys.Feature.EVENT_MOUSE)) {
const eventMouseList = this._eventMouseList$;
this._mouseInput$.on(InputEventType.MOUSE_DOWN, (event): void => {
this._needSimulateTouchMoveEvent$ = true;
this._simulateEventTouch$(event);
this._dispatchOrPushEvent$(event, eventMouseList);
this._dispatchEventMouse$(event);
});
this._mouseInput$.on(InputEventType.MOUSE_MOVE, (event): void => {
if (this._needSimulateTouchMoveEvent$) {
this._simulateEventTouch$(event);
}
this._dispatchOrPushEvent$(event, eventMouseList);
this._dispatchEventMouse$(event);
});
this._mouseInput$.on(InputEventType.MOUSE_UP, (event): void => {
this._needSimulateTouchMoveEvent$ = false;
this._simulateEventTouch$(event);
this._dispatchOrPushEvent$(event, eventMouseList);
this._dispatchEventMouse$(event);
});
this._mouseInput$.on(InputEventType.MOUSE_WHEEL, (event): void => {
this._dispatchOrPushEvent$(event, eventMouseList);
this._dispatchEventMouse$(event);
});
this._mouseInput$.on(InputEventType.MOUSE_LEAVE, (event): void => {
this._dispatchOrPushEvent$(event, eventMouseList);
this._dispatchEventMouse$(event);
});
this._mouseInput$.on(InputEventType.MOUSE_ENTER, (event): void => {
this._dispatchOrPushEvent$(event, eventMouseList);
this._dispatchEventMouse$(event);
});
}

Expand Down Expand Up @@ -459,8 +455,6 @@
* @engineInternal
*/
public _clearEvents (): void {
this._eventMouseList$.length = 0;
this._eventTouchList$.length = 0;
this._eventKeyboardList$.length = 0;
this._eventAccelerationList$.length = 0;
this._eventGamepadList$.length = 0;
Expand All @@ -476,17 +470,17 @@
}
}

private _dispatchOrPushEventTouch$ (eventTouch: EventTouch, touchEventList: EventTouch[]): void {
if (dispatchImmediately) {
const touches = eventTouch.getTouches();
const touchesLength = touches.length;
for (let i = 0; i < touchesLength; ++i) {
eventTouch.touch = touches[i];
eventTouch.propagationStopped = eventTouch.propagationImmediateStopped = false;
this._emitEvent$(eventTouch);
}
} else {
touchEventList.push(eventTouch);
private _dispatchEventMouse$ (event: Event): void {
this._emitEvent$(event);
}

private _dispatchEventTouch$ (eventTouch: EventTouch): void {
const touches = eventTouch.getTouches();
const touchesLength = touches.length;
for (let i = 0; i < touchesLength; ++i) {
eventTouch.touch = touches[i];
eventTouch.propagationStopped = eventTouch.propagationImmediateStopped = false;
this._emitEvent$(eventTouch);
}
}

Expand All @@ -509,25 +503,8 @@
this._emitEvent$(eventHandheld);
}

const eventMouseList = this._eventMouseList$;
// TODO: culling event queue
for (let i = 0, length = eventMouseList.length; i < length; ++i) {
const eventMouse = eventMouseList[i];
this._emitEvent$(eventMouse);
}

const eventTouchList = this._eventTouchList$;
// TODO: culling event queue
for (let i = 0, length = eventTouchList.length; i < length; ++i) {
const eventTouch = eventTouchList[i];
const touches = eventTouch.getTouches();
const touchesLength = touches.length;
for (let j = 0; j < touchesLength; ++j) {
eventTouch.touch = touches[j];
eventTouch.propagationStopped = eventTouch.propagationImmediateStopped = false;
this._emitEvent$(eventTouch);
}
}
this._mouseInput$.dispatchEventsInCache();
this._touchInput$.dispatchEventsInCache();

const eventKeyboardList = this._eventKeyboardList$;
// TODO: culling event queue
Expand Down Expand Up @@ -563,7 +540,7 @@

/**
* @en
* The singleton of the Input class, this singleton manages all events of input. include: touch, mouse, accelerometer, gamepad, handle, hmd and keyboard.

Check warning on line 543 in cocos/input/input.ts

View workflow job for this annotation

GitHub Actions / Run ESLint

This line has a length of 153. Maximum allowed is 150
*
* @zh
* 输入类单例,该单例管理所有的输入事件,包括:触摸、鼠标、加速计、游戏手柄、6DOF手柄、头戴显示器 和 键盘。
Expand Down
4 changes: 4 additions & 0 deletions pal/input/minigame/mouse-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,8 @@ export class MouseInputSource {
public on (eventType: InputEventType, callback: MouseCallback, target?: any): void {
this._eventTarget$.on(eventType, callback, target);
}

public dispatchEventsInCache (): void {
// Do nothing
}
}
4 changes: 4 additions & 0 deletions pal/input/minigame/touch-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,8 @@ export class TouchInputSource {
public on (eventType: InputEventType, callback: TouchCallback, target?: any): void {
this._eventTarget$.on(eventType, callback, target);
}

public dispatchEventsInCache (): void {
// Do nothing
}
}
154 changes: 117 additions & 37 deletions pal/input/native/mouse-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,31 +32,84 @@ export type MouseCallback = (res: EventMouse) => void;

declare const jsb: any;

class MouseEventElement {
type: InputEventType | null = null;
mouseEvent = {
x: 0,
y: 0,
xDelta: 0,
yDelta: 0,
button: 0,
windowId: 0,
wheelDeltaX: 0,
wheelDeltaY: 0,
};
}

class MouseEventCache {
private _events: MouseEventElement[] = [];
private _length = 0;

push (eventType: InputEventType, mouseEvent?: any): void {
const events = this._events;
const index = this._length;
if (index >= events.length) {
events.push(new MouseEventElement());
}
const e = events[index];
e.type = eventType;
const cachedEvent = e.mouseEvent;
if (mouseEvent) {
Object.assign(cachedEvent, mouseEvent);
} else {
cachedEvent.x = cachedEvent.y = cachedEvent.xDelta = cachedEvent.yDelta = 0;
cachedEvent.button = cachedEvent.windowId = cachedEvent.wheelDeltaX = cachedEvent.wheelDeltaY = 0;
}

++this._length;
}

clear (): void {
this._length = 0;
}

forEach (cb: ((e: MouseEventElement) => void)): void {
for (let i = 0, len = this._length; i < len; ++i) {
cb(this._events[i]);
}
}
}

export class MouseInputSource {
private _eventTarget: EventTarget = new EventTarget();
private _preMousePos: Vec2 = new Vec2();
private _isPressed = false;
private _windowManager: any;
private _pointLocked = false;
private _cache = new MouseEventCache();

private _handleMouseDown: (mouseEvent: jsb.MouseEvent) => void;
private _handleMouseMove: (mouseEvent: jsb.MouseEvent) => void;
private _handleMouseUp: (mouseEvent: jsb.MouseEvent) => void;
private _boundedHandleMouseWheel: (mouseEvent: jsb.MouseWheelEvent) => void;
private _handleWindowLeave: () => void;
private _handleWindowEnter: () => void;
private _handleMouseWheel: (mouseEvent: jsb.MouseWheelEvent) => void;

constructor () {
this._handleMouseDown = this._createCallback(InputEventType.MOUSE_DOWN);
this._handleMouseMove = this._createCallback(InputEventType.MOUSE_MOVE);
this._handleMouseUp = this._createCallback(InputEventType.MOUSE_UP);
this._boundedHandleMouseWheel = this._handleMouseWheel.bind(this);
this._registerEvent();
this._handleMouseDown = this._createEventCacheCallback$(InputEventType.MOUSE_DOWN);
this._handleMouseMove = this._createEventCacheCallback$(InputEventType.MOUSE_MOVE);
this._handleMouseUp = this._createEventCacheCallback$(InputEventType.MOUSE_UP);
this._handleWindowLeave = this._createEventCacheCallback$(InputEventType.MOUSE_LEAVE);
this._handleWindowEnter = this._createEventCacheCallback$(InputEventType.MOUSE_ENTER);
this._handleMouseWheel = this._createEventCacheCallback$(InputEventType.MOUSE_WHEEL);
this._registerEvent$();
this._windowManager = jsb.ISystemWindowManager.getInstance();
}

public dispatchMouseDownEvent (nativeMouseEvent: any): void { this._handleMouseDown(nativeMouseEvent as jsb.MouseEvent); }
public dispatchMouseMoveEvent (nativeMouseEvent: any): void { this._handleMouseMove(nativeMouseEvent as jsb.MouseEvent); }
public dispatchMouseUpEvent (nativeMouseEvent: any): void { this._handleMouseUp(nativeMouseEvent as jsb.MouseEvent); }
public dispatchScrollEvent (nativeMouseEvent: any): void { this._boundedHandleMouseWheel(nativeMouseEvent as jsb.MouseWheelEvent); }
public dispatchScrollEvent (nativeMouseEvent: any): void { this._handleMouseWheel(nativeMouseEvent as jsb.MouseWheelEvent); }

private _getLocation (event: jsb.MouseEvent): Vec2 {
const window = this._windowManager.getWindow(event.windowId);
Expand All @@ -67,53 +120,80 @@ export class MouseInputSource {
return new Vec2(x, y);
}

private _registerEvent (): void {
private _registerEvent$ (): void {
jsb.onMouseDown = this._handleMouseDown;
jsb.onMouseMove = this._handleMouseMove;
jsb.onMouseUp = this._handleMouseUp;
jsb.onMouseWheel = this._boundedHandleMouseWheel;
jsb.onMouseWheel = this._handleMouseWheel;
jsb.onPointerlockChange = (value: boolean): void => {
this._pointLocked = value;
};

// Treat window leave/enter events as mouse events as web.
jsb.onWindowLeave = this._handleWindowLeave.bind(this);
jsb.onWindowEnter = this._handleWindowEnter.bind(this);
jsb.onWindowLeave = this._handleWindowLeave;
jsb.onWindowEnter = this._handleWindowEnter;
}

private _createEventCacheCallback$ (eventType: InputEventType) {
return (mouseEvent?: jsb.MouseEvent | jsb.MouseWheelEvent): void => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why mouseEvent is optional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FOR MouseEnter and MouseLeave, they dont have event info and only have type

this._cache.push(eventType, mouseEvent);
};
}

private _createCallback (eventType: InputEventType) {
return (mouseEvent: jsb.MouseEvent): void => {
const location = this._getLocation(mouseEvent);
let button = mouseEvent.button;
switch (eventType) {
case InputEventType.MOUSE_DOWN:
this._isPressed = true;
public dispatchEventsInCache (): void {
const cache = this._cache;

cache.forEach((e: MouseEventElement) => {
switch (e.type) {
case InputEventType.MOUSE_LEAVE:
this._dispatchWindowLeave$();
break;
case InputEventType.MOUSE_UP:
this._isPressed = false;
case InputEventType.MOUSE_ENTER:
this._dispatchWindowEnter$();
break;
case InputEventType.MOUSE_MOVE:
if (!this._isPressed) {
button = EventMouse.BUTTON_MISSING;
}
case InputEventType.MOUSE_WHEEL:
this._dispatchMouseWheel$(e.mouseEvent as jsb.MouseWheelEvent);
break;
default:
this._dispatchEvent$(e.type!, e.mouseEvent);
break;
}
});

const eventMouse = new EventMouse(eventType, false, this._preMousePos, mouseEvent.windowId);
eventMouse.setLocation(location.x, location.y);
eventMouse.setButton(button);
const dpr = screenAdapter.devicePixelRatio;
eventMouse.movementX = typeof mouseEvent.xDelta === 'undefined' ? 0 : mouseEvent.xDelta * dpr;
eventMouse.movementY = typeof mouseEvent.yDelta === 'undefined' ? 0 : mouseEvent.yDelta * dpr;
// update previous mouse position.
this._preMousePos.set(location.x, location.y);
this._eventTarget.emit(eventType, eventMouse);
};
cache.clear();
}

private _dispatchEvent$ (eventType: InputEventType, mouseEvent: jsb.MouseEvent): void {
const location = this._getLocation(mouseEvent);
let button = mouseEvent.button;
switch (eventType) {
case InputEventType.MOUSE_DOWN:
this._isPressed = true;
break;
case InputEventType.MOUSE_UP:
this._isPressed = false;
break;
case InputEventType.MOUSE_MOVE:
if (!this._isPressed) {
button = EventMouse.BUTTON_MISSING;
}
break;
default:
break;
}

const eventMouse = new EventMouse(eventType, false, this._preMousePos, mouseEvent.windowId);
eventMouse.setLocation(location.x, location.y);
eventMouse.setButton(button);
const dpr = screenAdapter.devicePixelRatio;
eventMouse.movementX = typeof mouseEvent.xDelta === 'undefined' ? 0 : mouseEvent.xDelta * dpr;
eventMouse.movementY = typeof mouseEvent.yDelta === 'undefined' ? 0 : mouseEvent.yDelta * dpr;
// update previous mouse position.
this._preMousePos.set(location.x, location.y);
this._eventTarget.emit(eventType, eventMouse);
}

private _handleMouseWheel (mouseEvent: jsb.MouseWheelEvent): void {
private _dispatchMouseWheel$ (mouseEvent: jsb.MouseWheelEvent): void {
const eventType = InputEventType.MOUSE_WHEEL;
const location = this._getLocation(mouseEvent);
const button = mouseEvent.button;
Expand All @@ -136,13 +216,13 @@ export class MouseInputSource {
}

// Should include window id if supporting multiple windows.
private _handleWindowLeave (): void {
private _dispatchWindowLeave$ (): void {
const eventType = InputEventType.MOUSE_LEAVE;
const eventMouse = new EventMouse(eventType, false);
this._eventTarget.emit(eventType, eventMouse);
}

private _handleWindowEnter (): void {
private _dispatchWindowEnter$ (): void {
const eventType = InputEventType.MOUSE_ENTER;
const eventMouse = new EventMouse(eventType, false);
this._eventTarget.emit(eventType, eventMouse);
Expand Down
Loading
Loading