That works!
That said, I experimented a bit more, and it turns out the problem may be elsewhere than where we were looking:
Every time I make changes to the code and recompile, I have to go to Preferences-Security and Privacy-Accessibility and de-check and re-check my App's permissions there. If I don't, the code only activates the window but doesn't activate any controls on there (note that I used a DispatchQueue
call for safety, as these functions may be called by other threads than the main UI)
With that, I tried my original code for left- and right click, and it works fine once I de-check and re-check the App's permissions in Preferences after each compile:
func leftClick() {
DispatchQueue.main.async {
let source = CGEventSource.init(stateID: .hidSystemState)
let position = self.correctedCursorPosition // use your own CGPoint location here
let eventDown = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: position , mouseButton: .left)
let eventUp = CGEvent(mouseEventSource: source, mouseType: .leftMouseUp, mouseCursorPosition: position , mouseButton: .left)
eventDown?.post(tap: .cghidEventTap)
// usleep(50_000) // there's no need to sleep, it turns out
eventUp?.post(tap: .cghidEventTap)
}
}
func rightClick() {
DispatchQueue.main.async {
let source = CGEventSource.init(stateID: .hidSystemState)
let position = self.correctedCursorPosition // use your own CGPoint location here
let eventDown = CGEvent(mouseEventSource: source, mouseType: .rightMouseDown, mouseCursorPosition: position , mouseButton: .right)
let eventUp = CGEvent(mouseEventSource: source, mouseType: .rightMouseUp, mouseCursorPosition: position , mouseButton: .right)
eventDown?.post(tap: .cghidEventTap)
// usleep(50_000) // there's no need to sleep, it turns out
eventUp?.post(tap: .cghidEventTap)
}
}
By the way, using your code, one call to testClick works fine, too. In fact, two calls works too for activating controls on the targeted window (I guess one click or two doesn't matter for most controls), but using two testClick calls on e.g. the Apple icon in TopLeft produces two clicks, so that you're activating and immediately de-activating the dropdown. Fortunately, one call to testClick works fine (at least for me) both for controls in other windows as for the Apple dropdown etc.
That leaves me with the double-click as still being an issue, unfortunately. I tried using your original code, where I can change the clickCount (tried both 1 and 2), instead of let eventDown = CGEvent(mouseEventSource: source, mouseType: .leftMouseDown, mouseCursorPosition: position , mouseButton: .left)
, etc. No luck, though...
let newMouseDownEvent = NSEvent.mouseEvent(
with: .leftMouseDown,
location: position, //NSPoint(x: 205,y: 200), // this should be in the hitWindow
modifierFlags: NSEvent.ModifierFlags.control,
timestamp: ProcessInfo.processInfo.systemUptime,
windowNumber: numberOfHitWindow,
context: nil,
eventNumber: 0, //don't know what else to use
clickCount: 1,
pressure: 1)
self.perform(#selector(NSResponder.self.mouseDown(with:)), with: newMouseDownEvent)
Thread.sleep(forTimeInterval: 0.1)
let newMouseUpEvent = NSEvent.mouseEvent(
with: .leftMouseDown,
location: position, //NSPoint(x: 205,y: 200), // this should be in the hitWindow
modifierFlags: NSEvent.ModifierFlags.control,
timestamp: ProcessInfo.processInfo.systemUptime,
windowNumber: numberOfHitWindow,
context: nil,
eventNumber: 1, //don't know what else to use
clickCount: 1,
pressure: 1)
self.perform(#selector(NSResponder.self.mouseUp(with:)), with: newMouseUpEvent)