From b6d0ace2c8e87da62512e3dec1431797c74912a7 Mon Sep 17 00:00:00 2001 From: Dawei Zhou Date: Sun, 17 May 2026 17:46:40 +0800 Subject: [PATCH 1/3] fix: Update IOHIDEvent on touch phase changes for game compatibility - Rebuild IOHIDEvent in setPhaseAndUpdateTimestamp: so eventMask stays in sync with UITouch.phase (was only set on touch creation) - Fix kif_IOHIDEventWithTouches eventMask for ended/cancelled phases - Use per-finger timestamps for more realistic HID events Some games validate that IOHIDEvent properties match the current UITouch phase. Without this fix, moved/ended touches carry a stale began-phase IOHIDEvent, triggering detection. --- .../PTFakeTouch/Additions/IOHIDEvent+KIF.m | 98 ++++++++++++------- .../Additions/UITouch-KIFAdditions.m | 4 + 2 files changed, 67 insertions(+), 35 deletions(-) diff --git a/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m b/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m index d4628564..ba8d4e31 100644 --- a/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m +++ b/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m @@ -142,45 +142,73 @@ IOHIDEventRef kif_IOHIDEventWithTouches(NSArray *touches) { AbsoluteTime timeStamp; timeStamp.hi = (UInt32)(abTime >> 32); timeStamp.lo = (UInt32)(abTime); - IOHIDEventRef handEvent = IOHIDEventCreateDigitizerEvent(kCFAllocatorDefault, // allocator 内存分配器 - timeStamp, // timestamp 时间戳 - kIOHIDDigitizerTransducerTypeHand, // type - 0, // index - 0, // identity - kIOHIDDigitizerEventTouch, // eventMask - 0, // buttonMask - 0, // x - 0, // y - 0, // z - 0, // tipPressure - 0, // barrelPressure - 0, // range - true, // touch - 0); // options + IOHIDEventRef handEvent = IOHIDEventCreateDigitizerEvent(kCFAllocatorDefault, + timeStamp, + kIOHIDDigitizerTransducerTypeHand, + 0, + 0, + kIOHIDDigitizerEventTouch, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + true, + 0); IOHIDEventSetIntegerValue(handEvent, kIOHIDEventFieldDigitizerIsDisplayIntegrated, true); for (UITouch *touch in touches) { - uint32_t eventMask = (touch.phase == UITouchPhaseMoved) ? kIOHIDDigitizerEventPosition : (kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch); - uint32_t isTouching = (touch.phase == UITouchPhaseEnded) ? 0 : 1; + // Set eventMask and touch/range state based on actual touch phase. + // These must accurately reflect the UITouch.phase so that game-side + // validation (e.g. Tencent anti-automation) does not flag the IO HID + // event as inconsistent with the UIKit touch state. + uint32_t eventMask; + uint32_t isTouching; + switch (touch.phase) { + case UITouchPhaseMoved: + eventMask = kIOHIDDigitizerEventPosition; + isTouching = 1; + break; + case UITouchPhaseEnded: + case UITouchPhaseCancelled: + eventMask = kIOHIDDigitizerEventTouch; + isTouching = 0; + break; + default: // Began / Stationary + eventMask = kIOHIDDigitizerEventRange | kIOHIDDigitizerEventTouch; + isTouching = 1; + break; + } + CGPoint touchLocation = [touch locationInView:touch.window]; - IOHIDEventRef fingerEvent = IOHIDEventCreateDigitizerFingerEventWithQuality(kCFAllocatorDefault, // allocator - timeStamp, // timestamp - (UInt32)[touches indexOfObject:touch] + 1, //index - 2, // identity - eventMask, // eventMask - (IOHIDFloat)touchLocation.x, // x - (IOHIDFloat)touchLocation.y, // y - 0.0, // z - 0, // tipPressure - 0, // twist - 5.0, // minor radius - 5.0, // major radius - 1.0, // quality - 1.0, // density - 1.0, // irregularity - (IOHIDFloat)isTouching, // range - (IOHIDFloat)isTouching, // touch - 0); // options + + // Each finger gets its own timestamp for more realistic HID events. + // Real multi-touch hardware fires independent events per finger. + uint64_t fingerTime = mach_absolute_time(); + AbsoluteTime fingerTimestamp; + fingerTimestamp.hi = (UInt32)(fingerTime >> 32); + fingerTimestamp.lo = (UInt32)(fingerTime); + + IOHIDEventRef fingerEvent = IOHIDEventCreateDigitizerFingerEventWithQuality(kCFAllocatorDefault, + fingerTimestamp, + (UInt32)[touches indexOfObject:touch] + 1, + 2, + eventMask, + (IOHIDFloat)touchLocation.x, + (IOHIDFloat)touchLocation.y, + 0.0, + 0, + 0, + 5.0, + 5.0, + 1.0, + 1.0, + 1.0, + (IOHIDFloat)isTouching, + (IOHIDFloat)isTouching, + 0); IOHIDEventSetIntegerValue(fingerEvent, kIOHIDEventFieldDigitizerIsDisplayIntegrated, 1); IOHIDEventAppendEvent(handEvent, fingerEvent); CFRelease(fingerEvent); diff --git a/PlayTools/Controls/PTFakeTouch/Additions/UITouch-KIFAdditions.m b/PlayTools/Controls/PTFakeTouch/Additions/UITouch-KIFAdditions.m index 4776716a..41f1dd91 100644 --- a/PlayTools/Controls/PTFakeTouch/Additions/UITouch-KIFAdditions.m +++ b/PlayTools/Controls/PTFakeTouch/Additions/UITouch-KIFAdditions.m @@ -95,6 +95,10 @@ - (void)setPhaseAndUpdateTimestamp:(UITouchPhase)phase //DLog(@"setPhaseAndUpdateTimestamp : %ld",(long)phase); [self setTimestamp: [[NSProcessInfo processInfo] systemUptime]]; [self setPhase:phase]; + // Update the IOHIDEvent to match the new phase. + // Some games validate IOHIDEvent.eventMask against UITouch.phase, + // so keeping them in sync is critical for fake touch acceptance. + [self kif_setHidEvent]; } - (void)kif_setHidEvent { From 98b08aecab48460d95640bfd9290201787d1525d Mon Sep 17 00:00:00 2001 From: Dawei Zhou Date: Sun, 7 Jun 2026 23:03:16 +0800 Subject: [PATCH 2/3] Add back parameter comments for handEvent and fingerEvent --- .../PTFakeTouch/Additions/IOHIDEvent+KIF.m | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m b/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m index ba8d4e31..8d97846e 100644 --- a/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m +++ b/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m @@ -142,21 +142,21 @@ IOHIDEventRef kif_IOHIDEventWithTouches(NSArray *touches) { AbsoluteTime timeStamp; timeStamp.hi = (UInt32)(abTime >> 32); timeStamp.lo = (UInt32)(abTime); - IOHIDEventRef handEvent = IOHIDEventCreateDigitizerEvent(kCFAllocatorDefault, - timeStamp, - kIOHIDDigitizerTransducerTypeHand, - 0, - 0, - kIOHIDDigitizerEventTouch, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - true, - 0); + IOHIDEventRef handEvent = IOHIDEventCreateDigitizerEvent(kCFAllocatorDefault, // allocator 内存分配器 + timeStamp, // timestamp 时间戳 + kIOHIDDigitizerTransducerTypeHand, // type + 0, // index + 0, // identity + kIOHIDDigitizerEventTouch, // eventMask + 0, // buttonMask + 0, // x + 0, // y + 0, // z + 0, // tipPressure + 0, // barrelPressure + 0, // range + true, // touch + 0); // options IOHIDEventSetIntegerValue(handEvent, kIOHIDEventFieldDigitizerIsDisplayIntegrated, true); for (UITouch *touch in touches) { @@ -191,24 +191,24 @@ IOHIDEventRef kif_IOHIDEventWithTouches(NSArray *touches) { fingerTimestamp.hi = (UInt32)(fingerTime >> 32); fingerTimestamp.lo = (UInt32)(fingerTime); - IOHIDEventRef fingerEvent = IOHIDEventCreateDigitizerFingerEventWithQuality(kCFAllocatorDefault, - fingerTimestamp, - (UInt32)[touches indexOfObject:touch] + 1, - 2, - eventMask, - (IOHIDFloat)touchLocation.x, - (IOHIDFloat)touchLocation.y, - 0.0, - 0, - 0, - 5.0, - 5.0, - 1.0, - 1.0, - 1.0, - (IOHIDFloat)isTouching, - (IOHIDFloat)isTouching, - 0); + IOHIDEventRef fingerEvent = IOHIDEventCreateDigitizerFingerEventWithQuality(kCFAllocatorDefault, // allocator + timeStamp, // timestamp + (UInt32)[touches indexOfObject:touch] + 1, //index + 2, // identity + eventMask, // eventMask + (IOHIDFloat)touchLocation.x, // x + (IOHIDFloat)touchLocation.y, // y + 0.0, // z + 0, // tipPressure + 0, // twist + 5.0, // minor radius + 5.0, // major radius + 1.0, // quality + 1.0, // density + 1.0, // irregularity + (IOHIDFloat)isTouching, // range + (IOHIDFloat)isTouching, // touch + 0); // options IOHIDEventSetIntegerValue(fingerEvent, kIOHIDEventFieldDigitizerIsDisplayIntegrated, 1); IOHIDEventAppendEvent(handEvent, fingerEvent); CFRelease(fingerEvent); From 2265c73e589d57937a4d93f956ba78153d5d7246 Mon Sep 17 00:00:00 2001 From: Dawei Zhou Date: Mon, 8 Jun 2026 19:24:09 +0800 Subject: [PATCH 3/3] Use fingerTimestamp instead of timeStamp for per-finger HID events --- PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m b/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m index 8d97846e..926c8a18 100644 --- a/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m +++ b/PlayTools/Controls/PTFakeTouch/Additions/IOHIDEvent+KIF.m @@ -192,7 +192,7 @@ IOHIDEventRef kif_IOHIDEventWithTouches(NSArray *touches) { fingerTimestamp.lo = (UInt32)(fingerTime); IOHIDEventRef fingerEvent = IOHIDEventCreateDigitizerFingerEventWithQuality(kCFAllocatorDefault, // allocator - timeStamp, // timestamp + fingerTimestamp, // finger timestamp (UInt32)[touches indexOfObject:touch] + 1, //index 2, // identity eventMask, // eventMask