mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
Mouse events posted with CGEventPostToPid reach the target app with no window association, so AppKit never routes the press to a view: hover states fire but the control is never activated, and the mouseUp is dropped outright when posted back-to-back. Post click events to the HID event tap instead (as keyboard synthesis already does), pace them, and stamp mouseEventClickState so multi-clicks register. Synthetic clicks now also report verification unverified/synthetic_input from the helper itself, matching the other synthetic actions.
41 lines
1.6 KiB
Swift
41 lines
1.6 KiB
Swift
/// Event plan for synthetic mouse clicks (STA-3433).
|
|
///
|
|
/// Clicks must be posted to the HID event tap, not `CGEventPostToPid`:
|
|
/// pid-targeted mouse events reach the app with no window association, so
|
|
/// AppKit never routes the press to a view (hover fires, activation never
|
|
/// happens). The window server also drops a mouseUp posted back-to-back
|
|
/// with its mouseDown, so consecutive events need a pause between them.
|
|
public enum SyntheticMouseClickDelivery {
|
|
public enum Step: Equatable {
|
|
case move
|
|
case buttonDown(pressIndex: Int)
|
|
case buttonUp(pressIndex: Int)
|
|
}
|
|
|
|
/// Pause after posting each event; unpaced posts race the window
|
|
/// server's routing and the mouseUp is silently dropped.
|
|
public static let interEventPauseMicroseconds: UInt32 = 50_000
|
|
|
|
/// One move, then a paired down/up per press. `pressIndex` becomes the
|
|
/// event's click state so repeated presses register as double/triple
|
|
/// clicks instead of independent single clicks.
|
|
public static func steps(clickCount: Int) -> [Step] {
|
|
var steps: [Step] = [.move]
|
|
for press in 1...max(clickCount, 1) {
|
|
steps.append(.buttonDown(pressIndex: press))
|
|
steps.append(.buttonUp(pressIndex: press))
|
|
}
|
|
return steps
|
|
}
|
|
|
|
/// Click state field value for a step; 0 leaves the field unset.
|
|
public static func clickState(for step: Step) -> Int64 {
|
|
switch step {
|
|
case .move:
|
|
return 0
|
|
case let .buttonDown(pressIndex), let .buttonUp(pressIndex):
|
|
return Int64(pressIndex)
|
|
}
|
|
}
|
|
}
|