Sorry for the delay folks
Work. Earning a living. Family.
And SNOW !!! (yeah SNOW !!!) So my days will get filled up with things related
to being part of the Canadian Ski Patrol
One of the reasons to use the Text Input Canvas is to get proper text input handling
Something that really cant be done in a text area
But to get the input options (like press & hold to then see the popup of optional
character forms like ü and others, we need to respond to the text input system with
values that make sense to it
One of the first things we need to deal with is “Incomplete Text Ranges”
What exactly is a TextRange ?
It is actually very simple - a starting position, and a length. Nothing more.
But what is meant by an “incomplete text range” ?
In Cocoa terms this is marked text and can be a temporary
string displayed in the text during composition of the final input and is
not actually part of the content until it has been committed (via InsertText).
For international input, like the alternative form selector popup, the incomplete
text is whatever character was pressed and held down long enough for the OS to see
you wanted to see the popup. This might be something like the u, a, e i, or o which
all have alternative forms
So, for now we’re going to return a TextRage that is the the position of the last character
added and 1 character long. This would mean the last char typed forms the entire incomplete text range_
And once you do this you should, if you press the u key and hold it, see the popup show
up somewhere on your screen. It will be badly positioned and we’ll take care of that next
That code is simply
Return New TextRange(mInsertionPosition-1, 1)
Also as part of now having responded with a valid non-nil text range we should see in the debug logs
additional requests from the text input system to our control for the selected range as well as
requests for the rect for frange
Again this is the text input system asking us for details about how we position and draw things so it
at least knows where to position the popup
For now, since we do not have selections implemented we can set selected range to be the current
position that is 0 characters long
That code is simply
Return New TextRange(mInsertionPosition, 0)
The request for the RectForRange though we need to respond with a decently accurate rect otherwise
the system cant place the popup correctly
Since we previously added the PositionToLineColumn and LineColumnToXy methods this should be simple.
So first we need to convert the the current integer position into a line and column
Then e need to get the X Y position of that line & column given the current font settings etc
And the return the rect that would surround the range of text we were given
Dim pos As RealBasic.Point
// get the position as a line & column #
pos = PositionToLineAndColumn( range.Location )
Dim p As Picture = Self.TrueWindow.BitmapForCaching(10, 10)
p.Graphics.ForeColor = Self.TextColor
p.Graphics.TextFont = Self.TextFont
p.Graphics.TextUnit = CType(Self.TextUnit, REALbasic.FontUnits)
p.Graphics.TextSize = Self.TextSize
p.Graphics.Underline = Self.Underline
p.Graphics.Bold = Self.Bold
p.Graphics.Italic = Self.Italic
// get the x (left) edge and (y) baseline for the position
Dim position As REAlbasic.point = LineColumnToXY(p.Graphics, pos.X, pos.Y)
// now computer the rectangle
Dim width As Double = p.Graphics.StringWidth( Mid(mTextBuffer, range.Location, range.Length) )
Dim top As Double = position.Y - p.Graphics.TextAscent
Dim rangeRect As New REALbasic.Rect(position.x, top, width, p.Graphics.TextHeight)
Return rangeRect
And now that we have done this when we press & hold the u key on macOS the selection popup will appear in the right place.
- for those of you paying attention yes this is the same picture as before
*On macOS if you have your keyboard preferences set to show the keyboard alternates. That is the default but if you’ve turned this off then all this work isnt something you’ll notice. But it’s still necessary.