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

Verify event is not null on touch.js #13

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
95 changes: 47 additions & 48 deletions lib/touch.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,58 +129,57 @@ const Injector = ObjC.registerClass({

const app = UIApplication.sharedApplication();
const event = app['- _touchesEvent'].call(app);
event['- _clearTouches'].call(event);

const absoluteTime = mach_absolute_time();

const timestamp = [
absoluteTime.shr(32).toNumber(),
absoluteTime.and(0xffffffff).toNumber()
];

touch.setTimestamp_(CFGetSystemUptime());

const eventMask = (phase === UITouchPhaseMoved)
? kIOHIDDigitizerEventPosition
: (kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch);
const isRangeAndTouch = (phase !== UITouchPhaseEnded) ? 1 : 0;

const hidEvent = IOHIDEventCreateDigitizerFingerEvent(
kCFAllocatorDefault,
timestamp,
0,
2,
eventMask,
point[0],
point[1],
0,
0,
0,
isRangeAndTouch,
isRangeAndTouch,
0);

if ('- _setHidEvent:' in touch) {
touch['- _setHidEvent:'].call(touch, hidEvent);
}

event['- _setHIDEvent:'].call(event, hidEvent);
event['- _addTouch:forDelayedDelivery:'].call(event, touch, false);

const pool = NSAutoreleasePool.alloc().init();
try {
app.sendEvent_(event);
} finally {
pool.release();
if (event !== null) {
Copy link
Member

@oleavr oleavr Mar 3, 2023

Choose a reason for hiding this comment

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

Oh wait, sorry, I'm not sure I understand what happens here. Does -[UIApplication _touchesEvent] keep returning nil or is it a random glitch? If it's the latter I'm wondering if we should make the _touchesEvent() call earlier, before we do pending.shift(), and simply return there -- that way dispatchTouch: gets called again on the next frame, and might succeed that time and keep going. (But if this is a permanent failure, I suppose we should call onComplete() with an Error so it can reject the Promise?)

Copy link
Author

Choose a reason for hiding this comment

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

It occurs when the application goes to the background for any reason and comes back. So I would say it's happening on a non-predictable manner.

Copy link
Member

@oleavr oleavr Mar 3, 2023

Choose a reason for hiding this comment

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

Interesting. I guess the tap down event instantly triggers backgrounding, and in this failure case we get the next dispatchTouch: just after the app has gone off screen -- whereas in the happy case we get it after it is back on the screen again.

If that is correct, I think we have two options:

  1. Keep trying, by returning early, before we do pending.shift(). In this way we will eventually move it through the different phases.
  2. Complete the touch right away, as if pending.length === 0. In that case we will have to release priv.touch if we already created it.

It seems to me that 1) is the right solution, since we will keep going once the app is back on the screen. This is also what happens when we are luckier -- the app goes to the background and dispatchTouch: does not get called until it's back on the screen.

What do you think, @mrmacete?

event['- _clearTouches'].call(event);
const absoluteTime = mach_absolute_time();

const timestamp = [
absoluteTime.shr(32).toNumber(),
absoluteTime.and(0xffffffff).toNumber()
];

touch.setTimestamp_(CFGetSystemUptime());

const eventMask = (phase === UITouchPhaseMoved)
? kIOHIDDigitizerEventPosition
: (kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch);
const isRangeAndTouch = (phase !== UITouchPhaseEnded) ? 1 : 0;

const hidEvent = IOHIDEventCreateDigitizerFingerEvent(
kCFAllocatorDefault,
timestamp,
0,
2,
eventMask,
point[0],
point[1],
0,
0,
0,
isRangeAndTouch,
isRangeAndTouch,
0);

if ('- _setHidEvent:' in touch) {
touch['- _setHidEvent:'].call(touch, hidEvent);
}

CFRelease(hidEvent);
event['- _setHIDEvent:'].call(event, hidEvent);
event['- _addTouch:forDelayedDelivery:'].call(event, touch, false);

priv.previous = point;
if (isLastTouch) {
touch.release();
priv.touch = null;
const pool = NSAutoreleasePool.alloc().init();
try {
app.sendEvent_(event);
} finally {
pool.release();
CFRelease(hidEvent);
}
}
priv.previous = point;
if (isLastTouch) {
touch.release();
priv.touch = null;
}
}
}
}
Expand Down