Changing the mouse pointer over an inactive NSWindow

I have subclassed NSWindow, and I have a MYWindow class that implements the following method:

-(void)resetCursorRects {
    NSImage *image = [NSImage imageNamed:@"cursor.png"];
    [image setSize:NSMakeSize(32, 32)];
    NSCursor *cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(1, 1)];
    [super resetCursorRects];    
    [self addCursorRect:[self bounds] cursor:cursor];
}

This will change the cursor for the whole window, and I will see cursor.png instead of the default mouse pointer. The problem is that this only works if MYWindow is installed in the key window, which, of course, is not trivial to create it.

At the beginning of my project, I have only one main window, but now I need to have two different MYWindow. The problem with two windows cannot be set as a key window, and therefore, the user mouse pointer appears only in the active window. I need to click another window to display the cursor.

Is there any way around this? So, do I get a custom cursor in both windows?

Edit: tried NSTrackingArea

:

self.trackingArea = [[NSTrackingArea alloc] initWithRect:[self frame] options: (NSTrackingCursorUpdate | NSTrackingActiveAlways | NSTrackingMouseMoved) owner:self userInfo:nil];
[self addTrackingArea:self.trackingArea];

cursorUpdate: :

-(void)cursorUpdate:(NSEvent *)event {
    NSLog(@"event : %@", event);
    [[NSCursor crosshairCursor] set];
}

crosshairCursor, NSWindow, NSImageView, . NSWindow , . - ?

+4
3

, . , , .

Wil , . , , , resetCursorRects, . , , ( )

, (self.cursor - )

- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
    NSTrackingArea *const trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options:(NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil];
    [self addTrackingArea:trackingArea];
    [self.window invalidateCursorRectsForView:self];
}

- (void)resetCursorRects {
    [super resetCursorRects];
    [self addCursorRect:self.bounds cursor:self.cursor];
}

- (void)mouseEntered:(NSEvent *)theEvent {
    [super mouseEntered:theEvent];
    [self.cursor push];
}

- (void)mouseExited:(NSEvent *)theEvent {
    [super mouseExited:theEvent];
    [self.cursor pop];
}
+2

NSTrackingArea, , , , ( ).


Edit:

:

- (vod)someSetup;
{
    NSTrackingArea *const trackingArea = [[NSTrackingArea alloc] initWithRect:NSZeroRect options: (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingInVisibleRect) owner:self userInfo:nil];
    [self.view addTrackingArea:trackingArea];
}

- (void)mouseEntered:(NSEvent *)theEvent;
{
    [[NSCursor IBeamCursor] push];
}

- (void)mouseExited:(NSEvent *)theEvent;
{
    [[NSCursor IBeamCursor] pop];
}
+4

I have been struggling with this problem for a long period of time, and I think there is only one way to change the mouse cursor to an inactive application (above a window without a foreground). This is a hacker and magic way.

Before calling pretty standard:

[[NSCursor pointingHandCursor] push];

You need to call:

void CGSSetConnectionProperty(int, int, int, int);
int CGSCreateCString(char *);
int CGSCreateBoolean(BOOL);
int _CGSDefaultConnection();
void CGSReleaseObj(int);
int propertyString, boolVal;

propertyString = CGSCreateCString("SetsCursorInBackground");
boolVal = CGSCreateBoolean(TRUE);
CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, boolVal);
CGSReleaseObj(propertyString);
CGSReleaseObj(boolVal);

Or if you use Swift:

Put this in your YourApp-Bridging-Header.h:

typedef int CGSConnectionID;
CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value);
int _CGSDefaultConnection();

And then call:

let propertyString = CFStringCreateWithCString(kCFAllocatorDefault, "SetsCursorInBackground", 0)
CGSSetConnectionProperty(_CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue)
+3
source

Source: https://habr.com/ru/post/1525973/


All Articles