Understanding Text Input and the Text Services Manager

This document presents the information needed to appropriately handle keyboard input in Carbon, to create Carbon text service components for Mac OS X, and to revise Carbon client applications of text services. It discusses keyboard input, Carbon text input events, Unicode input, and the changes to the Text Services Manager (“TSM”), in the context of Carbon and Mac OS X.

If you have a Carbon program that uses text services or if you are interested in handling raw keyboard events (that is, if you must do key filtering or key input validation), you should read the sections What’s New for Applications With TSM and Text Input in Carbon and Text Input Event Handling for Applications With Carbon.

If you have a text service component, see What’s New for Text Service Components With TSM and Text Input in Carbon and Event Handling for Text Service Components With Carbon.

This document assumes some prior knowledge of the Text Services Manager, text input, and keyboard events on the Mac OS. If you would like background information, please see the following sources:

What’s New for Applications With TSM and Text Input in Carbon

Adapting your application for Carbon is not mandatory, but it is recommended, both for increased compatibility with text services and for the enhanced performance of your program. As you read through this section, you may find that the changes discussed below simplify your use of the Text Services Manager and/or your handling of text input.

If your program directly handles keyboard input, you can read the list that follows for highlights of the changes in handling text input with Carbon.

If your application currently supports the Text Services Manager, the following list provides an overview and checklist for revising your application for the Text Services Manager in Carbon. If your application does not currently support the Text Services Manager, the list supplements the information given in the Text Services Manager chapter of Inside Macintosh: Text.

Text Input Event Handling for Applications With Carbon

The Text Services Manager and text service components use text input events to give information to and request specific actions of client applications. Supporting full Unicode input and having inline input in your application depends on your installing handlers for these events. If your application does not handle text input events, the Text Services Manager automatically provides support only for partial Unicode input, via a floating or “bottomline” input window.

The following sections describe the various aspects of text input event handling for Carbon applications:

Carbon Text Input Events and Apple Events

Prior to Carbon, applications received text input events in the form of Apple events. With Carbon, the Text Services Manager now also provides Carbon text input events to applications. Supporting Carbon text input events is optional, but highly recommended. The performance advantages of using Carbon events over Apple events are significant. In addition, unlike Apple events, which are always targeted at the application level, Carbon events also can be targeted at the level of a window or even a control. If you have an existing Text Services Manager client application, revising it to use Carbon events is made simpler by the fact that it can be done piecemeal—you can change one, some, or all of its existing Apple event handlers at any time. Table 2-1 presents the Carbon text input events and notes the Apple events to which they correspond. (For a detailed description of the Carbon text input events, see the CarbonLib Universal Interfaces file CarbonEvents.h.)

Table 1-1  Text input events

Event description

Comments

Carbon event—kEventClassTextInput

Apple event—kTextServiceClass

Create or update text in an active input area

Must be supported for inline input

kEventTextInput UpdateActiveInputArea

kUpdateActive InputArea

Receive Unicode text generated from a keyboard layout or via the TSM bottomline input window

kEventTextInput UnicodeForKeyEvent

kUnicodeNotFrom InputMethod

Help position items on the screen by converting a byte offset in characters in the active input area to global coordinates

Supporting this event is recommended even for those applications that do not use inline input; to do so, provide a handler to this event that simply returns the position of the insertion point when the requested offset is 0

kEventTextInput OffsetToPos

kOffset2Pos

Help track cursor movements by converting global coordinates to a byte offset in characters in the active input area

kEventTextInputPosTo Offset

kPos2Offset

Show or hide a floating input window

Most applications do not need to support this event; this event must be supported only by applications that provide their own bottomline input window

kEventTextInputShow HideBottomWindow

kShowHideInput Window

Return the current text selection or the text on either side of the current insertion point

kEventTextInput GetSelectedText

kGetSelected Text

The kEventTextInputUnicodeForKeyEvent event, by its very nature, always contains Unicode. For other Carbon text input events that contain text, a client application informs the Text Services Manager of what kind of encoding to use for these events when the application creates a new TSM document and specifies its desired interface type(s). For example, an application can request that its text be delivered in the Unicode encoding by creating a TSM document with the kUnicodeDocument signature.

Text Input Event Routing

The Text Services Manager mediates the routing of text input events. In the case of text service–generated events, the component calls the Text Services Manager function SendTextInputEvent to initiate the routing of the event. Then, the Text Services Manager delivers the event in the appropriate form for your application.

In general, the Text Services Manager tries to route events in their most optimal form. In Mac OS X, since Carbon events are more efficient than Apple events, the Text Services Manager first attempts to pass a text input event to an application as a Carbon event. The Text Services Manager routes Carbon text input events to the current user focus—typically a control, window, or application.

If the Carbon text input event is not handled, typically the Text Services Manager then generates the Apple event that corresponds to the unhandled Carbon event and sends that. And, if neither the Carbon text input event nor the corresponding Apple event is handled, then typically the event simply remains unhandled. An exception to these rules is the event kEventTextInputUnicodeForKeyEvent; see Handling Unicode and Keyboard Input in Carbon for more details.

