Skip to content

Commit

Permalink
fixed #17866: [bug] EventTouch.getUIDelta return wrong delta values o…
Browse files Browse the repository at this point in the history
…n native platforms (#17895)
  • Loading branch information
dumganhar authored Nov 21, 2024
1 parent 158e15e commit 8884807
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 124 deletions.
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 @@ -142,8 +142,6 @@ export class Input {
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 @@ export class Input {
if (eventType === InputEventType.TOUCH_END) {
touchManager.releaseTouch(touchID);
}
this._dispatchOrPushEventTouch$(eventTouch, this._eventTouchList$);
this._dispatchEventTouch$(eventTouch);
}

/**
Expand Down Expand Up @@ -353,47 +351,45 @@ export class Input {

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 @@ export class Input {
* @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 @@ export class Input {
}
}

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 @@ export class Input {
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
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 => {
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

0 comments on commit 8884807

Please sign in to comment.