Documentation Archive Developer
Search

ADC Home > Reference Library > Technical Notes > Legacy Documents > Text & Fonts >

Legacy Documentclose button

Important: This document is part of the Legacy section of the ADC Reference Library. This information should not be used for new development.

Current information on this Reference Library topic can be found here:

Inline Input for TextEdit with TSMTE

CONTENTS

This Technical Note describes TSMTE, an extension that simplifies implementation of inline input for TextEdit using the Text Services Manager in System 7.1 and later, and shows you how to make the best use of it. It also contains some advice for working with the Text Services Manager that applies to any application using TSM, not just those using TSMTE.

[Dec 01 1993]






Introduction

System 7.1 introduced a new Toolbox manager, the Text Services Manager, that makes it easier for applications to provide inline input for 2-byte script systems (see Inside Macintosh: Text, pages 7-6 to 7-12, for an overview). To implement inline input using the Text Services Manager, an application has to do two things: make some calls to the Text Services Manager in the right places, and provide Apple event handlers that respond to events from input methods by updating text data structures, displaying text, and translating text offsets and screen coordinates. The first part is easy (maybe 50-100 lines of code), the second part can, depending on the complexity of the text engine that you use, require substantial work (several hundred to thousands of lines of code).

TSMTE is an extension to the Text Services Manager that does the second part of the work for you if you use TextEdit. It provides Apple event handlers that handle all interactions between an input method and TextEdit. The handlers are kept in the system heap, so they are shared between all applications.

TSMTE thus can reduce the effort needed to implement inline input to a day or two. If you use TextEdit in documents or modeless dialogs, you have to make a few calls to TSMTE in exchange for its help; if you use TextEdit only in modal dialogs, you only have to modify the DLOG resources that define them.

If you use a text engine other than TextEdit for editing in your application, you can still use TSMTE to handle inline input wherever you use TextEdit, e.g., in dialogs.


Note:
KanjiTalk 6.0.7 had an extension that provided fully automatic support for inline input with TextEdit without any kind of modification to applications. With TSMTE, inline input is not quite so automatic - you have to make the necessary calls to TSMTE and the Text Services Manager to make it work.



Note:
Inside Macintosh: Text, pages 2-107 to 2-109, discusses two feature bits, teFUseTextServices and teFInlineInput. TeFUseTextServices doesn't have any impact on the Text Services Manager or TSMTE, so you can safely ignore it. TeFInlineInput is handled by TSMTE, so there is no need for you to touch it.


Back to top

TSMTE Overview

Availability

Currently, TSMTE is delivered as a system extension called "Inline Tuika Kinou", which is shown here:

Inline Tuika Kinou extension file

Figure 1. Inline Tuika Kinou extension file

If you look for this file while running system software in some language using the Roman script system, the name of the extension file will be displayed as "ÉCÉìÉâÉCÉìí<<â¡ã@î\".

The extension is part of the Japanese version of System 7.1, KanjiTalk 7. It is not part of the Japanese Language Kit or of any other version of System 7.1. This means that if you use TSMTE to implement inline input, it will currently only benefit users of Japanese system software. However, TSMTE may get rolled into a future version of the base system software, so that it would then be available for use with any 2-byte script system on any Macintosh worldwide. Your application should therefore use Gestalt to check for the presence of TSMTE and use it whenever it is available.

For development purposes, if you don't feel comfortable using Japanese system software, you can install the Japanese Language Kit and the Inline Tuika Kinou extension into system software in any language that you like. Apple does not exactly guarantee that these configurations will work, but our experience so far has been good. Final testing should of course be done on a real Japanese system. In order to get your application to use a Japanese font in dialogs or in documents where you don't allow the user to select a font, you have to register your application as Japanese using the Language Register application that comes with the Japanese Language Kit.

Limitations

You may find that with some fonts TSMTE truncates the lower portion of characters drawn in the input area because it reserves a two-pixel high area for underlining. This problem will be fixed in a future release.

Prerequisites