Handling Unicode and Keyboard Input in Carbon

To receive text input, applications must support the two keyboard-related text input events. The first, the kEventTextInputUpdateActiveInputArea Carbon event (or the Apple event kUpdateActiveInputArea), delivers text to your application that is generated by an input method in an inline input session. The second, the kEventTextInputUnicodeForKeyEvent Carbon event (or the Apple event kUnicodeNotFromInputMethod), delivers text to your application that is derived from a keyboard layout or via the Text Services Manager’s bottomline window. Especially if you want your client application to always receive Unicode characters, your application should handle the kEventTextInputUnicodeForKeyEvent text input event.

In order to avoid interference with input methods, providing a handler for the kEventTextInputUnicodeForKeyEvent event and examining its parameters is the preferred means on Carbon for directly examining keyboard input in general. Even if your application doesn’t support Unicode, it can still examine the kEventTextInputUnicodeForKeyEvent event’s parameters and extract Mac character codes, when they exist.

Only in special cases, such as if an application handles individual key presses or performs its own keyboard translation, might the application need to obtain a keyboard event prior to the event being processed by the Text Services Manager. In these cases, in Carbon you can obtain such events by installing Carbon event handlers for raw keyboard events. The Carbon Event Manager then dispatches the event to the application before it is sent to the Text Services Manager.

The Text Services Manager sends the kEventTextInputUnicodeForKeyEvent event to deliver Unicode text when the input source is either a keyboard layout or a text service via the Text Services Manager’s bottomline input window. Unlike other Carbon text input events, in the case of kEventTextInputUnicodeForKeyEvent the Text Services Manager falls back to sending the corresponding Apple event only if the application specifically requests Unicode (by creating a TSM document that has the kUnicodeDocument signature). So, if the application has requested Unicode, but it does not handle the kEventTextInputUnicodeForKeyEvent event, only then does the Text Services Manager convert the event to a kUnicodeNotFromInputMethod Apple event. Finally, if the application does not handle the kUnicodeNotFromInputMethod Apple event, then the Text Services Manager attempts to produce a stream of “classic” events, which the application can handle in its WaitNextEvent loop.

For more information on Unicode input, as of Mac OS 8.5, see Inside Macintosh: Supporting Unicode Input at http://developer.apple.com/documentation/Carbon/Conceptual/Supporting_Unicode_Input/index.html.

What’s New for Text Service Components With TSM and Text Input in Carbon

With Mac OS X, text service components must be Carbon clients. (This is in contrast to Mac OS 8 and 9, where text service components cannot be Carbon clients, due to the potentially destabilizing effects of a component loading Carbon in the context of a non-Carbon application.) To help you in creating a Mac OS X–ready component, the following list provides a brief overview of the changes required:

Event Handling for Text Service Components With Carbon

Unlike client applications, text service components both send and receive events. Text service components, via the Text Services Manager, send text input events to give information to and request specific actions of client applications. The component calls the Text Services Manager function SendTextInputEvent to initiate the routing of the event, which is delivered by the Text Services Manager in the form appropriate for the application. (Note that the sending of Apple events and the use of the pre-Carbon function SendAEFromTSMComponent is discouraged on Mac OS X.) For more information on text input events, see Text Input Event Handling for Applications With Carbon.

A text service component also receives certain events targeted at the current user focus from the Text Services Manager, which it intercepts on the component’s behalf. These events are of two types: keyboard events and mouse events that intersect an inline input session’s region. The Text Service Manager routes these events to the active input method and to any other text services associated with the active TSM document through calls to the function TextServiceEventRef. For a more detailed discussion of the TextServiceEventRef function and the SendTextInputEvent function, see Inside Carbon: Text Services Manager Reference.

The Text Services Manager works on behalf of components to intercept keyboard events (these are Carbon events of class kEventClassKeyboard) in two passes. First, the Text Services Manager intercepts the raw keyboard event and uses a keyboard-layout resource to translate the keypress into character data. The Text Services Manager stores the keyboard translation information in the keyboard event and dispatches it to the current user focus—such as a window, menu, or control. Then, if the event is not handled, the Text Services Manager sends the event to the text service component.

In addition to keyboard events, the Text Services Manager intercepts mouse events for routing to components. The Text Services Manager directly passes any mouse-click events (kEventMouseDown, kEventMouseUp, kEventMouseDragged) that intersect an inline input session’s region to the active component(s).

The Text Services Manager also intercepts mouse-moved events, however it does not pass them along in a direct form to components, as it does with mouse-click events. The Text Services Manager promotes kEventMouseMoved events, after the applicable control or window receives them, to the window-specific kEventWindowCursorChange event. Next, the Text Services Manager delivers the kEventWindowCursorChange event to the active input method, then, if it is not handled, to any other active text services. If the event is still not handled, the Text Services Manager finally passes the event to the current user focus. This event-dispatching process gives applications that need to see the low-level mouse-moved events a chance to see these events first, while providing a mechanism for text services and applications to act on these events without conflict. After completing this process, the Carbon Event Manager converts any kEventWindowCursorChange event that remains unhandled to a “classic” mouse-moved event for WaitNextEvent clients.