objective-cpointersinput-method-kit

NSPoint and IMKCandidate Window Placement


I am using the inputmethodkit and trying to place a window underneath some text.

_currentClient is an IMKTextInput instance

candidates is an IMKCandidates instance

// Get the current location to place the window
NSRect tempRect = NSMakeRect(0, 0, 0, 0);
NSDictionary* clientData = [_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&tempRect];
NSPoint* windowInsertionPoint = (NSPoint*)[clientData objectForKey:@"IMKBaseline"];
...
[candidates setCandidateFrameTopLeft:*windowInsertionPoint];
[candidates showCandidates];

Now, I know that the windowInsertionPoint variable is fine, when I debug I can see it's value, eg: NSPoint: {647,365}

However when I use this, the candidate window just shows in the bottom left corner of the screen. I haven't worked with screen placement of stuff before, so help is appreciated.

If I pass in arbitrary static values to setCandidateFrameTopLeft, it gets placed in the screen. The following works:

[candidates setCandidateFrameTopLeft:NSMakePoint(401, 354)];

Is it a pointer problem?


Solution

  • OK, the solution to this is that I am an idiot. Here is the code you need:

    NSRect tempRect;
    NSDictionary* clientData = [_currentClient attributesForCharacterIndex:0 lineHeightRectangle:&tempRect];
    NSPoint windowInsertionPoint = NSMakePoint(NSMinX(tempRect), NSMinY(tempRect));
    

    The documentation for IMKTextInput attributesForCharacterIndex says

    lineRect: On return, a rectangle that frames a one-pixel wide rectangle with the height of the line. This rectangle is oriented the same way the line is oriented.

    This means it returns an NSRect into the variable your passed it for the lineHeightRectangle value. The important point is that the location of that NSRect is the location of the character you are searching for. So, then you need to just make a point from that rectangle and use NSMinY for the Y value. The rectangle is only a single pixel wide so Min/Max for X are basically the same.