To use the Text Services Manager and TSMTE, your application has to support Apple events. At a minimum, it has to install at least one Apple event handler using AEInstallEventHandler. Usually of course you would install handlers for the four required event types, and set the isHighLevelEventAware bit in the SIZE -1 resource.


Note:
The SIZE resource also has a useTextEditServices bit. Contrary to the comments in Types.r and in Inside Macintosh: Text, this bit doesn't have any influence on inline input done with the Text Services Manager and TSMTE. It was used by the extension that provided inline input for TextEdit in KanjiTalk 6.0.7.


Back to top

Preparing to Use TSMTE

Starting from this section, we assume that you have a good understanding of the high-level routines of the Text Services Manager. You can find the necessary information in Inside Macintosh: Text, pages 7-17 to 7-24. Please make sure to read the section "More Inline Input Advice" at the end of this Technical Note for additional hints on how to successfully use the Text Services Manager and input methods.

Defining the Level of Functionality You Need

Your application can provide several different kinds of text editing functionality, and your usage of TSMTE and the Text Services Manager depends on which one you offer. Your application may support text input:

  1. in modal dialogs (which use TextEdit)
  2. in document windows using TextEdit and in modeless dialogs
  3. in windows using your own text engine

plus in any combination thereof.

The rest of this section discusses the steps you have to take to prepare your application to use TSMTE in any possible context. The following sections then look at the individual cases.

Testing for TSMTE

Before making calls for TSMTE, you have to check for its presence using Gestalt. The selector for TSMTE is gestaltTSMTEAttr, and you know that it is available if the gestaltTSMTEPresent bit in the response is set.

The following code initializes separate Boolean variables to indicate the presence of the Text Services Manager and TSMTE. Having separate variables is useful if you use your own text engine in addition to TextEdit and want to support inline input for that engine even if TSMTE is not present.

static void CheckForTextServices(void)
{
    long gestaltResponse;

    gHasTextServices = false;        // unless proven otherwise
    gHasTSMTE = false;            // unless proven otherwise

    if (TrapAvailable(_Gestalt))
    {
        if ((Gestalt(gestaltTSMgrVersion, &gestaltResponse) == noErr) &&
             (gestaltResponse >= 1))
        {
            gHasTextServices = true;
            if (Gestalt(gestaltTSMTEAttr, &gestaltResponse) == noErr)
                gHasTSMTE = BTst(gestaltResponse, gestaltTSMTEPresent);
        };
    };
}

Initializing and Closing the Text Services Manager

To enable inline input, you have to initialize the Text Services Manager by calling InitTSMAwareApplication in your initialization sequence, and close it before quitting by calling CloseTSMAwareApplication. But what if TSMTE is not available? Then you have to make the floating input window available to the user for entering text in a 2-byte script into a TextEdit field. How to do this depends on whether you use your own text engine in addition to TextEdit (we assume that your own text engine supports inline input - otherwise you probably would not think about adding inline input support to TextEdit).

If you only use TextEdit in your application, you simply call InitTSMAwareApplication only if TSMTE is available. If you don't call InitTSMAwareApplication, system software will automatically handle input in 2-byte scripts for your application in a floating input window. The following code performs the initialization and also shows how to move on without text services if InitTSMAwareApplication fails:

