CGEventPostToPSN() not working for mouse clicking - objective-c

I need to send mouse click events to an arbitrary process (not necessarily the front one) without bringing that process's window to the front.
This code works for sending a mouse click and letting the window server send it to whatever process it decides has focus:
#include <ApplicationServices/ApplicationServices.h>
int
main()
{
CGEventRef down, up;
down = CGEventCreateMouseEvent(
NULL,
kCGEventLeftMouseDown,
CGPointMake(16, 36),
kCGMouseButtonLeft
);
up = CGEventCreateMouseEvent(
NULL,
kCGEventLeftMouseUp,
CGPointMake(16, 36),
kCGMouseButtonLeft
);
CGEventPost(kCGHIDEventTap, down);
CGEventPost(kCGHIDEventTap, up);
CFRelease(down);
CFRelease(up);
return 0;
}
I can send mouse click events via CGEventPost() just fine, but that requires the target process to have focus (which I am trying to avoid).
I can send keyboard events via CGEventPostToPSN() just fine, and as far as I can tell, mouse move events work too, what I'm having trouble with is mouse down/up events.
This code (pretty much the above, the only difference being that I specify myself which process to send the events to) does not work and I don't even know how to find out where it breaks down.
#include <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h> /* for ProcessSerialNumber stuff */
#include <stdio.h>
int
main()
{
ProcessSerialNumber psn;
CGEventRef down, up;
if (GetFrontProcess(&psn) != noErr) {
printf("Unable to get front process\n");
return 1;
}
down = CGEventCreateMouseEvent(
NULL,
kCGEventLeftMouseDown,
CGPointMake(16, 36),
kCGMouseButtonLeft
);
up = CGEventCreateMouseEvent(
NULL,
kCGEventLeftMouseUp,
CGPointMake(16, 36),
kCGMouseButtonLeft
);
CGEventPostToPSN(&psn, down);
CGEventPostToPSN(&psn, up);
CFRelease(down);
CFRelease(up);
return 0;
}
I've been stuck on this for a few days now, and I can't seem to figure it out. According to the documentation this is (as far as I can tell) exactly how it is supposed to be done.
I have tested this code on Snow Leopard and Lion, with the same results.
Could somebody who has had success with clicking via CGEventPostToPSN() please shed some insight on the proper way to accomplish this?

Related

macOS objective C generate keyboard events keystroke with repeat

How to generate keystroke with repeat in macOS application with objective-c?
I already manage to generate the keystroke:
CGEventRef keyup, keydown;
uint64_t keyModifier=0;
VK = kVK_RightArrow;
keyModifier = 0;
keydown = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)VK, true);
CGEventSetFlags( keydown, keyModifier);
keyup = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)VK, false);
CGEventSetFlags( keyup, keyModifier);
// press the key
// forward them to the frontmost app
CGEventPostToPid (pid, keydown);
// and finally behave friendly
CFRelease(keydown);
....
// somewhere else with time delay
// release the key
// forward them to the frontmost app
CGEventPostToPid (pid, keyup);
// and finally behave friendly
CFRelease(keyup);
Using this code the equivalent keyboard right key is pressed then released, but no repeat although there is enough time between the 2 events.

Generating relative mouse events on macOS using Core Graphics

