[comp.sys.mac.hypercard] Reading Function Keys from repeat...until loop: HOW?

hughes@ux.acs.umn.edu (Steve Hughes) (11/28/90)

There must be a way....

Man, all I want out of life is to check the function keys while
I'm executing a repeat...until handler. I want it to work like this:

  put the ticks + 180 into endTick
  repeat until the ticks >= endTick
    if functionKey then
      if functionKey = 1 then doThis
      if functionKey = 2 then doThat
      if functionKey = 3 then doThatOtherThing
    else
      beep
    end if
  end repeat

Now, I know that this is not how to use functionKey, and that what
I probably really want to do is use some kind of XFCN, but given that
this must run with HyperCard 2.0, I'm wondering if there are XFCNs out there
to do this (or does HC 2.0 have this ability and I'm not reading the right
documentation?)

It doesn't seem like simply reading the @#%&! function keys from within
a handler should be so difficult, yet I'm bashing my brains trying to make
it work! Can onyone help?

Thanks,

---Steve Hughes

   hughes@ux.acs.umn.edu

jk3t+@andrew.cmu.edu (Jonathan King) (11/28/90)

hughes@ux.acs.umn.edu (Steve Hughes) writes:
> There must be a way....
> 
> Man, all I want out of life is to check the function keys while
> I'm executing a repeat...until handler. 

It's good to see somebody with a clear and worthwhile goal...

> I want it to work like this:
> 
>   put the ticks + 180 into endTick
>   repeat until the ticks >= endTick
>     if functionKey then
>       if functionKey = 1 then doThis
>       if functionKey = 2 then doThat
>       if functionKey = 3 then doThatOtherThing
>     else
>       beep
>     end if
>   end repeat
> 
> Now, I know that this is not how to use functionKey, and that what
> I probably really want to do is use some kind of XFCN, but given that
> this must run with HyperCard 2.0, I'm wondering if there are XFCNs out there
> to do this (or does HC 2.0 have this ability and I'm not reading the right
> documentation?)

Leaving XFCNs out of this for now, the short answer to what you are
asking for seems to be "No, you can't test for a functionKey that way
in a repeat loop".  FunctionKey can be used either as a command or a
message, but not as a function.  Yes, it would have probably been nice
if there were a function that would return whichKey if a function key
was pressed, but there isn't.

So, now let me persuade you that you really want to do something else
which you *can* do :-).

What your script fragment suggests you *really* want to do is allow a
user to make some choice or other that can be signalled by pressing a
function key, as long as that choice is made in some reasonable amount
of time.  So, I'm guessing that the handler surrounding your repeat
loop looks (schematically) like this:

on makeChoice
  preparestuff
  setTimeOut
  loopAroundUntilTimeIsOutOrFunctionKeyIsPressed
end makeChoice

(I'm ignoring the beeping for now since I don't understand why you
would want to constantly beep at the user  if the functionKey
isn't down yet; that could be really, really annoying.)

The simplest way to do this (without the beeping) is to set a global 
variable TimeOut (your EndTick) to the proper value, and set another
global variable contextCommand to the name of the command you want
executed when the event occurs.  Then you can let other independent
handlers do the dispatching for you.  Note that this allows you to
handle functionKeys (or other kinds of events) in multiple contexts.
The finished functionKey handler might look something like this:

on functionKey whichkey
  global timeOut, contextCommand
   if contextCommand is not empty then 
     if the ticks < timeOut then
        put empty into timeOut        --clean up your globals
        put contextCommand into doit  --prepare to clean up your global
        put empty into contextCommand --otherwise your global survives
        do doit whichkey    --check my syntax, but this is doable
     end if  -- do your complaining in an idle handler (like below)
   end if
  else pass functionKey  -- someone else might want this message
end functionKey

The "do" command here will dispatch an appropriate message (maybe
"recordChoice") with the functionKey argument which you can handle in
a separate handler.

Now, you might also want to do something in case you time out, which
you can handle in an idle handler like this:

on idle
  global timeOut, contextComand
  if contextCommand is not empty then  -- can't time out otherwise
    if the ticks > timeOut then
       put empty into timeOut          -- more global scrubbing
       put contextCommand into doit    -- same dance as before so that
       put empty into contextCommand   -- we don't need to return
       do doit "timedout"  --check my syntax, but this is doable
    end if
  else pass idle -- someone else might want this message
end idle

Now if you time out, the handler can do something appropriate like
give feed back to the user, or do some default thing or whatever.

It might seem like all this mucking around with functionKey and idle
handlers is just an enormous hack, but I've been finding that it is
sometimes really convenient to spread control around like this and
worry more about trapping events flexibly than about maintaining rigid
control at all times (unless you're writing stack that do things like
take reaction times or something equally bizarre).  A variation of this same
technique can be used to do things like check for doubleclicks and put
together escape sequences using the escape key.  

(The latter has been really useful to me recently, since I'm
developing a stack that pretends it's EMACS--you just put it on the
stacks-in-use list and voila! you can do emacs-style editing in any
field you're in, including (really usefully) the message box.  Right
now I'm debugging keyboard macro creation...pretty tricky stuff.  If
anybody else out there is weird enough to be interested in this, you
can drop me a line and I'll let you know when it's stable.)

> It doesn't seem like simply reading the @#%&! function keys from within
> a handler should be so difficult, yet I'm bashing my brains trying to make
> it work! Can onyone help?

Hope this helps some...

> ---Steve Hughes
>    hughes@ux.acs.umn.edu

jking