Canvas simultaneous keypresses

BlitzMax Forums/BlitzMax GUI Programming/Canvas simultaneous keypresses

I was wondering how others are handling multiple, simultaneous keystrokes on a MaxGUI canvas.

Here's my attempt:

'A key-handling test for multiple, simultaneous key presses on a MaxGUI canvas.

'Blocks marked with asterisks(*) highlight relevent code.

SuperStrict

Global MainWindow:TGadget = CreateWindow("Simultaneous Key Press Test - MaxGUI Canvas.", 10, 10, 800, 600, Null, WINDOW_TITLEBAR | WINDOW_RESIZABLE)
Global GameCanvas:TGadget = CreateCanvas(0, 0, 0, 0, MainWindow)
Global GameCanvas_Width:Int 
Global GameCanvas_Height:Int
resizeGameCanvas()

Global PlayerX:Int = 0
Global PlayerY:Int = 0

Global FlipTimer:TTimer = CreateTimer(60)


'*** Key-handling initialisation ***

Const MaxKeys:Byte = 255					'Should equal maximum number of key scancodes. 
											'Non-english keyboards may have a higher value.
											
Global KeysDown:Int[MaxKeys]				'An array 'mapped' to the scancodes.
	
Global KeyTimer:TTimer = CreateTimer(100)	'The rate at which to check the keys.

'***********************************


Repeat

	PollEvent
	
	Select EventID()
	
		Case EVENT_TIMERTICK
		
			Select EventSource()
		
				Case FlipTimer
					RedrawGadget GameCanvas
					
				'*** Call the key handling function when 
				'*** the KeyTimer timer event occurs.
				
				Case KeyTimer
					processKeys()
					
				'****************************************
					
			EndSelect
	
		Case EVENT_GADGETPAINT
			SetGraphics CanvasGraphics(GameCanvas)
			Cls
			SetBlend SOLIDBLEND
			SetColor 255, 255, 255
			DrawText "ARROW keys move, ESC quits, T and E and S together brings up a Notify dialog.", 10, 10
			drawPlayer()
			Flip

		'*** When a key is pressed, set the corresponding 
		'*** array address to True.
		
		Case EVENT_KEYDOWN
			KeysDown[EventData()] = True

		'************************************************


		'*** When a key is released, set the corresponding 
		'*** array address to False.

		Case EVENT_KEYUP
			KeysDown[EventData()] = False

		'************************************************


		Case EVENT_WINDOWSIZE
			resizeGameCanvas()
			checkPlayerPosition()

		Case EVENT_APPRESUME
			ActivateGadget GameCanvas

		Case EVENT_WINDOWCLOSE
			endApp()
	
		Case EVENT_APPTERMINATE
			endApp()

	EndSelect	

Forever


'*** Key handling function

Function processKeys()

	If KeysDown[KEY_RIGHT] Then	PlayerX :+ 10
	If KeysDown[KEY_LEFT] Then PlayerX :- 10
	If KeysDown[KEY_UP] Then PlayerY :- 10
	If KeysDown[KEY_DOWN] Then PlayerY :+ 10
	If KeysDown[KEY_ESCAPE] Then endApp()
		
	checkPlayerPosition()
	
	If KeysDown[KEY_T] And KeysDown[KEY_E] And KeysDown[KEY_S] 
		Notify("Test")
		KeysDown[KEY_T] = False
		KeysDown[KEY_E] = False
		KeysDown[KEY_S] = False
	EndIf

End Function

'*************************


Function drawPlayer()

	SetBlend ALPHABLEND
	SetAlpha 0.75
	SetColor 0, 255, 255
	DrawOval PlayerX - 4, PlayerY - 4, 8, 8

EndFunction

Function resizeGameCanvas()

	SetGraphics CanvasGraphics(GameCanvas)
	SetGadgetShape GameCanvas, 5, 5, ClientWidth(MainWindow) - 10, ClientHeight(MainWindow) - 10
	GameCanvas_Width = GadgetWidth(GameCanvas)
	GameCanvas_Height = GadgetHeight(GameCanvas)
	SetViewport 0, 0, GameCanvas_Width, GameCanvas_Height
	ActivateGadget GameCanvas

EndFunction

Function endApp()

	FreeGadget GameCanvas		
	End

EndFunction

Function checkPlayerPosition()

	If PlayerX >= GameCanvas_Width Then PlayerX = GameCanvas_Width
	If PlayerX < 0 Then PlayerX = 0
	If PlayerY < 0 Then PlayerY = 0
	If PlayerY >= GameCanvas_Height Then PlayerY = GameCanvas_Height

