Change mouse cursor over inactive NSWindow

前端 未结 3 1082
醉梦人生
醉梦人生 2020-12-16 06:02

I have subclassed NSWindow and I have a MYWindow class implementing the following method:

-(void)resetCursorRects {
    NSImage *image = [NSImage imageNamed:         


        
相关标签:
3条回答
  • 2020-12-16 06:15

    Now I finally found a solution that works. I don't know if this will bite me in the tail in the future but at least this seem to work when testing.

    Thanks Wil for the example it got me half way there. But it was only when I finally combined it with resetCursorRects and also defined a cursor rect in each view with the specific cursor. This took me a long time to figure out and I don't know if the solution is optimal (suggestions of improvement are welcome)

    Below is the full example that made it work for me in the end (self.cursor is an instance of the 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];
    }
    
    0 讨论(0)
  • 2020-12-16 06:19

    You should be able to add an NSTrackingArea that changes the cursor, as long as you don’t want it to also change when the app is inactive (that is essentially impossible).


    Edit:

    I was able to get this working with the following code:

    - (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];
    }
    
    0 讨论(0)
  • 2020-12-16 06:29

    I struggled with this problem for a long period of time and I think there is only one way to change mouse cursor over inactive application (over non-foreground window). This is hacky and magic way.

    Before calling pretty standard:

    [[NSCursor pointingHandCursor] push];
    

    You have 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 are using 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)
    
    0 讨论(0)
提交回复
热议问题