Filter buffered keystrokes

You can post your code snippets here for others to use and learn from
Post Reply
Flinx
Posts: 192
Joined: Sun Feb 14, 2021 9:54 am
Location: Germany

Filter buffered keystrokes

Post by Flinx »

When characters sent by key events trigger actions that last for a while, and you hold down a key so that the automatic key repeat starts, the characters are buffered, and the actions are repeated way too often with no way to stop it. In my player I had this effect in the search and at volume changes.
Because it took me a while to handle this reasonably, here's an example of how to filter these events generated by the operating system's TypeMatic function.
To demonstrate, I move a small square with the left and right arrow keys. (Of course this is just an example, for this action you would not use key events but query the keys directly).
Moving the square happens in the last five lines of the event function. Before that the TypeMatic repetitions are filtered, but I made this filtering inoperative with the line TypeMatic=False, so you have the unwanted behavior first and can compare.
To filter the events, a table of pressed keys is made using the key string as index, and then the automatically repeated keystrokes older than 0.1 seconds are removed.

In this way, separate keystrokes remain valid, but the automatically repeated ones do not.

Code: Select all

Const #BOXSIZE=14
Const #WIDTH=1000

Function p_EventPhysKey(msg)
	Local TypeMatic
	Switch (msg.action)
	Case "OnKeyDown":
		If RawGet(gKeysDown, msg.key)
			; if already in the table
			TypeMatic=True
		Else
			TypeMatic=False
			gKeysDown[msg.key]=True
		EndIf
	Case "OnKeyUp":
		gKeysDown[msg.key]=Nil
		Return
	EndSwitch

	TypeMatic=False ; ***** remove this line to make the TypeMatic filter work *****

	Local KeyTimestampAge=GetTimestamp()-msg.TimeStamp ; age of the current key event
	If KeyTimestampAge>0.1 And TypeMatic
		Return ; discard all TypeMatic events older than 0.1 seconds
	EndIf

	If msg.key="RIGHT" Then newXpos=Xpos+#BOXSIZE*2
	If msg.key="LEFT"  Then newXpos=Xpos-#BOXSIZE*2
	MoveBrush(1, Xpos, Ypos, newXpos, Ypos, {Speed = #BOXSIZE/6})
	Box(Xpos, Ypos, #BOXSIZE, #BOXSIZE, #GRAY) ; restore gray box
	Xpos=newXpos
EndFunction

@DISPLAY{WIDTH = #WIDTH, HEIGHT = #BOXSIZE*3}
SetFillStyle(#FILLCOLOR)
CreateBrush(1,#BOXSIZE,#BOXSIZE,#YELLOW)
Xpos = #BOXSIZE ; initial X position
Ypos = #BOXSIZE ; initial Y position
For i=0 To #WIDTH/(#BOXSIZE*2)-1 ; gray boxes
	Box(i*#BOXSIZE*2+#BOXSIZE, Ypos, #BOXSIZE, #BOXSIZE, #GRAY)
Next
DisplayBrush(1, Xpos, Ypos)
gKeysDown={} ; table of currently pressed keys for TypeMatic detection
InstallEventHandler({OnKeyDown=p_EventPhysKey, OnKeyUp=p_EventPhysKey})
Repeat
	WaitEvent
Forever
Post Reply