if (!(gHasTSMTE && InitTSMAwareApplication() == noErr))
{
    // if this happens, just move on without text services
    gHasTextServices = false;
    gHasTSMTE = false;

If you use your own text engine in addition to TextEdit and support inline input for it, you want to use inline input for your engine even if TSMTE is not available. To do this, you simply check gHasTextServices instead of gHasTSMTE in the first line of the code above. Later, you also have to make sure that you tell the Text Services Manager to use the floating input window whenever a TextEdit field is active - the section "Using TSMTE and TextEdit in Addition to Your Own Text Engine" discusses this in detail.

In either case, you have to call CloseTSMAwareApplication before quitting an application for which you successfully called InitTSMAwareApplication:

if (gHasTextServices)
    (void) CloseTSMAwareApplication();

Back to top

Using TSMTE for Modal Dialogs

Once you have initialized the Text Services Manager, TSMTE offers a very easy way to handle inline input for modal dialogs: you set the refCon field in the DLOG resource to kTSMTEDialog or kTSMTEInterfaceType, TSMTE handles the rest. Or, if circumstances force you to create a dialog programmatically, you can pass kTSMTEInterfaceType as the refCon argument to NewDialog or NewCDialog (these routines do not accept kTSMTEDialog). Either way, TSMTE will automatically create a TSMDocument for you, activate and deactivate the TSMDocument, and enable inline input for the dialog. When you call CloseDialog or DisposeDialog, TSMTE disposes of the TSMDocument it created, activates the TSMDocument that was active before opening the dialog (if there was one), and resets the Text Services Manager flag that determines whether to use the floating input window to its previous state.


Note:
If you use this feature, you can still use the refCon field for your own purposes after creating the dialog - TSMTE doesn't need it any longer.


The difference between the two constants is that kTSMTEInterfaceType tells TSMTE to use an extended dialog record, TSMDialogRecord, while kTSMTEDialog uses the standard dialog record. Using the extended dialog record lets you access the information that TSMTE uses if you need it; without it, the information is stored in TSMTE's private data structures. If you use kTSMTEInterfaceType but don't provide storage for the dialog record, the Dialog Manager routines will automatically allocate an extended record.

If you use kTSMTEInterfaceType and allocate your own storage or add your own fields to the dialog record, you have to take the additional 20 bytes of the extended dialog record into account. If you add your own fields, it's a good idea to also allocate your own storage. This way you can always include the fields for TSMTE, otherwise the location of your fields in the record depends on whether TSMTE is installed or not.

If you provide an event filter function for ModalDialog, TSMTE gives you the choice whether you want to handle Text Services Manager calls or whether TSMTE should do it. To determine whether the function handles the calls, TSMTE calls it with a null event. If the function calls TSMEvent, TSMTE assumes that the function makes all the necessary calls to the Text Services Manager. If it doesn't, or if there is no event filter function, TSMTE makes all the necessary calls itself.

While using inline input, ModalDialog doesn't return because it doesn't get to see any "real" events. If you have a dialog that opens with a disabled action button and waits for the user to type text into an editable text item before enabling the button, checking the editable text item only after ModalDialog returns does not have the desired effect - if the user uses inline input to enter text, the button doesn't get enabled. A solution for this is to use an event filter function that checks the text in the editable text item and enables the button if the text length is above zero. The event filter function is guaranteed to be called with a null event whenever TSMEvent consumes a keyDown event.

Back to top

Using TSMTE for Document Windows and for Modeless Dialogs

If you use TextEdit to edit text in document windows or if you use modeless dialogs, some more work is shifted over to you: now it becomes your responsibility to call the high-level Text Services Manager routines. You'll have to add calls to:

NewTSMDocument
DeleteTSMDocument
ActivateTSMDocument
DeactivateTSMDocument
TSMEvent
TSMMenuSelect
SetTSMCursor

Before making the Text Services Manager calls, you have to make sure that their preconditions are met. You only want to create a TSM document for a TextEdit text record if TSMTE is available. You only want to delete, activate, or deactivate, or confirm ("fix") a TSM document if creating it was successful. The remaining routines depend on the Text Services Manager being available, but not necessarily on TSMTE - you may be using your own text engine with inline input in addition to TextEdit. The variables gHasTextServices and gHasTSMTE introduced above can help you make the necessary decisions. For example, your menu handling code might look like this:

menuResult = MenuSelect(event->where);
if (!(gHasTextServices && TSMMenuSelect(menuResult)))
    DoMenuCommand(menuResult);

The usage of Text Services Manager routines is documented in Inside Macintosh: Text, so we'll discuss only how TSMTE extends the Text Services Manager interface.

Creating a TSM Document

When creating a TSMDocument for a TextEdit text record, you have to use a special interface type kTSMTEInterfaceType to indicate that TSMTE should handle Apple events for this TSM document.

If you pass kTSMTEInterfaceType to NewTSMDocument, the refCon argument takes on a different meaning. Instead of a value to be stored in the TSM document, you should pass in the address of a variable of type TSMTERecHandle. TSMTE allocates a data structure of type TSMTERec and assigns a handle to it to your variable. This data structure contains several fields that you can use to tailor TSMTE's behavior to the needs of your application. It is your application's responsibility to initialize the record.

struct TSMTERec {
    TEHandle             textH;
    TSMTEPreUpdateUPP    preUpdateProc;
    TSMTEPostUpdateUPP   postUpdateProc;
    long                 updateFlag;
    long                 refCon;

The textH field has to be set to the text record handle that this TSM document relates to.

In preUpdateProc and postUpdateProc you can specify call-back routines that TSMTE should call before and after its own code when handling the Update Active Input Area event (one of the Apple events that is sent by the input method). The interfaces and possible uses for both routines are described below. If you don't have routines that TSMTE should call, set the fields to nil.

The updateFlag field is intended for customization of TSMTE's behavior. The idea is that TSMTE can define several constants for variations in its behaviors, and you sum up the constants for the variations that you like and assign them to the updateFlag field. Currently, only one such constant, kTSMTEAutoScroll, is defined. It specifies that TSMTE automatically scrolls the selection range into view. If you set updateFlag to 0, automatic scrolling is disabled, and you have to scroll the text yourself, e.g., in one of the call-back routines.

The refCon field lets you specify a value that TSMTE will pass on to the call-back routines. TSMTE doesn't make any other use of this field.

Here is some sample code for creating a TSMDocument. It assumes that you have just created a TEHandle called docTEHandle, and that a Boolean variable good is used to indicate whether operations are successful, and that you want to pass a pointer to the document window to your call-back routine.

if (good && gHasTSMTE)
{
    supportedInterfaces[0] = kTSMTEInterfaceType;
    if (NewTSMDocument(1, supportedInterfaces, &doc->docTSMDoc,
                (long) &doc->docTSMTERecHandle) == noErr)
    {
        TSMTERecPtr tsmteRecPtr = *(doc->docTSMTERecHandle);

        tsmteRecPtr->textH = doc->docTE;
        tsmteRecPtr->preUpdateProc = gTSMTEPreUpdateUPP;
        tsmteRecPtr->postUpdateProc = gTSMTEPostUpdateUPP;
        tsmteRecPtr->updateFlag = kTSMTEAutoScroll;
        tsmteRecPtr->refCon = (long) window;
    }
    else
        good = false;

You shouldn't dispose of the TSMTERecHandle - DeleteTSMDocument will do this for you.

Using a Pre-Update Call-Back Routine

Pre-update call-back routines for TSMTE have the following interface:

If you provide a pre-update routine for a TSM document, it is called before TSMTE's code for handling the Update Active Input Area events relating to this document.

The values for the textH and refCon arguments are taken from the TSMTERecHandle of the TSM document.

One common use of the pre-update routine is to save information that will be needed for Undo and Redo. Without inline input, an application typically treats an uninterrupted sequence of keyDown events (other than arrow or function keys) as one action, and saves the currently selected text and related information when receiving the first event in this sequence. In this regard, you should treat a call to your pre-update routine as just another form of typing, and if it's the first one in a typing sequence, save the information for Undo.

Another use is to work around a bug in TSMTE 1.0, which doesn't always synchronize the font to be used with the current keyboard script. The following routine checks whether the current font can display the incoming characters, and if not, sets the font to the keyboard script's application font. A better solution would be to scan the text backwards for the most recently used font of the keyboard script. This solution will be used by future versions of TSMTE, so make sure to check the TSMTE version and use the workaround only for TSMTE 1.0, as shown below. The synchronization is only necessary when a new active input area is created, so you may want to use the post-update routine to track whether there is an active input area and only execute the font synchronization code when the pre-update routine is called while there's no active input area.

static pascal void MyTSMTEPreUpdateProc(TEHandle textH, long refCon)
{
    long response;
    ScriptCode keyboardScript;
    short mode;
    TextStyle theStyle;

    if ((Gestalt(gestaltTSMTEVersion, &response) == noErr) &&
         (response == gestaltTSMTE1))
    {
        keyboardScript = GetScriptManagerVariable(smKeyScript);
        mode = doFont;
        if (!(TEContinuousStyle(&mode, &theStyle, textH) &&
                FontToScript(theStyle.tsFont) == keyboardScript))
        {
            theStyle.tsFont = GetScriptVariable(keyboardScript, smScriptAppFond);
            TESetStyle(doFont, &theStyle, false, textH);
        };
    };

Note:
Depending on which interface files you use, you may have to use the old name GetEnvirons instead of the new GetScriptManagerVariable, because there's no correct declaration for the new name. The universal interfaces have a correct declaration.


If your application occasionally changes the origin of the TextEdit record's grafPort, you can also use the pre-update routine to reset the origin so that characters get drawn in the right location.

Using a Post-Update Call-Back Routine

Post-update call-back routines for TSMTE have the following interface:

pascal void MyTSMTEPostUpdateProc(TEHandle textH, long fixLen,
            long inputAreaStart, long inputAreaEnd,

If you provide a post-update routine for a TSM document, it is called after TSMTE's code for handling Update Active Input Area events relating to this document. If you have set the updateFlag field in the TSMTERec record to kTSMTEAutoScroll, TSMTE calls the call-back routine first, and then scrolls the selection range into view.

The values for the textH and refCon arguments are taken from the TSMTERecHandle of the TSM document. InputAreaStart and inputAreaEnd are the offsets of the start and end of the active input area relative to the entire text handle; they are both set to -1 if there is no active input area. The remaining parameters are a subset of the parameters for the Update Active Input Area event. The fixLen parameter is the length of the confirmed text. PinStart and pinEnd are the offsets of the start and end of the text range that should be in view.

Common uses of the post-update routine are:

  • adjusting scroll bars or input field widths to the width and height of the text, which may have changed during editing,
  • setting a "modified" flag for the document,
  • saving information about the text being entered for Undo and Redo,
  • keeping track of whether there's an active input area.

Calling FixTSMDocument

The FixTSMDocument routine should be called whenever the user switches from typing to a different kind of activity that operates on the text, e.g., initiating an editing command from the menu or selecting text. It should not be called for actions that would not be considered interrupting a typing sequence, e.g., resizing or scrolling the window. There are some actions in between for which we don't have clear guidelines yet; in these cases use your best judgment.

TSMTE will in some cases detect that FixTSMDocument needs to be called and do it for you, e.g., when the user clicks into a part of the document outside the input area. In most cases however it is your responsibility to call FixTSMDocument when appropriate: when the user selects an editing command from the menu, closes a document, saves or prints it.


Back to top

Using TSMTE and TextEdit in Addition to Your Own Text Engine

If you use your own text engine in addition to TextEdit, you will have to provide your own Apple event handlers for the Text Services Apple events to implement inline input for your engine. However, you can still use TSMTE to provide inline input wherever you use TextEdit in your application.

Your Apple event handlers don't need to worry about TextEdit at all. TSMTE installs its event handlers in the system heap, so you can install your handlers in the application heap. The supported interface type that you specify when you create a TSM document is used to arbitrate between the handlers: for TSM documents that were created with kTSMTEInterfaceType, the TSMTE handlers are called, for those that were created with kTextService, your handlers.

The only thing you have to worry about is what to do if the Text Services Manager is available, but not TSMTE, so that you can provide inline input for your engine, but not for TextEdit. In this case you want to make sure that inline input is used whenever your engine is active, but that a floating input window is made available whenever a TextEdit field is active (without the floating input window users would not be able to type anything meaningful in a 2-byte script). You can do this by calling UseInputWindow whenever you activate or deactivate a TextEdit record - here is sample code for activation:

if (doc->docTSMDoc != nil)
    CheckError(ActivateTSMDocument(doc->docTSMDoc));
else

Back to top

More Inline Input Advice

This section contains some information that is not specific to TSMTE, but applies to all applications that use the Text Services Manager in any form. It shows workarounds for some unexpected features (we won't use entomological terminology here...) in the Text Services Manager and first-generation input methods written for it. Some of those unexpected features are expected to be or have already been discontinued in newer versions.

Incorrect Declaration in TextServices.p

The Text Services interface file TextServices.p that is currently distributed on E.T.O. 12 and the November 1993 Developer CD contains an incorrect declaration for NewTSMDocument. The declaration should read:

Function NewTSMDocument(numOfInterface: Integer;
        VAR supportedInterfaceTypes: InterfaceTypeList;
        VAR idocID: TSMDocumentID;
        refCon: Longint): OSErr;

Without the keyword "var" in front of "supportedInterfaceTypes", your application will encounter a bus error in NewTSMDocument. So, go in and add the keyword "var" if it's not there.

The declaration for NewTSMDocument in TextServices.h is correct.

DeleteTSMDocument Uses Disposed Handle

If a TSMDocument is deleted without being deactivated first, the routine DeleteTSMDocument may reuse a handle that it has already disposed of. It dereferences this handle and writes a single byte. This may eventually cause your application to crash mysteriously.

Workaround: make sure to deactivate each TSM document using DeactivateTSMDocument before calling DeleteTSMDocument to delete it. If TSMTE calls DeleteTSMDocument for a TSM document it created for a modal dialog it does the right thing.

ActivateTSMDocument Must Be Called From Foreground

ActivateTSMDocument does not work properly if called from the background. When a window that owns a TSM document is coming to the foreground from the background, your application is supposed to call ActivateTSMDocument with the TSMDocumentID for that window. However, if your application makes this call while still in the background, inline input may not become re-enabled in that window. Applications that follow the usual scheme of activating windows after receiving an activate event shouldn't have any problems.

SetTSMCursor and Cursor Regions

Applications that use TSM are supposed to call SetTSMCursor generously in order to allow TSM components to set the cursor when they need to do so. Unfortunately, there is no protocol for finding out in which region the input method would want to set the cursor. This presents a problem for many applications that try to be cooperative by passing a cursor region to WaitNextEvent. Without information from the input method, an application using inline input cannot calculate a meaningful cursor region, and thus has to be run whenever the mouse moved.

The only thing you can currently do is to define a 1-pixel cursor region under the mouse point and pass this region to WaitNextEvent. This setup will cause mouse-moved events to be generated whenever the mouse is moved, but will let the application sleep if the mouse stays put.

Strange Delete Key Behavior

If you use version 1.0 of Kotoeri, Apple's Japanese input method, you may notice that deletion of Japanese characters in the active input area using the delete character does not work properly in your application. This is more likely to happen with styled text or on non-Japanese system software (e.g., with the Japanese Language Kit installed). Kotoeri thinks that it is using a Roman font and only deletes one byte for each delete key pressed. This results in the need to press the delete key twice to delete a single Japanese character as well as other strange inline behavior. This bug has been fixed in version 1.1.1, which was first shipped as part of the Japanese version of the system software for Power Macintosh.

Workaround: Add some code around your call to TSMEvent that sets the font in the current grafPort to one of the keyboard script, and resets it afterwards if necessary. Kotoeri's behavior depends on the font in the current grafPort that it encounters during your call to TSMEvent. Here is a routine that you can call instead of TSMEvent to accomplish this:

static Boolean IntlTSMEvent(EventRecord *event)
{
    short oldFont;
    ScriptCode keyboardScript;

    // make sure we have a port and it's not the Window Manager port
    if (qd.thePort != nil && FrontWindow() != nil)
    {
        oldFont = qd.thePort->txFont;
        keyboardScript = GetScriptManagerVariable(smKeyScript);
        if (FontToScript(oldFont) != keyboardScript)
            TextFont(GetScriptVariable(keyboardScript, smScriptAppFond));
    };
    return TSMEvent(event);

You should also make sure that the current grafPort at this point is the one in which the input will be displayed.

Input Methods Need Null Events

Some input methods rely on receiving null events to function properly. The effects you may see if you don't feed them enough null events vary: An input method may not redraw its windows correctly, or it may occasionally lose input data.

Workaround: you should call IntlTSMEvent (or TSMEvent if you don't use the workaround in the previous section) even if WaitNextEvent returns false. The sample code in Inside Macintosh: Text , page 7-22, is wrong in this respect. Your code might look like this:

gotEvent = WaitNextEvent(everyEvent, &event, GetSleep(), cursorRgn);
if (gHasTextServices && (gotEvent || event.what == nullEvent))
    if (IntlTSMEvent(&event))
        gotEvent = false;
if (gotEvent)
    HandleEvent(&event);
else

Back to top

Pascal Summary

Constants

const

    { signature, interface types }

    kTSMTESignature = 'tmTE';
    kTSMTEInterfaceType = kTSMTESignature;
    kTSMTEDialog = 'tmDI';

    { Gestalt }

    gestaltTSMTEAttr = kTSMTESignature;
    gestaltTSMTEPresent = 0;
    gestaltTSMTEVersion = 'tmTV';
    gestaltTSMTE1 = $0100;

    { update flag for TSMTERec }

Data Types

type

    TSMTERec = record
        textH:          TEHandle;
        preUpdateProc:  ProcPtr;
        postUpdateProc: ProcPtr;
        updateFlag:     Longint;
        refCon:         Longint;
        end;

    TSMTERecPtr = ^TSMTERec;
    TSMTERecHandle = ^TSMTERecPtr;

    TSMDialogRecord = record
        fDialog:        DialogRecord;
        fDocID:         TSMDocumentID;
        fTSMTERecH:     TSMTERecHandle;
        fTSMTERsvd:     array [0..2] of Longint;
        end;

Application-Defined Routines

procedure MyTSMTEPreUpdateProc(textH: TEHandle; refCon: Longint);
procedure MyTSMTEPostUpdateProc(textH: TEHandle; fixLen: Longint;
        inputAreaStart, inputAreaEnd: Longint;

Back to top

C Summary

Constants

// signature, interface types

enum  {
    kTSMTESignature     = 'tmTE',
    kTSMTEInterfaceType = kTSMTESignature,
    kTSMTEDialog        = 'tmDI'
};

// Gestalt

enum  {
    gestaltTSMTEAttr    = kTSMTESignature,
    gestaltTSMTEPresent = 0,
    gestaltTSMTEVersion = 'tmTV',
    gestaltTSMTE1       = 0x100
};

// update flag for TSMTERec

enum  {
    kTSMTEAutoScroll    = 1

Data Types

// the following proc ptr declarations come with the usual complements of
// universal proc ptr declarations and related routines

typedef pascal void (*TSMTEPreUpdateProcPtr)(TEHandle textH, long refCon);

typedef pascal void (*TSMTEPostUpdateProcPtr)(TEHandle textH, long fixLen,
        long inputAreaStart, long inputAreaEnd,
        long pinStart, long pinEnd, long refCon);

struct TSMTERec {
    TEHandle            textH;
    TSMTEPreUpdateUPP   preUpdateProc;
    TSMTEPostUpdateUPP  postUpdateProc;
    long                updateFlag;
    long                refCon;
};

typedef struct TSMTERec TSMTERec, *TSMTERecPtr, **TSMTERecHandle;

struct TSMDialogRecord {
    DialogRecord        fDialog;
    TSMDocumentID       fDocID;
    TSMTERecHandle      fTSMTERecH;
    long                fTSMTERsvd[3];
};

Application-Defined Routines

pascal void MyTSMTEPreUpdateProc(TEHandle textH, long refCon);
pascal void MyTSMTEPostUpdateProc(TEHandle textH, long fixLen,
        long inputAreaStart, long inputAreaEnd,

Back to top

References

Inside Macintosh: Text, Text Services Manager

Sample Code: "InlineInputSample"

Change History

01-January-1994

Fixed a bug in the IntlTSMEvent routine that could modify the Window Manager port's font, and updated the related information about the Japanese input method. Added section "Input Methods Need Null Events". Clarified the information about required support for Apple events in the Prerequisites section.

01-December-1993

Originally written.


Back to top

Downloadables

Acrobat gif

Acrobat version of this Note (80K).

Download