The Lesser-Known Mac Hacker’s Info Page

This section collects together various miscellaneous bits of information to do with programming the Macintosh, that don’t seem to be very well-known.

Speech Manager: capturing speech to a sound file (Macintalk Pro voices only).

UserDelay: smooth acceleration without scrolling out of control.

Selecting programmatically from the application menu.

Controlling the default applications that the Finder uses for documents whose creators can’t be found.

A description of the 68K MPW Object Code Format.

The format of Finder clipping files.

Description of the Appearance Manager’s “.Keyboard” font.


Capturing sound samples from Speech Manager voices

The Macintalk Pro synthesizer has a semi-documented feature that allows you to retrieve direct sound samples corresponding to a given piece of text. To use it, you need to make a GetSpeechInfo call with the “xtnd” selector, and pass a pointer to a structure that looks like this:

    GTXtndConvertData = (* Extended info for conversion selectors. *)
        RECORD
          (* input values *)
            synthID : OSType; (* soGalaSynthID ('gala'). *)
            selector : OSType; (* Extended selector ('cval' or 'cvwv'). *)
            inputBuffer : ADDRESS; (* Address of the data to convert. *)
            inputLen : LONGCARD; (* Length of the data to convert. *)
            controlFlags : (*long*) SpeechControlFlags;
              (* 0 (for last buffer) or kNoEndingProsody. *)
            outputBuffer : Handle;
              (* Handle to buffer for the output *)
          (* return values *)
            outputLen : LONGCARD; (* Returns the size of the output. *)
            moreOutput : BOOLEAN;
              (* Returns true if outputBuffer is too small for
                all the output at once *)
            unused : Byte
        END (*RECORD*);
In the synthID field, pass the value “gala” (hex 67616C61). In the selector field, pass “cvwv” (hex 63767776) to perform a text-to-sound-sample conversion. Pass a pointer to the text in inputBuffer, and its length in inputLen. Pass a handle to contain the sound samples in outputBuffer.

The output handle will be resized and filled with 16-bit twos-complement sound samples, at a fixed sample rate of 22254 Hz. If you want to turn this into a “snd ” resource, for example, then you will need to prepend a suitably-constructed ExtSoundHeader structure onto it.

As I’ve mentioned, this call works only with the Macintalk Pro voices. Also, it was clearly done as an interim hack, so it could very well stop working in a future release of Macintalk Pro. Use at your own risk.


Smooth scrolling acceleration

This call is used internally by TrackControl in order to implement smooth acceleration when the user holds the mouse button down on an arrow in a scrollbar. It can also be useful if you implement your own controls that perform some repeated increment/decrement action as long as the user holds the mouse button down. Here’s the interface to it:

    PROCEDURE UserDelay
      (
        StartTicks : LONGCARD;
        CurrTicks : LONGCARD;
        Limit : ShortCard
      ) : OSErr;

        CODE
            0303CH, 00500H,             (* move.w #$500, d0 *)
            0A84CH;                     (* _UserDelay *)

The idea is that you set StartTicks to the TickCount at the start of the loop, while CurrTicks is updated each time round the loop; the difference between these two values is used to gradually decrease the delay time according to one of two different formulas, depending on whether Limit is zero or not.

Note that the function never actually returns an error; its OSErr result is always noErr.

The precise algorithm is to delay until the user releases the mouse button, or until

    TickCount() >= CurrTicks + k1 + 108 DIV (CurrTicks - StartTicks + k2)
If Limit = 0, then k1 = 0 and k2 = 9; if Limit is nonzero, then k1 = 3 and k2 = 12. TrackControl always passes 0 for Limit.

Here’s an example code sequence that outlines how to use UserDelay, once you’ve determined that a mouse-down event has occurred within the appropriate part of your control:

    StartTicks := TickCount();
    HiliteTheControl(TRUE);
    Hilited := TRUE;
    REPEAT
      (* while the mouse is down *)
        LastTicks := TickCount();
        GetMouse(MouseWhere);
        IF WithinControl(MouseWhere) THEN
          (* turn highlighting on if off *)
            IF NOT Hilited THEN
                Hilited := TRUE;
                HiliteTheControl(TRUE)
            END (*IF*)
        ELSE
          (* turn highlighting off if on *)
            IF Hilited THEN
                Hilited := FALSE;
                HiliteTheControl(FALSE)
            END (*IF*)
        END (*IF*);
        IF Hilited THEN
            InvokeControlAction;
            Err := UserDelay
              (
                (*StartTicks :=*) StartTicks,
                (*CurrTicks :=*) LastTicks,
                (*Limit :=*) 0
              )
        END (*IF*)
    UNTIL
        NOT WaitMouseUp();
    IF Hilited THEN
        HiliteTheControl(FALSE)
    END (*IF*)
In this example, HiliteTheControl turns control highlighting on and off, WithinControl checks whether the mouse is still within the appropriate part of the control, and InvokeControlAction invokes whatever action is to be performed while the user holds the mouse button down.


Selecting programmatically from the application menu

You can invoke any of the items from the System 7 application menu (the one that drops from the application icon at the righthand end of the menu bar) by using the SystemMenu call. The ID of this menu is -16489. In particular, item number 1 hides the frontmost application; item 2 hides all but the frontmost application; and item 3 shows all applications. These functions work even when invoked from an application that is not the frontmost one.


Controlling the default applications for documents whose creators can’t be found

When you double-click on a document for which no creator application can be found on any mounted volume, and the document is of one of a particular set of types (including text files and QuickDraw picture files), the Finder will ask you if you want to open the document using a particular application, usually SimpleText.

The nice thing is, the set of file types, and the choice of application to open them, are not hard-coded into the Finder, but are stored in a resource with a simple format. This is the Finder’s “fmap” resource with ID 17010.

The format is a simple sequence of eight-byte entries, terminated by eight bytes of zeroes. Each entry consists of an OSType file type, followed by the OSType signature of the application to use to open a file of that type if the original creator cannot be found. For example, here is what the standard set of mappings looks like in Finder 7.5.1:

54455854 74747874 -- TEXT ttxt -- open text files with SimpleText
50494354 74747874 -- PICT ttxt -- open QuickDraw picture files with SimpleText
6C747472 6C617032 -- lttr lap2 -- open PowerTalk letters with AppleMail
736A6F62 74747874 -- sjob ttxt -- open QuickDraw GX print files with SimpleText
726A6F62 74747874 -- rjob ttxt -- open QuickDraw GX print files with SimpleText
716A6F62 74747874 -- qjob ttxt -- open QuickDraw GX print files with SimpleText
00000000 00000000 -- end of list

You can change, add and remove entries, so long as you keep the all-zero entry at the end.


Last modified 1998 April 20.

Back to LDO’s Home Page