End Function


Is there a simplier, more obvious approach?

For the moment, I do things the same way: store key states (and also mouse states for that matter!) into variables or arrays.

The undocumented (unfortunately) command enablepolledinput should enable you to use standard KeyDown commands with a canvas or active panel.

Note the use of waitevent instead of pollevent so your app doesn't run with 100% cpu usage:

'A key-handling test for multiple, simultaneous key presses on a MaxGUI canvas.

'Blocks marked with asterisks(*) highlight relevent code.

SuperStrict

Global MainWindow:TGadget = CreateWindow("Simultaneous Key Press Test - MaxGUI Canvas.", 10, 10, 800, 600, Null, WINDOW_TITLEBAR | WINDOW_RESIZABLE)
Global GameCanvas:TGadget = CreateCanvas(0, 0, 0, 0, MainWindow)
Global GameCanvas_Width:Int 
Global GameCanvas_Height:Int
resizeGameCanvas()

Global PlayerX:Int = 0
Global PlayerY:Int = 0

Global FlipTimer:TTimer = CreateTimer(60)

'*** Key-handling initialisation ***

enablepolledinput
	
Global KeyTimer:TTimer = CreateTimer(100)	'The rate at which to check the keys.

'***********************************

Repeat
	Select WaitEvent()
	
		Case EVENT_TIMERTICK
		
			Select EventSource()
		
				Case FlipTimer
					RedrawGadget GameCanvas
					
				'*** Call the key handling function when 
				'*** the KeyTimer timer event occurs.
				
				Case KeyTimer
					processKeys()
					
				'****************************************
					
			EndSelect
	
		Case EVENT_GADGETPAINT
			SetGraphics CanvasGraphics(GameCanvas)
			Cls
			SetBlend SOLIDBLEND
			SetColor 255, 255, 255
			DrawText "ARROW keys move, ESC quits, T and E and S together brings up a Notify dialog.", 10, 10
			drawPlayer()
			Flip

		Case EVENT_WINDOWSIZE
			resizeGameCanvas()
			checkPlayerPosition()

		Case EVENT_APPRESUME
			ActivateGadget GameCanvas

		Case EVENT_WINDOWCLOSE
			endApp()
	
		Case EVENT_APPTERMINATE
			endApp()

	EndSelect	

Forever


'*** Key handling function

Function processKeys()

	If KeyDown(KEY_RIGHT) Then	PlayerX :+ 10
	If KeyDown(KEY_LEFT) Then PlayerX :- 10
	If KeyDown(KEY_UP) Then PlayerY :- 10
	If KeyDown(KEY_DOWN) Then PlayerY :+ 10
	If KeyDown(KEY_ESCAPE) Then endApp()
		
	checkPlayerPosition()
	
	If KeyDown(KEY_T) And KeyDown(KEY_E) And KeyDown(KEY_S) 
		Notify("Test")
		FlushKeys
	EndIf

End Function

'*************************


Function drawPlayer()

	SetBlend ALPHABLEND
	SetAlpha 0.75
	SetColor 0, 255, 255
	DrawOval PlayerX - 4, PlayerY - 4, 8, 8

EndFunction

Function resizeGameCanvas()

	SetGraphics CanvasGraphics(GameCanvas)
	SetGadgetShape GameCanvas, 5, 5, ClientWidth(MainWindow) - 10, ClientHeight(MainWindow) - 10
	GameCanvas_Width = GadgetWidth(GameCanvas)
	GameCanvas_Height = GadgetHeight(GameCanvas)
	SetViewport 0, 0, GameCanvas_Width, GameCanvas_Height
	ActivateGadget GameCanvas

EndFunction

Function endApp()

	FreeGadget GameCanvas		
	End

EndFunction

Function checkPlayerPosition()

	If PlayerX >= GameCanvas_Width Then PlayerX = GameCanvas_Width
	If PlayerX < 0 Then PlayerX = 0
	If PlayerY < 0 Then PlayerY = 0
	If PlayerY >= GameCanvas_Height Then PlayerY = GameCanvas_Height

End Function


Works a treat. Thanks Simon.

Simon excelent demo dose'nt work under Linux!

I just tried this under Ubuntu Linux 7.04 and it works okay.

I had to change this line (winXP) for this to work...

Global GameCanvas:TGadget = CreateCanvas(0, 0, 0, 0, MainWindow)

to

Global GameCanvas:TGadget = CreateCanvas(0, 0, 10, 10, MainWindow)