I'm using the Core Graphics framework to generate mouse events. I want to be able to move the mouse around normally and also move the mouse inside of an FPS game. The issue I'm having is that these two situations seem to require different events.
I can use the following to move the mouse outside of a game.
// Event source was created with this:
// CGEventSourceCreate(kCGEventSourceStateCombinedSessionState)
CGPoint mouse_location(CGEventSourceRef source) {
CGEventRef event = CGEventCreate(source);
CGPoint loc = CGEventGetLocation(event);
CFRelease(event);
}
void mouse_move_relative(CGEventSourceRef source, int x, int y) {
CGPoint pos = mouse_location(source);
pos.x += x;
pos.y += y;
CGEventRef event = CGEventCreateMouseEvent(source, kCGEventMouseMoved, loc, kCGMouseButtonLeft);
CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, x);
CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, y);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
This works outside of a game but inside a game, the mouse seems to hit the edge of the screen and stop. So I tried using deltas without setting the position.
void mouse_move_relative(CGEventSourceRef source, int x, int y) {
CGEventRef event = CGEventCreate(source);
CGEventSetType(event, kCGEventMouseMoved);
CGEventSetIntegerValueField(event, kCGMouseEventButtonNumber, kCGMouseButtonLeft);
CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, x);
CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, y);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
This works inside of a game and the mouse doesn't hit the edge of the screen but the mouse doesn't move when outside of the game. If I'm inside a game and open a menu screen, I can't move the mouse anymore. I need two separate code paths or two separate modes for these two situations. I'm trying to avoid having to switch between modes and wondering if this is at all possible.
Can I generate a mouse event that works in both situations?
Maybe there's some way that I tell when the system has gone into relative mouse mode and change the emitted events accordingly? I'm not sure if Core Graphics can do that (or if that even makes sense). Also, I don't fully understand what kCGHIDEventTap and kCGEventSourceStateCombinedSessionState mean. The docs are talking about taps and tables and I don't really get it. Maybe all I need to do is change one of those...?
Note that the above snippets might not be quite right because I'm using a wrapper library in Rust but that's besides the point.
Turned out to be quite simple. All I needed to do was limit the mouse coordinates within the display.
CGDirectDisplayID display = CGMainDisplayID();
size_t width = CGDisplayPixelsWide(display);
size_t height = CGDisplayPixelsHigh(display);
pos.x = min(max(pos.x, 0), width - 1);
pos.y = min(max(pos.y, 0), height - 1);

SDL left mouse button event without press on startup

On the start-up of my SDL program a left mouse button event is registered without me pressing the physical left mouse button. The next physical left button press is not registered. All other keys and buttons work normal. When clicking the .exe the mouse is not located within the location of the window.
Here are the specifications of that event (taken from the SDL_Event struct):
type=1025 (SDL_MOUSEBUTTONDOWN)
timestamp=24
windowID=1
which=0
button=1 (SDL_BUTTON_LEFT)
state=1
clicks=1
x=0
y=0
I am on windows 8.1 compiling with MinGW (gcc version 4.8.1).
I have SDL version 2.0.3
This is my source code:
#include <stdio.h>
#include <SDL.h>
int main(int argc, char* argv[])
{
SDL_Window* window = NULL;
SDL_Surface* screen = NULL;
SDL_Event ev;
SDL_Init(SDL_INIT_EVERYTHING);
window = SDL_CreateWindow("SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, 0);
screen = SDL_GetWindowSurface(window);
while (1) {
while (SDL_PollEvent(&ev)) {
if (ev.type == SDL_QUIT)
return 0;
else {
if (ev.type == SDL_MOUSEBUTTONDOWN) {
if (ev.button.button == SDL_BUTTON_LEFT) {
printf("MOUSE DOWN\n");
printf("type=%d\n", ev.button.type);
printf("timestamp=%d\n", ev.button.timestamp);
printf("windowID=%d\n", ev.button.windowID);
printf("which=%d\n", ev.button.which);
printf("button=%d\n", ev.button.button);
printf("state=%d\n", ev.button.state);
printf("clicks=%d\n", ev.button.clicks);
printf("x=%d\n", ev.button.x);
printf("y=%d\n\n", ev.button.y);
}
}
}
}
SDL_UpdateWindowSurface(window);
SDL_Delay(5);
}
SDL_FreeSurface(screen);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
I have tried to solve it by calling SDL_PumpEvents() and SDL_FlushEvents() and while this removed the first (erroneous) event, the second press was still not registered.
Something strange I noticed was that it worked as expected when I opened the program .exe by right clicking and then pressing 'open'.
It'd be very grateful if somebody could shed light on this issue.

How to discard command+shift+Q command in mac OS X objective c code?

I'm trying to implement a screensaver simulator on Mac OS X , I managed to disable the effect of pressing command+Q that was causing the application to exit, so now if it's in the full screen mode, it will not respond to the quit keyboard shortcut.
But, my problem is in handling the shortcut of ( Command+ Shift+Q) that pops up the confirmation dialog of Max OS X that warns exiting all the apps and logging of the system.
Can anyone help me in preventing the effect of command+shift+q shortcut while being in full screen mode ?
thanks
This is the best answer for this question
First in your applicationDidFinishedLoad function, add this peace of code to create an event tap and add the event tap in the current run loop
CFMachPortRef eventTap;
CGEventMask eventMask;
CFRunLoopSourceRef runLoopSource;
// Create an event tap. We are interested in key presses.
eventMask = ((1 << kCGEventKeyDown) | (1 << kCGEventKeyUp));
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0,
eventMask, myCGEventCallback, NULL);
if (!eventTap) {
fprintf(stderr, "failed to create event tap\n");
exit(1);
}
// Create a run loop source.
runLoopSource = CFMachPortCreateRunLoopSource(
kCFAllocatorDefault, eventTap, 0);
// Add to the current run loop.
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource,
kCFRunLoopCommonModes);
// Enable the event tap.
CGEventTapEnable(eventTap, true);
then in your class, you can implement the call back function called myCGEventCallback like this
CGEventRef myCGEventCallback(CGEventTapProxy proxy, CGEventType type,
CGEventRef event, void *refcon)
{
// Paranoid sanity check.
// type will be key down or key up, you can discard the command + q by setting the kecode to be -1 like this
if (((type == kCGEventKeyDown) || (type == kCGEventKeyUp)))
{
CGEventSetIntegerValueField(
event, kCGKeyboardEventKeycode, (int64_t)-1);
return event;
}
// The incoming keycode.
CGKeyCode keycode = (CGKeyCode)CGEventGetIntegerValueField(
event, kCGKeyboardEventKeycode);
// Swap 'a' (keycode=0) and 'z' (keycode=6).
if (keycode == (CGKeyCode)0)
keycode = (CGKeyCode)6;
else if (keycode == (CGKeyCode)6)
keycode = (CGKeyCode)0;
// Set the modified keycode field in the event.
CGEventSetIntegerValueField(
event, kCGKeyboardEventKeycode, (int64_t)keycode);
// We must return the event for it to be useful.
return event;
}
for the original code
Check Here
Thanks

