Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Text /
Chapter 7 - Text Services Manager / Using the Text Services Manager (for Client Applications)


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

Initializing as a TSM-Aware Application

If your client application plans to use any of the Text Services Manager application-interface routines, it must call InitTSMAwareApplication 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 the TSMDocument 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 the NewTSMDocument 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 the refcon parameter to the call. The Text Services Manager returns the refcon value in the keyAETSMDocumentRefcon parameter of any Apple event sent to your application. You can then use the refcon 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 to NewTSMDocument 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 the idocID parameter. The routine makes use of a modified window record (type MyWindowRecord) 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 function GetComponentListModSeed to see if the list of registered text service components may have changed.

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

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 the ActivateTSMDocument 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 function DeactivateTextService 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 function WaitNextEvent, you need to give each text service component an opportunity to handle that event, if appropriate. Use the TSMEvent 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 returns TRUE and the event is changed to a null event. If the event is not handled, TSMEvent returns FALSE 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 is TRUE 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 the TSMMenuSelect function with the result from the Menu Manager function MenuSelect in the menuResult parameter. If TSMMenuSelect returns TRUE, 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 returns TRUE, 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 the DeleteTSMDocument 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 call CloseTSMAwareApplication 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 the useInputWindow parameter set to TRUE to display a floating input window for the TSM document you specify in the idocID parameter to the call. To display floating input windows for all documents associated with your application, you set the idocID parameter to NIL and the useInputWindow parameter to TRUE. To return to inline input, call UseInputWindow with the useInputWindow parameter set to FALSE.

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 and SetDefaultInputMethod 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 the GetTextServiceLanguage 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.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
6 JUL 1996