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?
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.