The 10.6.3 os x update broke simulated key-presses for Nestopia

The iPhone app that I released is a wireless game controller, it translates touches on the device into key-presses on the networked Mac. This allowed for playing emulator (e.g. Nestopia) games using the iPhone as a controller. Of course, the day that I released it coincided with an os x update. After installing this update, the simulated key-presses no longer work in Nestopia! The crazier thing is, when I go to 'File > Open' within Nestopia, I can cycle through the file list by hitting the up-arrow on my iphone controller; i.e. the simulated key-presses work in menu items, but not in the game itself. The code that I use to simulate keys is below. Given the list of changes here, can anyone identify which change would cause this problem?
Thanks!!
#define UP false
#define DOWN true
-(void)sendKey:(CGKeyCode)keycode andKeyDirection:(BOOL)keydirection{
CGEventRef eventRef = CGEventCreateKeyboardEvent(NULL, keycode, keydirection);
CGEventPost(kCGSessionEventTap, eventRef);
CFRelease(eventRef);
}
The author of Mac Nestopia is using an older call, GetKeys(), to capture key events. As of 10.6.3, GetKeys does not catch generated key presses using the methods detailed in this post. The workaround I found was to use this instead:
-(void)sendKey:(CGKeyCode)keycode andKeyDirection:(BOOL)keydirection{
AXUIElementRef axSystemWideElement = AXUIElementCreateSystemWide();
AXError err = AXUIElementPostKeyboardEvent(axSystemWideElement, 0, keycode, keydirection);
if (err != kAXErrorSuccess)
NSLog(#" Did not post key press!");
}
Huge thanks to Richard Bannister for his quick email responses!
I think it's a problem with your code and not with 10.6.3. I have an app I'm writing that simulates key presses, and I've upgraded to 10.6.3, and my simulated key presses still work just fine.
Here's what I'm doing:
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
CGEventRef keyDownPress = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, YES);
CGEventSetFlags(keyDownPress, (CGEventFlags)flags);
CGEventRef keyUpPress = CGEventCreateKeyboardEvent(source, (CGKeyCode)keyCode, NO);
CGEventPost(kCGAnnotatedSessionEventTap, keyDownPress);
CGEventPost(kCGAnnotatedSessionEventTap, keyUpPress);
CFRelease(keyDownPress);
CFRelease(keyUpPress);
CFRelease(source);