Reputation: 326
When Mission Control runs, it prevents applications from receiving keyboard and mouse events. It also leaves the last application running thinking that it still has focus. This is a problem for me because I don't receive keyUp or mouseUp events if I start Mission Control with a mouse button or a key held down and my application will behave as if that mouse button or key is held down.
I would like a way to either read both keyboard and mouse events even when Mission Control is active, or a way of detecting that Mission Control is active. Ideally, I would like to be able to do the latter since I effectively can't use my application when Mission Control is running.
I've tried a couple of things with no luck:
[[NSRunningApplication currentApplication] {isActive, ownsMenuBar}]
.
Apparently, my application is active even though it's not receiving events![NSApp keyWindow] != nil
.
Apparently, one of my windows should be receiving key events. None of them are.[NSWorkspace runningApplications]
. Mission Control does not show up in this list when it's running.Edit:
I've finally worked around this problem (albeit not in a very satisfactory way). For the mouse, it turns out that you can query the state of the pressed buttons with [NSEvent pressedMouseButtons]
. I simply keep track of what I think the mouse state should be from NSLeftMouseDown and NSLeftMouseUp events and compare that to [NSEvent pressedMouseButtons]
every so often to make sure that they're consistent. If they're not, then I know that something has hijacked my NSLeftMouseUp event and act accordingly.
For the keyboard, I could not find a way to query the keyboard state, so I couldn't do a similar workaround. I ended up disabling application switching using presentation options when keys are pressed.
Upvotes: 27
Views: 3005
Reputation: 21
C++ and Qt implementation works in latest OS X.
bool Window::missionControlIsActive() {
bool result = false;
CFArrayRef windows = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly+kCGWindowListExcludeDesktopElements, kCGNullWindowID);
for (int i = 0; i < CFArrayGetCount(windows) ; i++) {
auto cfMutableDictionaryRef_dict = (CFMutableDictionaryRef)CFArrayGetValueAtIndex( windows, i );
auto cfStringRef_name = (CFStringRef)CFDictionaryGetValue(cfMutableDictionaryRef_dict, kCGWindowName);
if (QString::fromCFString(cfStringRef_name) != u"") continue;
auto cfStringRef_ownerName = (CFStringRef)CFDictionaryGetValue(cfMutableDictionaryRef_dict, kCGWindowOwnerName);
if (QString::fromCFString(cfStringRef_ownerName) != u"Dock") continue;
auto cfDictRef_bounds = (CFDictionaryRef)CFDictionaryGetValue(cfMutableDictionaryRef_dict, kCGWindowBounds);
auto cfNumRef_bounds_Y = (CFNumberRef)CFDictionaryGetValue(cfDictRef_bounds, QString("Y").toCFString());
double num;
CFNumberGetValue(cfNumRef_bounds_Y, kCFNumberFloat64Type, &num);
if (num > 1.0 and num < 1000000) continue;
result = true;
break;
}
CFRelease(windows);
return result;
}
Upvotes: 0
Reputation: 1689
At least in OS X 10.10, you can use this code to check if Mission Control is active or not:
func missionControlIsActive() -> Bool
{
var result: Bool = false
let windowInfosRef = CGWindowListCopyWindowInfo(CGWindowListOption(kCGWindowListOptionOnScreenOnly), CGWindowID(0)) // CGWindowID(0) is equal to kCGNullWindowID
let windowList: NSArray = windowInfosRef.takeRetainedValue() // We own the returned CFArrayRef
for entry in windowList
{
if (entry.objectForKey("kCGWindowOwnerName") as! String) == "Dock"
{
var bounds: NSDictionary = entry.objectForKey("kCGWindowBounds") as! NSDictionary
if (bounds.objectForKey("Y") as! NSNumber) == -1
{
result = true
}
}
}
return result
}
In a nutshell, the code checks if a specific window owned by the OS X Dock process is visible on the screen and if it is in a specific position. If both conditions are met, Mission Control will be active right now. Code will work in a sandboxed app and no privileges for assistive devices are required.
Upvotes: 4
Reputation: 8722
It does appear that DTrace has some ability to see Mission Control being activated. Try running:
sudo fs_usage -filesys | grep Mission
from the command line and then launching the Mission Control app from the /Application folder.
You should see a lot of output related to Mission Control starting up. Unfortunately, this same output did not appear by using the keyboard short cut or swiping. Of course, using DTrace in production code is not something I would actually recommend.
Upvotes: 0
Reputation: 5971
Did you try on bash level using NSTask? Something like ps -faxU <username>
should list all running processes and then you could parse the output, or indeed you could use ps -faxU <username> | grep -i "mission control"
(At the top of my head I am not sure how the process may be called, but sth like "mission control" seems legit). Not the most elegant solution maybe, but if nothing else works it may be worth it.
Upvotes: 1
Reputation: 966
May be i'm missing something, but have you tried to use event taps instead of global monitoring?
Upvotes: 0