Is there a way to register for global mouse moved events in Cocoa? I was able to register for the events using Carbon's InstallEventHandler(), but would prefer a Cocoa equivalent. I have looked for NSNotificationCenter events, but there doesn't seem to be any public event names (are there private ones?)
Alternatively, is there a way to use NSTrackingArea for views with a clearColor background?
The app is Snow Leopard only.
In SnowLeopard there is a new class method on NSEvent which does exactly what you want: + (id)addGlobalMonitorForEventsMatchingMask:(NSEventMask)mask handler:(void (^)(NSEvent*))block. You’ll want mask = NSMouseMovedMask.
A similar question was already asked on StackOverflow:
How to make a transparent NSView subclass handle mouse events?
To summarize, the tansparent view method didn't work. Quartz Event Taps seem to be the best answer.
Here are some hints on working with taps:
Create the tap with CGEventTapCreate.
a) For the location (first) parameter you'll probably want to use kCGSessionEventTap.
b) For the placement (second) parameter you'll probably want kCGHeadInsertEventTap.
c) For the event mask parameter, try (1 << kCGEventMouseMoved).
Create a run loop source with CFMachPortCreateRunLoopSource, passing the event tap as the second parameter.
Add the run loop source to your run loop. Assuming you want it added to the main run loop, do:
CFRunLoopAddSource(CFRunLoopGetMain(), sourceFromStep2, kCFRunLoopDefaultMode);
Enable the event tap with CGEventTapEnable
If you want to track the mouse no matter where it is, you want a CGEventTap. There is no Cocoa equivalent. If you just want to track it in your application then you should explain why you're finding yourself unable to do so a little more thoroughly.
Related
I'm working on a screenshot Mac app. I'm trying to rebuilt what happens when you press Cmd-Ctrl-Shift-4: the cross hair cursor and the selection rectangle for the screenshot.
I'm using a custom borderless NSWindow on top of all other windows. I disabled the cursor to draw my own along with the selection rectangle.
My problem is that as soon as I click & drag to capture a screenshot, my app gets activated (because the click is intercepted by my shielding window).
Is there a way how I can receive the click in my custom view/window without having my app get activated?
I tried using an NSPanel with the NSNonactivatingPanelMask flag, but in this case, I have a problem with the cursor: I can't draw my own when another app is active, because I can't hide the cursor for other apps...
Actually, I have a new, better answer to this question involving more undocumented goodies. Here it is for future posterity:
There is an undocumented method on NSWindow that does exactly what you want:
#interface NSWindow (Private)
- (void )_setPreventsActivation:(bool)preventsActivation;
#end
[myWindow _setPreventsActivation:true];
This stops the window from activating both itself and its application when the user clicks on it.
The standard warnings about using undocumented APIs of course apply: Apple may change this at some point (although it's been around for many OS X versions so there's a good chance they won't) and using this may get your app rejected from the Mac app store.
For what it's worth, there's another way to make the cursor invisible globally other than creating a giant window. It involves some undocumented APIs if that's something you can use:
extern "C" {
typedef int CGSConnection;
void CGSSetConnectionProperty(int, int, const void *, const void *);
int CGSMainConnectionID();
}
void allowHidingCursorForBackgroundOnlyApp()
{
CFStringRef propertyString = CFStringCreateCopy(NULL, CFSTR("SetsCursorInBackground"));
CGSSetConnectionProperty(CGSMainConnectionID(), CGSMainConnectionID(), propertyString, kCFBooleanTrue);
CFRelease((CFTypeRef)propertyString);
}
Combine that with judicious use of event taps to capture and filter out mouse clicks, and you can create the same effect as the built-in screen shot feature.
I pray that there is a better way to do this now, but when I had to do something similar I ended up letting my window/view ignore all mouse input, then I used a CGEventTap (see Quarts Event Services documentation) to capture mouse events globally(without removing them from the event queue). I them mapped them manually to my window, created a custom copy NSEvent and manually dispatched it to my window.
The huge downside here (aside from complexity) is that I recall needing to run as root to be able to install the event tap. However, I think there is a way to get permission though universal access.
I'm completely unsure if dispatching a custom NSEvent directly to the window will have the same side effect of activating your application; especially since many things have changed since 10.6... I would suggest a simple test to see if this is feasible before pursuing it.
One more idea, you can override - (BOOL)_isNonactivatingPanel private method in NSWindow subclass:
#implementation MyWindow
- (BOOL)_isNonactivatingPanel
{
return YES;
}
#end
Voila, you got behaviour similar to NSPanel :)
I am making an app that has to save the screen, like a screenshot, when the screen is tapped or touched a specific number of times. I have tried all of the solutions that other users have suggested that are associated with my question, but nothing helps...
I will appreciate all suggestions. :)
Thanks
The following blog post does a good job of explaining the built-in option for recognizing multiple taps in a row (and explains the shortcomings): Detecting tap and double-tap with Gesture Recognizers.
If you need more customized logic than is provided by the built-in gesture recognizers, you will either be implementing your own custom subclass of UIGestureRecognizer or you will be adding your logic into the UIResponder (superclass of UIViewController, UIView, etc.) callbacks for tap input: touchesBegan:withEvent:, touchesMoved:withEvent:, and touchesEnded:withEvent:.
I have more experience with the latter method (not UIGestureRecognizer). The UITouch events passed to the various UIResponder callbacks each contain information about touch location and touch timing. You could use this information in combination with a NSTimer to determine if the user taps twice (or more) within a certain amount of time. If the timer fires before the second (or nth touch), then you can consider it a single touch event.
I don't know if that is the best way to do this, but it is certainly more granular control than the built-in UIGestureRecognizers provide you.
I know there are several questions on Stackoverflow regarding global mouse events in MacOsX and I've spent the last hours searching for one that helped me out.
What I want to create is a functionality that works almost like the build in screenshot functionality of OsX. (Shift+CMD+4)
I want to press a Shortcut and activate the mouse listener with it. Then the mouseDown event should return one coordinate and the mouseRelease event another one. I then want to make a CGRect from them and the eventlistener should be deactivated.
All the codesamples I found give me mouseEvents in a NSView or NSWindow but not global or they give me the location of the mouse coordinate but I've to poll it by myself with a NSTimer. Neither of those is what I need.
As I said: I've spent several hours searching. I've read through many questionthreads and the Apple guide for Cocoa event handling but none of the answers really helped me out.
Thanks for your time!
You will be able to get the global mouse events using
1) CGEvents. Use CGEventTap().
2) From OS X v 10.6, there is a new method :
+ (id)addGlobalMonitorForEventsMatchingMask:(NSEventMask)mask handler:(void (^)(NSEvent*))block
I've run in a bit of a pickle with my puzzle game for windows phone.
I want to change between two adjutant rectangles, both on the same grid.
The tap event was easily implemented, but implementing drag seems to be a really big pain.
I'm also using a custom user control to get the rectangles on the grid, so i need to create custom delegates before attaching events to my rectangle matrix.
I am currently using the manipulation completed and manipulation started events to implement the drag gesture, but there are a couple of problems:
1) i have to tell the difference between tap and actual drag, both which are covered by the manipulation completed event. This is the way I do it right now:
if (e.TotalManipulation.Translation.X == 0 && e.TotalManipulation.Translation.Y == 0)
{
}
else
{do drag stuff here}
however, the do drag stuff here part does not seem to work, even if the transitions are different from 0; It always executes the tap event.
I am currently stacked in using manipulation events, because, as i said, I am using a custom control as an object prototype for my rectangle matrix, and i need custom delegates for that, and apparently, the GestureListener has no constructors for its event classes.
So, any suggestion on how to do this?
I figured the answer just after posting this question.
You can actually attach a gesture listener to a custom control and create custom delegates, by sending the drag gesture event parameter from the gesture listener drag event to the delegate you create and it works.
I have a problem: how can I create gesture event by code, (rotate, magnify or swipe...), I don't want to use it to zoom or rotate a specific image or something like that, I want to create gesture event like scroll event create by CGEventRef cgEvent = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitLine, wheelCount, yScroll, xScroll);
CGEventPost(kCGHIDEventTap, cgEvent);
Thanks
Not all events have "shortcut" creation functions (like CGEventCreateScrollWheelEvent, CGEventCreateMouseEvent, and CGEventCreateKeyboardEvent), so you have to create an empty event and then set the fields manually using the CGEventSet* functions.
The gesture-related events only have public constants for the Cocoa API level. For example, while NSLeftMouseDragged == kCGEventLeftMouseDragged == NX_LMOUSEDRAGGED == 6, NSEventTypeMagnify == 30 doesn't have any equivalent kCGEventMagnify or NX_MAGNIFY.
Also, the way gesture events work is a bit tricky; if you don't send the proper sequence of mouse/trackpad events, gesture, gesture begin/end, and specific-gesture events, it won't work.
There's not much documentation on which fields each event type needs; the easiest way to find out is to first create an event tap that logs everything, then generate the events you want and see what gets logged. In fact, you probably want to also log an NSEvent global monitor (log both the NSEvent itself and its underlying cgEvent).