Sounds like a plan. Here's the code I used:
func leftClick() {
DispatchQueue.main.async {
print("-----------------------")
let sleepTime = 0.05
let inBetweenClickSleepTime = 0.1
let source = CGEventSource.init(stateID: .hidSystemState)
let position = self.correctedCursorPosition // holds the intended click position
let eventDown = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: position , mouseButton: .left)
let eventUp = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: position , mouseButton: .left)
print("before D & before U post, leftMouseDown count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseDown)), leftMouseUp count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseUp))")
eventDown?.post(tap: .cghidEventTap)
Thread.sleep(forTimeInterval: sleepTime)
print("after D post and \(sleepTime) sec sleep, leftMouseDown count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseDown)), leftMouseUp count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseUp))")
eventUp?.post(tap: .cghidEventTap)
Thread.sleep(forTimeInterval: sleepTime)
print("after D and U post and \(sleepTime) sec sleep, leftMouseDown count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseDown)), leftMouseUp count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseUp))")
print("\nSleeping for \(inBetweenClickSleepTime) secs, then trying another click\n")
Thread.sleep(forTimeInterval: inBetweenClickSleepTime)
print("before D & before U post, leftMouseDown count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseDown)), leftMouseUp count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseUp))")
eventDown?.post(tap: .cghidEventTap)
Thread.sleep(forTimeInterval: sleepTime)
print("after D post and \(sleepTime) sec sleep, leftMouseDown count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseDown)), leftMouseUp count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseUp))")
eventUp?.post(tap: .cghidEventTap)
Thread.sleep(forTimeInterval: sleepTime)
print("after D and U post and \(sleepTime) sec sleep, leftMouseDown count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseDown)), leftMouseUp count: \(CGEventSource.counterForEventType(.hidSystemState, eventType: .leftMouseUp))")
}
}
Some interesting stuff happens: if I put sleepTime
and inBetweenClickSleepTime
to 0, counters are not increased. The output becomes:
- before D & before U post, leftMouseDown count: 4190, leftMouseUp count: 4190
- after D post and 0.0 sec sleep, leftMouseDown count: 4190, leftMouseUp count: 4190
- after D and U post and 0.0 sec sleep, leftMouseDown count: 4190, leftMouseUp count: 4190
- Sleeping for 0.0 secs, then trying another click
- before D & before U post, leftMouseDown count: 4190, leftMouseUp count: 4190
- after D post and 0.0 sec sleep, leftMouseDown count: 4190, leftMouseUp count: 4190
- after D and U post and 0.0 sec sleep, leftMouseDown count: 4190, leftMouseUp count: 4190
Even so, a single click is registered in the target window (provided I de- and re-checked the app's privileges after compile). If I put sleepTime
and inBetweenClickSleepTime
to 0.05 and 0.1 but forget to do the privileges trick, counters are not increased and the target window doesn't receive the event. If I do reset privileges, the output becomes:
- before D & before U post, leftMouseDown count: 4036, leftMouseUp count: 4036
- after D post and 0.05 sec sleep, leftMouseDown count: 4037, leftMouseUp count: 4036
- after D and U post and 0.05 sec sleep, leftMouseDown count: 4037, leftMouseUp count: 4037
- Sleeping for 0.1 secs, then trying another click
- before D & before U post, leftMouseDown count: 4037, leftMouseUp count: 4037
- after D post and 0.05 sec sleep, leftMouseDown count: 4038, leftMouseUp count: 4037
- after D and U post and 0.05 sec sleep, leftMouseDown count: 4038, leftMouseUp count: 4038
That is, both Down events and both Up events are registered by the counters. Still, the target window seems to receive only 1 click. For example, if the target window is Mail and the click is on a message, it doesn't open up - it just gets selected. Things don't change if I set inBetweenClickSleepTime
to 0 but keep sleepTime
at 0.05. Removing the Dispatch also doesn't help....