Page 1 of 1

rawKeyDown/rawKeyUp seemingly out of sequence

Posted: Sat Feb 06, 2010 11:53 pm
by pkocsis
I just realized something about rawKeyDown/rawKeyUp (as well as keyDown/keyUp) that has become problematic for me. I mistakenly assumed that (in a field where someone is typing) if I receive a rawKeyDown, I should receive that keystroke's rawKeyUp before the next keystrokes rawKeyDown....of course I was wrong....

If someone quickly types 'abc', many times they are striking the 'b' key before the 'a' key is actually released. This renders logic that assumes a rawKeyUp would be sent before the next key's rawKeyDown totally useless. I don't know how I didn't realize this earlier in my development, I guess my software is getting in the hands of faster typists.

Has anyone ever faced the dilemma of wanting to do things in rawKeyDown/rawKeyUp handlers and faced the situation where two rawKeyDown messages are sent before receiving the initial key's rawKeyUp?

Thank you!

Re: rawKeyDown/rawKeyUp seemingly out of sequence

Posted: Thu Feb 11, 2010 9:32 am
by Regulae
Hi,

I have not faced precisely this challenge with synchronising rawKeyDown/Up and keyDown/Up, but have had to ensure mouseDown/Up synchronisation. Unexpected problems can emerge when a proficient user operates at speed. Some of these ideas may be of use in your case. To investigate the current problem, I created a new test stack, and put in three text fields of reasonable size, named:
card field “CharacterOutput”
card field “RawOutput”
card field “TestTyping”
... along with a button, whose script is:

Code: Select all

on mouseEnter
   put empty into card field "CharacterOutput"
   put empty into card field "RawOutput"
   put empty into card field "TestTyping"
end mouseEnter
... so I can easily clear the fields with a sweep of the mouse..
To see what is happening when keys are pressed, I wrote the following as a script for card field “TestTyping”:

Code: Select all

on keyDown keyValue
   put space&keyValue&"(d)" after line 1 of card field "CharacterOutput"
   pass keyDown
end keyDown

on keyUp keyValue
   put space&keyValue&"(u)" after line 1 of card field "CharacterOutput"
   pass keyUp
end keyUp

on rawKeyDown keyValue
   put space&keyValue&"(d)" after line 1 of card field "RawOutput"
   pass rawKeyDown
end rawKeyDown

on rawKeyUp keyValue
   put space&keyValue&"(u)" after line 1 of card field "RawOutput"
   pass rawKeyUp
end rawKeyUp
... and with this script, by alternately typing the characters “a” then “b”, at a modest pace, the output is “echoed” thus:

in card field “CharacterOutput”
a(d) a(u) b(d) b(u)
in card field “RawOutput”
97(d) 97(u) 98(d) 98(u)

... which is as it should be.
Typing at speed introduces problems:

in card field “CharacterOutput”
a(d) b(d) b(u)
... the keyUp for “a” is blocked by the “b”

and two possible problems in card field “RawOutput”
97(d) 98(d) 97(u) 98(u)
... where the key presses of “a” and “b” are “interlaced”, and
97(d) 98(d) 98(u) 97(u)
... where, while the “a” is pressed, the “b” is pressed and released, and then the “a” released. Note that the typing that appears in card field “TestTyping” is normal in both cases.
Replacing the script of card field “TestTyping” with the following:

Code: Select all

on keyDown keyValue
   global keyState, CharacterStore
   put space&keyValue&"(d)" after line 1 of card field "CharacterOutput"
   if keyState = "d" then
      put space&CharacterStore&"(u)" after line 2 of card field "CharacterOutput"
   end if
   put space&keyValue&"(d)" after line 2 of card field "CharacterOutput"
   put keyValue into CharacterStore
   put "d" into keyState
   pass keyDown
end keyDown

on keyUp keyValue
   global keyState
   put space&keyValue&"(u)" after line 1 of card field "CharacterOutput"
   put space&keyValue&"(u)" after line 2 of card field "CharacterOutput"
   put "u" into keyState
   pass keyUp
end keyUp

on rawKeyDown keyValue
   global rawKeyState, keyStore, bypassRawKeyUp
   put space&keyValue&"(d)" after line 1 of card field "RawOutput"
   if rawKeyState = "d" then
      put space&keyStore&"(u)" after line 2 of card field "RawOutput"
      put "yes" into bypassRawKeyUp
   end if
   put space&keyValue&"(d)" after line 2 of card field "RawOutput"
   put keyValue into keyStore
   put "d" into rawKeyState
   pass rawKeyDown
end rawKeyDown

on rawKeyUp keyValue
   global rawKeyState, bypassRawKeyUp, keyStore
   put space&keyValue&"(u)" after line 1 of card field "RawOutput"
   if bypassRawKeyUp = "yes" then
      if keyValue <> keyStore then
         put "no" into bypassRawKeyUp
         pass rawKeyUp
      end if 
   end if
   put space&keyValue&"(u)" after line 2 of card field "RawOutput"
   put "u" into rawKeyState
   pass rawKeyUp
end rawKeyUp
... we continue to have the downs/ups “echoed” in line 1 of the output fields, but with corrected output in line 2. Both keyDown and rawKeyDown adjustments look for a double “down”- if a keyDown is received, with the keyState still “d” (i.e. it was not switched back to “u” by a keyUp), keyDown takes corrective action. I have used separate variables for keyDown and rawKeyDown, so they don’t interfere with each other. rawKeyDown is more complex, to cope with the variety of problem cases. It took a diagram to work out the logic, so it is difficult to explain in words. It may be clearer if we consider how the solution might be applied to something more interesting than simply echoeing the keystrokes. What you would need to do is “break out” the parts of rawKeyDown/Up you want executed into separate handlers, say PressDown and ReleaseUp. You would then re-write the rawKeyDown/Up script thus:

Code: Select all

on rawKeyDown keyValue
   global rawKeyState, keyStore, bypassRawKeyUp, keyToUse
   if rawKeyState = "d" then
      put keyStore into keyToUse
      ReleaseUp
      put "yes" into bypassRawKeyUp
   end if
   put keyValue into keyToUse
   PressDown
   put keyValue into keyStore
   put "d" into rawKeyState
   pass rawKeyDown
end rawKeyDown

on rawKeyUp keyValue
   global rawKeyState, bypassRawKeyUp, keyStore, keyToUse
   if bypassRawKeyUp = "yes" then
      if keyValue <> keyStore then
         put "no" into bypassRawKeyUp
         pass rawKeyUp
      end if 
   end if
   put keyValue into keyToUse
   ReleaseUp
   put "u" into rawKeyState
   pass rawKeyUp
end rawKeyUp
... as I am don’t know exactly where these handlers are placed in your application, I have included the globals explicitly. It would be important to include keyToUse as a global available to PressDown and ReleaseUp, for correct operation. The above solution may not meet your needs, and I have tested it as much as possible, but I still may have tripped up somewhere. One observation I can make is that whatever happens in PressDown and ReleaseUp must be efficiently programmed, as a proficient typist will be “firing” them rapidly (which is the source of the current problem anyway), so slower processes can “queue up”, causing problems. Please don’t hesitate to let me know if I’ve made a mistake, been unclear, or am simply wide of the mark. It’s an interesting problem which may take some “tinkering” to solve.