Back in 2010, Pierre asked this question (his accepted answer doesn't work for me).
I'm having the same problem: I am able to successfully move the mouse around (and off!?!) the screen programmatically from my Cocoa Application, however bringing the mouse to the location of my dock doesn't show it (and some other applications aren't registering the mouse moved event, eg. games that remove the mouse)
The method I am using is thus:
void PostMouseEvent(CGMouseButton button, CGEventType type, const CGPoint point)
{
CGEventRef theEvent = CGEventCreateMouseEvent(NULL, type, point, button);
CGEventSetType(theEvent, type);
CGEventPost(kCGSessionEventTap, theEvent);
CFRelease(theEvent);
}
And then when I want to move the mouse I run:
PostMouseEvent(0, kCGEventMouseMoved, mouseLocation);
Note that this code DOES generate mouseover events for things such as links.
Now that's it's 2013, is it possible to fix this issue?
Thanks for your time!
I would both warp the cursor and generate the mouse-move event. I know from experience, for example, that warping the cursor, while it doesn't generate an event itself, modifies the subsequent mouse move event to include the moved distance in its mouse delta. I don't know if your synthesized move event will include the proper delta values on its own.
OK, so evidently MacOSX needs the mouse to be at exactly the edge of the screen for the dock to show!
Because I keep my dock on the left-side of the screen (due to many programs keeping vital buttons at the bottom of their windows), all I had to do was say
if (mouseLocation.x < 0)
{
mouseLocation.x = 0;
}
And it worked!
I am also using KenThomases' idea to warp the cursor as well.
(this answer is marked correct as it allows me to show the dock - however there are still some applications that are not responding to mouse input)
Related
So I have a game for Mac OS X built in cocos2D.
I'm using gestures to simulate keyboard commands to control my character and it works really well.
I submitted my game to the AirSpace store and it got rejected on the grounds that the Leap should be used to control my menus as well which is fair enough I guess.
Thing is for the life of me I cannot figure out how this is done. There are no examples out there to show me how to implement it and nothing in the SDK example that makes it clear either.
Does anyone have any examples they'd care to share, I only need it to hijack my cursor and allow a click when held over a button. I really didn't think something so complex would be needed on simply for basic menu navigation.
If this is a Mac only game you should have access to the Quartz event api. This is the easiest way to generate mouse events in OS X...
I would recommend simply tracking the palm (hand) position, and moving the cursor based on that.
This is how I do my palm tracking:
float handX = ([[hand palmPosition] x]);
float handY = (-[[hand palmPosition] y] + 150);
The "+ 150" is the number of millimetres above the Leap device, to use as the '0' location. From there you can move the cursor based on the hand offset from 0.
The function I use to move the cursor (using Quartz):
- (void)mouseEventWithType:(CGEventType)type loc:(CGPoint)loc deltaX:(float)dX deltaY:(float)dY
{
CGEventRef theEvent = CGEventCreateMouseEvent(NULL, type, loc, kCGMouseButtonLeft);
CGEventSetIntegerValueField(theEvent, kCGMouseEventDeltaX, dX);
CGEventSetIntegerValueField(theEvent, kCGMouseEventDeltaY, dY);
CGEventPost(kCGHIDEventTap, theEvent);
CFRelease(theEvent);
}
and an example function call:
[self mouseEventWithType:kCGEventMouseMoved loc:CGPointMake(newLocX, newLocY) deltaX:dX deltaY:dY];
This call will move the mouse. Basically you just pass the new location of the mouse, and the corresponding deltas, relative to the last cursor position.
I can provide more examples such as examples for getting mouse location, clicking the mouse, or even a full mouse moving program...
EDIT 1:
To handle click and drag with Quartz, you can call the same function as above only pass in kCGEventLeftMouseDown.
The catch is that in order to drag you cannot call the kCGEventMouseMoved you must instead pass kCGEventLeftMouseDragged while the drag is happening.
Once the drag is done you must pass a kCGEventLeftMouseUp.
To do a single click (no drag) you simply call mouse down and then up right after, without any drag...
My application is screenshot maker. User needs to select screen area to make a screenshot. I use Win32 API with PureBasic, but it doesn't matter, all is similar with C++.
When user runs application, the semitransparent borderless form is shown on full screen to hook mouse over all other windows. On mouse down event selection is started and I apply XORed region to the form to cut a hole in it with size of current selection.
I create and apply a new region on every mousemove event:
rgn1 = CreateRectRgn_(0,0,DWidth,DHeight) ; full size of desktop
rgn2 = CreateRectRgn_(sx, sy, ex, ey) ; current selection points
CombineRgn_(rgn1, rgn1, rgn2, #RGN_XOR)
SetWindowRgn_(WindowID(0), rgn1, #True); apply region
It works well on my computer with Windows XP, but works buggy on other computer with Vista. I think it is wrong when I create the new region object on every mouse move. Maybe I need to create it once and then to resize? Can anybody explain how to do this right? Examples on C++ are ok.
In the beginning you create region, using CreateRectRgn (like in your code).
Then it's enough to call SetRectRgn function for updating region bounds
I am making an application to control the mouse using an analog stick from a gamepad for Mac OS X (10.7.3).
Currently it is working pretty well, I can control the cursor in desktop and most games. But in Team Fortress 2, I cant control the aim, but can control the cursor in the menu. Mouse wheel and clicks works everywhere.
Another strange thing is that when I move the real mouse, the aim "jumps" the traveled distance from my "virtual mouse" before aiming normally, so it somewhat is receiving the events.
The game option "Raw mouse input" is disabled (I think it is not even supported in osx). And a similar application can controle the aim successfully.
I suspect the game is looking for "delta movement" or "relative movement" events or anything similar, but my code sets the position of the cursor using absolute positions. Not sute how to change this.
Here is the snippet of code used to send mouseMoved events:
EDIT: Crappy code removed!
.
EDIT:
Also, because I did this way, I need to check the screen bounds manually to prevent the cursor going Crazy. So in multi-screen setups, and when the user change the resolution, it gets worst. Would be so much better if I can just send the amount of movement and let the OS take care of constraining the cursor.
.
The question is:
I am doing the mouse move events the wrong way?
How can I fix this?
EDIT2:
So, that was just a stupid bug, sorry =P
I just forgot to call CGSetIntegerValueField(kCGEventMouseDeltaX, ...) (and Y) with the delta values... =P
Finally got this working, after just a few short hours of Googling and experimenting :) Looks like Rodrigo was trying to say that you have to call CGEventSetIntegerValueField on kCGMouseEventDeltaX and kCGMouseEventDeltaY on the mouse event after constructing it.
My code, using PyObjC:
from Quartz.CoreGraphics import (
CGEventCreate,
CGEventCreateMouseEvent,
CGEventGetLocation,
CGEventPost,
CGEventSetIntegerValueField,
kCGEventMouseMoved,
kCGHIDEventTap,
kCGMouseEventDeltaX,
kCGMouseEventDeltaY,
)
def mouse_delta(delta_x, delta_y):
"""
Send a MouseMoved event with the given deltaX and deltaY attributes,
but without changing the cursor location.
"""
# Might be a better way to get the current mouse location
x, y = CGEventGetLocation(CGEventCreate(None))
# The `mouseButton` parameter to CGEventCreateMouseEvent is ignored
# unless `mouseType` is kCGEventOtherMouse{Down,Dragged,Up},
# so let's just pass the value 0
event = CGEventCreateMouseEvent(None, kCGEventMouseMoved, (x, y), 0)
CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, delta_x)
CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, delta_y)
return CGEventPost(kCGHIDEventTap, event)
I am working on a DX11 game, and I want to clip the cursor during fullscreen mode to the fullscreen window. I use this method
void MyClass::_SetupCursor( BOOL bFullscreen ) {
// Clip cursor if requested
if( bFullscreen ) {
if(m_bShowCursorWhenFullscreen) {
ShowCursor(m_bShowCursorWhenFullscreen);
}
if(m_bClipCursorWhenFullscreen) {
// Confine cursor to full screen window
RECT windowRect;
GetWindowRect( m_hWnd, &windowRect );
ClipCursor( &windowRect );
}
}
else {
ShowCursor( TRUE );
ClipCursor( NULL );
}
}
However, when I am in fullscreen mode with 2 monitors, I can still move the mouse over to the other monitor. With resolution set to 2048x1152 in fullscreen mode, I get the window rectangle as 1360x768, and that is what it gets clipped to. I confirm that it is clipped using GetClippedRect.
So I have two questions:
1) Why isn't the mouse getting clipped to the monitor my window is in?
2) Why is the window rectangle measured as 1360x768 when I know for a fact the monitor is 2048x1152, and I have the resolution set to 2048x1152?
It turns out that for ClipCursor to work, you must have all your DX11 buffers and your window size correct. I found this out by running my application in fullscreen first, without toggling into it, and ClipCursor worked just fine, even with multiple monitors. For more information on when ClipCursor will fail, check out my other question on stackoverflow: Why is D3D10SDKLayers.dll loaded during my DX11 game? .
ClipCursor will fail ever time the situations i describe in that question arise. Also, in response to my 2nd question, the window size is incorrect because of the situation I describe in the linked question.
Unfortunately according to a comment on the documentation (by a user) it appears that this does not work for multimonitor setups. You may want to develop a method that will reposition the mouse when it goes off screen, turns off the rendring for it, then turn it back on when you move the cursor back to the window (to detect if the mouse moves off the window or not, there is windows messages for that).
I'm developing an extension to MATLAB's PsychToolbox that allows for better control of the mouse during psychophysical experiments (specifically, preventing the screen boundaries from limiting drag operations... it should feel like you can move the mouse "infinitely" in all directions). Since MATLAB doesn't support the creation of additional threads (and that would be needlessly complicated for this situation anyway), I can't make use of either the Carbon or Cocoa event managers.
CGGetLastMouseDelta is almost perfect for what I need to do (it gets me the amount the mouse has moved "since the last mouse movement event received by the application" ignoring screen boundaries), however there is one slight problem. When moving the mouse programatically (using either CGWarpMouseCursorPosition or CGDisplayMoveCursorToPoint), no events are generated. Therefore, CGGetLastMouseDelta doesn't seem to be aware that the mouse has moved at all. In other words, if I move the mouse 50 pixels over and 50 pixels down programatically, CGGetLastMouseDelta returns (0, 0) afterwards for the mouse delta. This is undesirable behavior in my context, and requires ugly workarounds. I've tried moving the mouse by posting events through the event system, as follows (this is a "mexFunction", MATLAB's way of calling C code):
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
CGEventRef event;
CGPoint offset;
CGPoint currentLocation;
CGPoint newLocation;
if (nrhs != 2)
mexErrMsgTxt("The global x and y coordinates (and only those) must be supplied.");
event = CGEventCreate(NULL);
currentLocation = CGEventGetLocation(event);
CFRelease(event);
offset = CGPointMake((CGFloat) mxGetScalar(prhs[0]), (CGFloat) mxGetScalar(prhs[1]));
newLocation = CGPointMake(currentLocation.x + offset.x, currentLocation.y + offset.y);
event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, newLocation, kCGMouseButtonLeft);
CGEventPost(kCGHIDEventTap, event);
CFRelease(event);
}
This happily moves the mouse, but doesn't seem to change the behavior of CGGetLastMouseDelta at all. Does anybody know the exact specifications regarding what is returned by CGGetLastMouseDelta (and when?). Apple's documentation on on this stuff (the Quartz reference) is as usual close to useless (or at least, lacking in necessary details).
Thanks!
A good idea might be to use CGAssociateMouseAndMouseCursorPosition(0) to disconnect mouse movement from the cursor. Then you don't get the problem with screen boundaries.
Option (1) Generate your own event which specifies that you caused the mouse to move.
Option (2) Call your mouse moved event handler function from the I moved the mouse routine.