Adventures in TextInputCanvas : 8

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 its still necessary.


Where exactly is that setting? I can’t seem to find it. I’m noticing that the flyout only shows occasionally here when I press and hold a character. (Same issue as quoting perhaps?)

see the last note in that post
its actually a terminal command to toggle this

defaults write -g ApplePressAndHoldEnabled -bool false

or you can set this on a per application basis

Off this list I’ve been asked

Can you clarify your TIC number 8 post? You don’t mention which events the TextRange code is for…

TextRange is mostly used for things like the services menu where hyou might have "Look up with "

On a right click on a selection you would first see the SelectedRange event raised
If you return a non-nil range you would next see the TextForRaqnge event raised and if you return a non-empty string then the value returned can/will be used in calls to the various services that are presented

1 Like

Would be very cool @npalardy, if you could attache the sample for each TextInputCanvas Tutorial Part, because sometimes small things missing in your step by step tutorial.

Great work, looking forward for the next parts.

Its buried inside a larger project so that might not be possible
I’ll see what I can do

1 Like