[comp.sys.mac] Catching all keyDown events in a DA

kkim@uiucdcsb.cs.uiuc.edu (05/27/87)

    I am writing a Desk Accessory which transforms every input character.
The transformation is affected by a previous character, a current char,
Caps Lock key, shift key, option key, and command key.  My DA does *not
have its own window*; it is running in the *background* and transformed 
chars will be passed to an application (e.g. MacWrite).

    My DA is working a little now.  The biggest problem is that ONLY SOME
input chars do get transformed; however, there are other input chars which
do not get transformed.  I will show you a skeleton of my DA in Lightspeed
Pascal to give you a concrete idea.

-----------------------------------------------------------------
procedure OpenRoutine;
begin
    dCtlStorage:=NewHandle(SizeOf(PrivateStorage));
    dCtlFlags:=$6400; {DA can respond to control calls;}
        {DA needs time for performing periodic actions;}
        {DA will be locked in memory as soon as it is opened}
    dCtlDelay:=0; {must be called as often as possible}
    dCtlEMask:=keyDownMask;{meaningless?}
    whenSaved:=0;{evtQWhen of the latest keyDown event processed by a DA}
end;

procedure ControlRoutine;
begin
for counter:=1 to LIMIT do begin {LIMIT will be explained below}
    evQHdrPtr:=GetEvQHdr; {get a pointer to the header of the event queue}
    CurrElem:=evQHdrPtr^.qHead;
    while (CurrElem <> nil) do
        if (CurrElem^.evQElem.evtQWhen > whenSaved) then begin
            {an event which has not been processed by a DA; do transformation}
            CurrElem^.evQElem.evtQMessage:=transformedChar;
            whenSaved:=CurrElem^.evQElem.evtQWhen;
            end; {if}
        end; {while}
    end; {for counter}
end;

procedure CloseRoutine;
begin
    disposHandle(dCtlStorage);
end;

---------------------------------------------------------------
    I test my DA using MacWrite.  At first, LIMIT was 1 (i.e. no for loop).
The result was that about 2/3 of input chars did not get transformed.
The following table will help:

LIMIT            portion of input chars which did not get transformed
  1              2/3
 10              1/2
700              1/10
1000             1/15
2000             < 1/30

    When LIMIT was greater than about 500, some characters were lost if
I typed fast (due to the maximum event queue size).  I guess that LIMIT
shoud be set to 1 and some other mechanism must be adopted to get around
the problem. Does Vertical Retrace Manager have anything to do with it?


    Could anybody give me clues/hints/comments as to how to CATCH ALL THE 
KEYDOWN EVENTS IN A DESK ACCESSORY AND TRANSFORM THEM?

    Thanks in advance.

Kyongsok KIM

Dept. of Computer Science; Univ. of Illinois at Urbana-Champaign
arpanet/csnet: kkim@a.cs.uiuc.edu
usenet/uucp  : {seismo, pur-ee, ihnp4}!uiucdcs!kkim

tecot@apple.UUCP (Ed Tecot) (06/09/87)

In article <164500033@uiucdcsb> kkim@uiucdcsb.cs.uiuc.edu writes:
>
>    I am writing a Desk Accessory which transforms every input character.
>The transformation is affected by a previous character, a current char,
>Caps Lock key, shift key, option key, and command key.  My DA does *not
>have its own window*; it is running in the *background* and transformed 
>chars will be passed to an application (e.g. MacWrite).
>
>    My DA is working a little now.  The biggest problem is that ONLY SOME
>input chars do get transformed; however, there are other input chars which
>do not get transformed.  I will show you a skeleton of my DA in Lightspeed
>Pascal to give you a concrete idea.
>
>...
>
>    When LIMIT was greater than about 500, some characters were lost if
>I typed fast (due to the maximum event queue size).  I guess that LIMIT
>shoud be set to 1 and some other mechanism must be adopted to get around
>the problem. Does Vertical Retrace Manager have anything to do with it?
>
>
>    Could anybody give me clues/hints/comments as to how to CATCH ALL THE 
>KEYDOWN EVENTS IN A DESK ACCESSORY AND TRANSFORM THEM?
>

Your problem is that keyboard (and mouse) events are asynchronous.  It is
possible that your DA could check the queue, find no events, only to have a
user type immediately after that (and before the application calls
GetNextEvent.)  I recommend that you catch the events as they are posted.
Every event is posted using PostEvent.  Simply use GetTrapAddress and
SetTrapAddress to insert your code.  Remember that you will be called at
different interrupt levels and therefore you cannot make calls to the
memory manager (even indirectly), and that relocatable segments are not
usable.

						_eme