This question might seem kind of odd. Basically I'm trying to make a menubar application. When the user presses command, I want to make so that you can't interact with other apps running (write/select/click etc).
Im using this code to detect if command and mouse button is pressed:
mouseEventMonitor = [NSEvent addGlobalMonitorForEventsMatchingMask:(NSLeftMouseDownMask ) {
if (event.modifierFlags & NSCommandKeyMask)
{
// "Freeze" all other apps.
}
}];
When I use this on the desktop it works find, however, using this xcode in safari or xcode causes huge lag because they conflict with my app. I also tried adding a invisible window behind this. But, when I did so the mouseEventMonitor will not work because it only work for events outside of the app.
I hope i explained this well enough.
Cheers.
I am don't really understand your question, but for invisible background window (inside your app) you can try use LocalMonitor instead GlobalMonitor:
mouseEventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:(NSLeftMouseDownMask | NSRightMouseDownMask | NSOtherMouseDownMask) handler:^NSEvent *(NSEvent *event) {
NSLog(#"theEvent->%#",event);
return event;
}];
Related
I am having a problem where [NSRunningApplication activateWithOptions:] returns NO when there is no obvious reason that it should fail to activate an application.
This is not a duplicate of -[NSRunningApplication activateWithOptions:] not working
The accepted answer to that question is to use NSApplicationActivateIgnoringOtherApps instead of NSApplicationActivateAllWindows but that is not an acceptable answer as the two options are intended to activate an application in a different manner as the option values imply.
There are places within my code where [NSRunningApplication activateWithOptions:] does work, however when calling it via an EventTap, it almost always returns NO regardless of using NSApplicationActivateAllWindows or NSApplicationActivateIgnoringOtherApps as the option argument. The reason I say "almost" always returns NO is because the very first time it is called, it does work. All 2nd and subsequent calls fail.
I am basically handling a single-click event on an Application icon in the Dock. I am using an EventTap installed on the Dock process that was created with CGEventTapCreateForPSN(). Within the event tap callback, I have successfully determined the process identifier of the icon that was clicked on in the Dock. The process id was obtained using the Accessibility API.
Now I need to activate the application, so I call:
BOOL result = NO;
NSRunningApplication *currentApp = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
if (currentApp) {
result = [currentApp activateWithOptions:NSApplicationActivateAllWindows];
}
In the above example, I have verified that currentApp is valid, and that bundleIdentifier, processIdentifier and a few other instance vars in the RunningApplication object are correct.
As mentioned above, regardless of the NSApplicationActivationOptions used, the application does not activate, and the method returns NO. Again, it does occasionally work on the very first click, but fails on all subsequent clicks on any application's dock icon.
Can anyone explain why such a simple method is failing? and possibly why it would work only the first time it is called? and why it always works when not executed from an EventTap?
I have spent several hours trying to resolve the issue, and the only thing that always works is to use the deprecated method SetFrontProcessWithOptions(&psn, 0); instead of [NSRunningApplication activateWithOptions:NSApplicationActivateAllWindows].
I have tried wrapping the call to [NSRunningApplication activateWithOptions:] within dispatch_async, I have also tried using an operation queue from within the EventTap, neither of which solves the problem. Finally, I have tried sending a notification and calling [NSRunningApplication activateWithOptions:] from within the notification callback, which also fails. This is the code in my event tap:
case kCGEventLeftMouseDown:
if (cgClickCount == 1) {
NSNumber *pidNumber = [NSNumber numberWithLong:actualPid];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:pidNumber, #"pidNumber", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"DockApplicationClickedNotification" object:self userInfo:userInfo];
return NULL; /* swallows event */
}
break;
Any assistance is greatly appreciated! A debug screen grab is attached that shows how the 1st attempt to activate an app by clicking its dock icon is successfully, and how subsequent clicks fail to activate the app.
UPDATE and half-solved:
I have determined why [NSRunningApplication activateWithOptions:] works on the 1st attempt and fails on 2nd and subsequent attempts. The first time I click on an application icon in the dock, my application is the active app. On subsequent clicks on an app icon, some other application is active. So the problem here seems to be that [NSRunningApplication activateWithOptions:] will only work if my application is the frontmost process.
If I add [NSApp activateIgnoringOtherApps:YES]; before the call to [NSRunningApplication activateWithOptions:], it consistently works as intended, however, there is a menubar flicker due to activating my app only to then activate a different app. So the question becomes:
Is there any way to get [NSRunningApplication activateWithOptions:] to work when my application is not the frontmost app? and is activateWithOptions: supposed to work this way?
I'm writing a Cocoa app that needs to be able to capture keyboard events even when not focused. (It's controlling another app via the Apple Scripting Bridge).
I have tried the solution here: OSX: Detect system-wide keyDown events?
It compiles fine, but doesn't actually do anything. I'm putting the code in my init method.
I also can't get CGEventTap to work either. Any suggestions?
Here's my code:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSEvent addGlobalMonitorForEventsMatchingMask:(NSKeyDownMask) handler:^(NSEvent *event){
NSLog(#"test");
}];
}
Also, I'm aware that assistive devices needs turned on. Unfortunately when I go into the settings it only lists specific apps. Mine isn't one of them.
Use AXIsProcessTrustedWithOptions to request access. Then you'll show up in System Preferences.
I'm trying out chromium-tabs. I have an issue where the icon of a tab never gets properly updated after it gets created for the first time. In my CTTabContents subclass, I have:
- (void)tabDidBecomeSelected {
NSLog(#"selected");
[self setIcon:[NSImage imageNamed:#"default"]];
}
- (void)tabDidResignSelected {
NSLog(#"resign selected");
[self setIcon:[NSImage imageNamed:#"notification"]];
}
This should change the icon if the tab resigns its selected status to a different one. But it doesn't. The icon never changes. Note that I've tried the same exact calls in (id)initWithBaseTabContents:(CTTabContents *)baseContents andJid:(NSString *)jid andStatus:(NSString *)status where they work fine, so the calls fail only on an update of the icon later.
I've also made sure the functions are getting called (I see the log statements). What's the problem here? Also, is this the fork that Chrome actually uses? It obviously works in Chrome, which is strange... Am I doing something wrong?
I even tried doing [[[self.browser.windowController window] contentView] setNeedsDisplay:YES]; in the tabDidBecomeSelected functions, to force the whole window to redraw, in case their code for updating the icon fails, but still no luck.
I want to make a windowless application. The problem is that I'm using a framework that shows some alert boxes sometimes, and I'm not able to suppress them (at least not without a crash).
I've set LSBackgroundOnly to 1 (in the info.plist app file), but this doesn't seem to work. Any chance I'm missing something here (maybe some other settings that I need to set)?
I've also tried creating a category for NSWindow:
Overwritten alloc and allocWithZone: so that no window gets created. This works on some situations, but starting a modal session throws exception (because sending a nil parameter to beginModalSessionForWindow:).
Tried overwriting NSApplication's beginModalSessionForWindow: and returned nil everytime, but this leads to EXC_BADACCESS somewhere in the framework (runModalSession: and endModalSession: were also overwritten, but the crash is before any of them being called).
Any other ideas will be welcome.
In case it helps, the framework that I'm using is Twain.Framework, so if instead anyone knows a way to block all UI from twain (this includes error alerts shown when a device is not connected) it would be great if you share.
It's not clear what you're hoping for. Are you hoping for an app that doesn't normally display windows but does allow the third-party framework to show its alerts? Or are you hoping to find a way to prevent the framework from showing its alerts so your app absolutely never has any windows?
If it's the former, you're probably looking for LSUIElement. That's an app which can have some UI elements, but doesn't show in the Dock or the Command-Tab application switcher and doesn't have a menu bar.
I managed to make it 'windowless' (some windows are still shown, but at least they're not visible, and they're automatically closed). I only handled modal windows, since these where shown in my situation.
I made a category for NSWindow, so that all windows are invisible, and can't become key or main windows:
-(BOOL)canBecomeKeyWindow{
[self setOpaque:NO];
self.alphaValue = 0;
return NO;
}
-(BOOL)canBecomeMainWindow{
[self setOpaque:NO];
self.alphaValue = 0;
return NO;
}
Subclassed NSApplication:
-(NSInteger)runModalForWindow:(NSWindow *)aWindow{
return NSCancelButton;
}
-(NSModalSession)beginModalSessionForWindow:(NSWindow *)aWindow{
NSModalSession session = [super beginModalSessionForWindow:aWindow];
[aWindow performSelector:#selector(close) withObject:nil afterDelay:1];
return session;
}
However, this didn't help much. In case of runModalForWindow: everything was good, since the owner of the window received a response. In case of beginModalSessionForWindow: the application got stuck, most probably because the window's owner was waiting for a specific event (e.g. button click) which it never received.
Here's my situation:
I've written a simple web browser. Tabbed browsing was easy enough to get working once I wrapped my head around the concepts and figured how to perform operations on specific tabs. It works well and is pretty reliable under most circumstances.
A problem has plagued me, however, and I cannot figure out its cause.
Let's say I open a new tab and navigate to YouTube. I click on a video and the flash player loads. The video plays and all works fine. I now create another new tab and navigate to some site. The audio from the youtube player stops completely.
When I switch back to the youtube tab, the page will all still be there just as it was except the player has to reload completely, as if I had just reloaded the page. This seems to apply to other plugin types as well.
What's causing this?
Garbage collection is not enabled and as far as I know I'm creating the web views properly. Is there some silly, simple little thing that I missed somewhere along the line?
The - (void)setHostWindow:(NSWindow *)hostWindow method on WebView is probably what you're looking for.
I had the same problem with the flash in a WebView reloading whenever the syle mask of the enclosing window was changed. Wrapping the call to setStyleMask fixed the problem, as follows:
NSWindow *hostWindow = [[NSWindow alloc] init];
[self.webView setHostWindow:hostWindow];
[[self windowForSheet] setStyleMask:styleMask];
[self.webView setHostWindow:nil];
[hostWindow release];
The documentation for the method isn't stellar, but it does explicitly state a having a WebView inside a NSTabView as one of the use cases:
This method sets the receiver’s host window to hostWindow. Your application should only use this method if a web view is going to be removed from its window temporarily, and you want the web view to continue operating (for example, you don’t want to interrupt a load in progress). Since the receiver retains hostWindow, it is your responsibility to set the host window to nil before closing the window to avoid a retain loop.
For example, you might invoke this method if you attach a web view to an NSTabView object (as in a tabbed browser implementation). The NSTabView object takes views out of the window when they are not in the active tab, so you need to invoke this method before the web view is removed from its window. If you don't invoke this method, plug-ins will stop operating when the web view is removed from its window.
I had a similar problem but with a window with a webView that is closed and restored. Unfortunately the solution by #mlwelles did not solve the problem alone.
What did solve however is removing the webView from the window before it closes (proper "timing" is important). What I came up with is something like this:
id contentView;
id tmpHostWindow;
[window setDelegate:self];
- (BOOL)windowShouldClose:(NSNotification *)notification
{
// set temporary hostWindow on WebView and remove it from
// the closed window to prevent stopping flash plugin
// (windowWillClose would be better but that doesn't always work)
tmpHostWindow = [[NSWindow alloc] init];
[webView setHostWindow:tmpHostWindow];
[window setContentView:nil];
[contentView removeFromSuperview];
return TRUE;
}
- (void)windowDidBecomeKey:(NSNotification *)notification
{
// restore "hidden" webview
// (would be better to do it in applicationShouldHandleReopen
// but that seems to be too early (has no effect)
if ([window contentView] != contentView) {
[window setContentView:contentView];
[webView setHostWindow:nil];
tmpHostWindow = nil;
}
}