Important: The information in this document is obsolete and should not be used for new development.
Calling the Text Services Manager
The application interface to the Text Services Manager consists of application-level calls that your client application uses to send information to text service components by way of the Text Services Manager. They are documented in detail under "Text Services Manager Routines for Client Applications" on page 7-48. The Text Services Manager maps many of those calls to equivalent component-level calls to text service components. Those text service component routines are described under "Text Service Component Routines" on page 7-84.This section describes how your client application can use the application interface to the Text Services Manager to
- prepare for communication with the Text Services Manager
- create an internal record called a TSM document
- make text services other than text input available to the user
- activate and deactivate a TSM document
- give text service components a chance to handle events, respond to menu selections, and set the shape of the cursor
- explicitly confirm text within the active input area
- terminate communication with the Text Services Manager
Initializing as a TSM-Aware Application
If your client application plans to use any of the Text Services Manager application-interface routines, it must callInitTSMAwareApplication
at startup, immediately after calling the rest of the Toolbox initialization routines. See Listing 7-1.Listing 7-1 Initializing as a TSM-aware application
FUNCTION Initialize: OSErr; VAR myErr: OSErr; BEGIN InitGraf(@thePort); InitFonts; InitWindows; InitMenus; TEInit; InitDialogs(NIL); InitCursor; IF (InitTSMAwareApplication = noErr) THEN Initialize := DoNew; {application routine that } { creates window & TSM document} END;The Text Services Manager records the fact that your client application is TSM-aware, and allocates any private data storage as necessary.Creating a TSM Document
Your client application needs to create an internal record called a TSM document (defined by theTSMDocument
data type) before it can use any services provided through the Text Services Manager. A TSM document is a private data structure that is associated with each of your application's documents that use a text service. You cannot access the TSM document record directly. You call theNewTSMDocument
function to instruct the Text Services Manager to create the TSM document. The Text Services Manager returns a TSM document ID, an identifier that you supply in subsequent calls to the Text Services Manager.Typically, you create a TSM document for each window that your application uses. Use the
supportedInterfaceTypes
array to indicate which text service interfaces you support. Currently only one interface is defined--'tsvc'
, the component type for text services components. Pass any data you like in therefcon
parameter to the call. The Text Services Manager returns therefcon
value in thekeyAETSMDocumentRefcon
parameter of any Apple event sent to your application. You can then use therefcon
value to determine which TSM document and window the Apple event belongs to.Listing 7-2 shows the sample application's
DoNew
function, which is called from the initialization routine presented in Listing 7-1. The call toNewTSMDocument
specifies that the application supports one interface type (kTextService
).NewTSMDocument
opens the default input method for the current keyboard script, assigns it to this document, and returns the TSM document ID in theidocID
parameter. The routine makes use of a modified window record (typeMyWindowRecord
) that is a standard window record with an additional field for holding the TSM document ID.Listing 7-2 Creating a new TSM document and associating it with a window
FUNCTION DoNew: OSErr; VAR wRecordPtr: myWindowPtr; window: WindowPtr; supportedTypes: InterfaceTypeList; myErr: OSErr; BEGIN supportedTypes[0] := kTextService; {allocate storage for window record} wRecordPtr := myWindowPtr(NewPtr(sizeof(myWindowRecord))); IF wRecordPtr <> NIL THEN BEGIN IF gColorQDAvailable THEN window := GetNewCWindow(kWINDResID, Ptr(wRecordPtr), WindowPtr(-1)) ELSE window := GetNewWindow(kWINDResID, Ptr(wRecordPtr), WindowPtr(-1)); IF window = NIL THEN {couldn't get window} BEGIN DisposePtr(Ptr(wRecordPtr)); {clean up} DoNew := kWindowFailed; Exit(DoNew); END; myErr := NewTSMDocument(1, supportedTypes, wRecordPtr^.idocID, LongInt(wRecordPtr)); END; {do other window intialization, like creating scroll bars} DoNew := myErr; END;Making Text Services Available to the User
Text services that are input methods are always displayed in the keyboard menu. System software takes care of that; your application does not need to list input methods. However, your application may wish to provide a menu or scrolling list to display other types of available text services. (Note that, currently, no text services other than input methods are available. This capability is provided for future extensibility.)To obtain a list of the available text services on the user's system, call the
GetServiceList
function. You pass it an array of interface types (to indicate the types of services you want returned in the list) and a pointer to a data structure (to hold the list). The function returns the number of available components, and a name and component identifier for each one.Because text service components can be registered or unregistered at any time, your client application should periodically call either
GetServiceList
or the Component Manager functionGetComponentListModSeed
to see if the list of registered text service components may have changed.
The Text Services Manager automatically opens input methods; your client application does not have to open them. You do have to explicitly open all other types of text services, however. If the user chooses a text service from a menu or list that you have displayed, you need to open that text service.
- IMPORTANT
- If your client application displays a list or menu of text service components, do not show input methods. They are already displayed in the Keyboard menu. To show them in two places would be confusing to users.
You call the
OpenTextService
function to associate the text service component with the current TSM document.OpenTextService
then returns a valid component instance to indicate that the text service component has been opened and initialized.Whenever a user wishes to close a text service component that you have opened, call the
CloseTextService
function.Activating and Deactivating a TSM Document
To notify the Text Services Manager that a window in your client application associated with a TSM document has been activated, and that you are ready to use a text service component, use theActivateTSMDocument
function.Listing 7-3 shows how to handle activating and deactivating a TSM document. You specify the document using the ID assigned to it when it was created (with the
NewTSMDocument
function). This routine, like the previous samples, assumes that the application has an extended window record with a field,idocID
, that contains the TSM document ID.Listing 7-3 Activating and deactivating a TSM document
PROCEDURE DoActivate(window: WindowPtr; becomingActive: Boolean); VAR myErr: OSErr; BEGIN IF becomingActive THEN myErr := ActivateTSMDocument(MyWindowPtr(window)^.idocID) ELSE myErr := DeactivateTSMDocument(MyWindowPtr(window)^.idocID); END;When the Text Services Manager receives an ActivateTSMDocument call, it deactivates the currently active TSM document (if it hasn't already been explicitly deactivated) and stores the new document as the currently active TSM document. If the specified text service component for the document has a menu, the Text Services Manager inserts the menu into the menu bar as an application or system menu.When a window in your client application associated with a TSM document has been deactivated, you should call the
DeactivateTSMDocument
function. The Text Services Manager in turn calls the text service component functionDeactivateTextService
for any text service components associated with the TSM document being deactivated.Input-method text services are handled in a special way: the identity of the input method of the deactivated document is retained by the Text Services Manager, and compared with the input method used by the next activated document. If the newly active document uses the same input method, the Text Services Manager will simply activate the new instance of the same input method. If the documents use different input methods, the previous input method is then closed, and any windows belonging to it are closed and menus are removed. The new input method is then activated. Not closing an input method until it is actually unneeded avoids extra removal and immediate redisplay of input method palettes and menus.
Passing Events, Menu Selections, and Cursor Setting
Whenever your client application receives an event from the Event Manager functionWaitNextEvent
, you need to give each text service component an opportunity to handle that event, if appropriate. Use theTSMEvent
function to let the Text Services Manager dispatch the events to the correct text service component. You provide a pointer to the event record containing the event. The Text Services Manager passes the event in turn to each component associated with the currently active TSM document, starting with input methods. If the event is handled by a component,TSMEvent
returnsTRUE
and the event is changed to a null event. If the event is not handled,TSMEvent
returnsFALSE
and you are responsible for handling the event.Listing 7-4 is a partial example of an event handler in which the application passes events to the Text Services Manager for routing to text service components. If no text service component handles an event, the application handles it. The global variable
gUsingTSM
isTRUE
if the Text Services Manager is present and the application is making use of it.Listing 7-4 Passing events to a text service component
PROCEDURE MyDoEvent(event: eventRecord); VAR handledByTS: Boolean; gotEvent: Boolean; BEGIN WHILE TRUE DO BEGIN IF gHasWaitNextEvent THEN BEGIN gotEvent := WaitNextEvent(everyEvent, event, kSleep, NIL); handledByTS := FALSE; IF (gUsingTSM AND gotEvent) THEN handledByTS := TSMEvent(event); END; IF gotEvent AND (NOT handledByTS) THEN {process event in normal way} ; END; END;Whenever a user chooses a menu item, it may be from a text service component's menu; your application must therefore give the text service component a chance to respond. (This situation occurs only with text service components that are not input methods.) To do this, use theTSMMenuSelect
function with the result from the Menu Manager functionMenuSelect
in themenuResult
parameter. IfTSMMenuSelect
returnsTRUE
, then the text service component has handled the menu selection, so your client application does not need to do so. However, your application is still responsible for removing the highlighting from the menu title after the selection has been handled.Your client application is generally responsible for setting the cursor to an appropriate shape. However, the text service component may have its own cursor requirements when the cursor is within the boundaries of its windows or palettes. To allow a text service component to set the cursor, use the SetTSMCursor function. Call it whenever you would normally set the cursor yourself. If
SetTSMCursor
returnsTRUE
, the cursor is either on a text service component window or on the active input area and a text service component has set the cursor. In this case, you should not set the cursor.Confirming Active Text Within a TSM Document
Normally, an input method text service component ejects finished input from the active input area continually as it processes user events, sending the confirmed text to your application with the Update Active Input Area Apple event.Circumstances may arise in which you need to confirm input in progress before the text service component ejects it (that is, before the user presses Return). If, for example, the user clicks the mouse in text outside the active input area, that constitutes an implicit user acceptance of the text in the active input area. You should explicitly terminate any active input and save the text that is in the active input area by calling the
FixTSMDocument
function. The text service component sends the confirmed text to your application and empties the active input area.Listing 7-5 shows what happens when the user clicks the go-away box of the active document window after entering some text in the active input area. The global variable
gIDocID
represents the ID of the active TSM document.Listing 7-5 Confirming text in an active input area
PROCEDURE DoMouseDown (event: EventRecord); VAR part: Integer; theWindow: WindowPtr; myErr: OSErr; BEGIN part := FindWindow(event.where, theWindow); CASE part OF inContent: DoContentClick(theWindow, event); inDrag: DragWindow(theWindow, event.where, theWindow^.portRect); inGoAway: IF TrackGoAway(theWindow, event.where) THEN BEGIN myErr := FixTSMDocument(gIDocID); {confirm text} DoActivate(theWindow, FALSE); {deactivate window} HideWindow(theWindow); {put it away} gVisible := FALSE; END; END; END;Deleting a TSM Document
When your client application closes a document window and no longer needs its associated TSM document, it needs to call theDeleteTSMDocument
function to inform the Text Services Manager that the TSM document should be deleted.The Text Services Manager closes the text service components for the specified TSM document by calling the Component Manager
CloseComponent
function for each open text service component. It then disposes of the internal TSM document record for the specified TSM document.Closing Down as a TSM-Aware Application
To let the Text Services Manager perform needed housekeeping chores when your application has closed, your client application needs to callCloseTSMAwareApplication
just before quitting, as shown in Listing 7-6.Listing 7-6 Closing a TSM-aware application
FUNCTION DoQuitApplication: OSErr; VAR myErr: OSErr; BEGIN {app-specific clean up} myErr := CloseTSMAwareApplication; {ignore the error} ExitToShell; END;Requesting a Floating Input Window for Text Entry
Your client application may need to provide for users who prefer to enter text using a floating input window instead of entering text directly in the line of a document. For example, when the text font size is too small for reading ideographic characters, too big for convenient entry directly into the document window, or is being greeked, users may prefer a floating input window.Your client application calls the
UseInputWindow
function with theuseInputWindow
parameter set toTRUE
to display a floating input window for the TSM document you specify in theidocID
parameter to the call. To display floating input windows for all documents associated with your application, you set theidocID
parameter toNIL
and theuseInputWindow
parameter toTRUE
. To return to inline input, callUseInputWindow
with theuseInputWindow
parameter set toFALSE
.Associating Input Methods With Scripts and Languages
If you use the application-interface routines, the Text Services Manager automatically associates a default input method with your TSM document every time the current script and language change. Although it is unlikely that it would ever need to, your client application can use Text Services Manager routines to control that automatic association.The Operating System uses the
GetDefaultInputMethod
andSetDefaultInputMethod
functions to associate an input method with a given script and language. When the user uses the Keyboard menu, Keyboard control panel, or other device for controlling input method preferences, these functions establish permanent associations (they last across restarts).The Text Services Manager maintains a current text service language that it uses to synchronize input methods to the current script system and language. The Operating System calls the
SetTextServiceLanguage
function when the user switches the keyboard script, and the floating window service calls theGetTextServiceLanguage
function to determine the text service language.These routines make use of the script-language record, described under "Identifying the Supported Scripts and Languages" on page 7-42.
If your client application uses the Text Services Manager application-interface routines, the Text Services Manager automatically synchronizes the input method to the current text service language and there is no need to make the calls described here. If your client application bypasses the Text Services Manager and uses the text service component routines, the Text Services Manager does not provide automatic input method synchronization and you may have to make some of these calls yourself. See "Direct Access to Text Service Components" on page 7-36 for more information on the Component Manager and on how to communicate directly with text service components.