Key Code For Canvas Games (Source Included)

BlitzMax Forums/BlitzMax Programming/Key Code For Canvas Games (Source Included)

dw817(Posted 2015) [#1]
Having decided to go with canvas-style graphics, it does open up many possibilities that cannot be done easily with standard graphics.

However, you cannot use simple keydown() routines in there. No, you must write a monster routine that keeps track of which keys are down AND up as both messages are sent now through a polling system.

Not as easy as I thought it would be.

In any case, this program I wrote works perfectly, it additionally recognizes when you use SHIFT, CTRL, and ALT for your keystrokes.

Further it has a little key repeat routine. Hold down the key and it will register only once, then again, then it will be held down until you let go.

If you are holding down a key and jump out of the frame, it will intelligently wait until you return and clear the keyboard queue so a key is not 'stuck' as many Windows games today have this problem.

Hope This Helps !

' Get Keys using Canvas
' Written by David W (dw817) 12-14-15
' GetDeskTopArea written by dan_upright

Import MaxGui.Drivers
Strict

Extern "Win32"
	Function SystemParametersInfoA:Int(action:Int, param:Int, param2:Byte Ptr, winini:Int)
EndExtern

Global a,b,c,d,e,f,g,h,i,j,kk,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
Global aa$,bb$,cc$,dd$,ee$,ff$,gg$,hh$,ii$,jj$,k$,ll$,mm$
Global nn$,oo$,pp$,qq$,rr$,ss$,tt$,uu$,vv$,ww$,xx$,yy$,zzz$
Global key:Byte[256],lastkey,keytimer,mx,my,mk
Global shiftkey,ctrlkey,altkey,arrowkey,numkey

Global deskrect[4]
GetDesktopArea(deskrect)

Global window:TGadget
Global mainview:tgadget

window=CreateWindow("",deskrect[0],deskrect[1],deskrect[2],deskrect[3],,WINDOW_ACCEPTFILES)
mainview=createcanvas(deskrect[0]-2,deskrect[1]-1,deskrect[2]+4,deskrect[3]+3,window,1)

SetGraphics canvasgraphics(mainview)
activategadget mainview
Flip
SetBlend solidblend
SetScale 10,10

Repeat
  nano
  Cls
  If k$>""
    DrawText k$,50,50
  EndIf
Until k$="es"
zz

Function zz()
  End
EndFunction
    
Function nano()
Global ce,cd,cx,cy,i
  If lastkey>0
    keytimer:+1
    If keytimer<50 And keytimer<>25
      key[lastkey]=0
    Else
      key[lastkey]=1
    EndIf
  EndIf
  If PollEvent()
    ce=CurrentEvent.id
    cd=CurrentEvent.data
    cx=EventX()
    cy=EventY()
    If ce=event_windowclose Or ce=event_appterminate
      zz
    ElseIf ce=event_keydown
      key[cd]=1
      If cd<160 Or cd>165
        lastkey=cd
        keytimer=0
      EndIf
    ElseIf ce=event_keyup
      lastkey=0
      key[cd]=0
    ElseIf ce=event_mousemove
      mx=EventX()
      my=EventY()
    ElseIf ce=event_mousedown
      mk=cd
    ElseIf ce=event_mouseup
      mk=0
    ElseIf ce=event_appsuspend Or ce=event_mouseleave
      mk=0
      For i=0 To 255
        key[i]=0
      Next
      ce=0
      Repeat
        If PollEvent()
          ce=CurrentEvent.id
        EndIf
        Flip
        Flip
      Until ce=event_mouseenter Or ce=event_appresume
      k$=""
      lastkey=0
      keytimer=0
      activategadget mainview
      Return
    EndIf
  EndIf
  shiftkey=0; ctrlkey=0; altkey=0; arrowkey=0; numkey=0
  If key[160]+key[161]
    shiftkey=1
  EndIf
  If key[162]+key[163]
    ctrlkey=1
  EndIf
  If key[164]+key[165]
    altkey=1
  EndIf
  k$=""
  For i=48 To 57
    If key[i]=1And k$="" Then k$=k$+Chr$(i);numkey=1
  Next
  For i=65 To 90
    If key[i]=1And k$="" Then k$=k$+Chr$(32+i)
  Next
  If key[8] Then k$=k$+"bs"
  If key[9] Then k$=k$+"ta"
  If key[13] Then k$=k$+"cr"
  If key[27] Then k$=k$+"es"
  If key[32] Then k$=k$+" "
  If key[33] Then k$=k$+"pu"
  If key[34] Then k$=k$+"pd"
  If key[35] Then k$=k$+"en"
  If key[36] Then k$=k$+"ho"
  If key[37] Then k$=k$+"lf";arrowkey=1
  If key[38] Then k$=k$+"up";arrowkey=1
  If key[39] Then k$=k$+"rt";arrowkey=1
  If key[40] Then k$=k$+"dn";arrowkey=1
  If key[45] Then k$=k$+"in"
  If key[46] Then k$=k$+"de"
  If key[107] Then k$=k$+"n+"
  If key[109] Then k$=k$+"n-"
  If key[186] Then k$=k$+";"
  If key[187] Then k$=k$+"="
  If key[188] Then k$=k$+","
  If key[189] Then k$=k$+"-"
  If key[190] Then k$=k$+"."
  If key[191] Then k$=k$+"/"
  If key[192] Then k$=k$+"`"
  If key[219] Then k$=k$+"["
  If key[220] Then k$=k$+"\"
  If key[221] Then k$=k$+"]"
  If key[222] Then k$=k$+"'"
  If shiftkey And k$>""Then k$="#"+k$
  If ctrlkey And k$>""Then k$="^"+k$
  If altkey And k$>""Then k$="@"+k$
  If k$="^q"Or k$="es"Then zz
  Flip
  Flip
EndFunction

Function getdesktoparea(lprect:Int Ptr)
	systemparametersinfoa(spi_getworkarea,0,lprect,0)
End Function


Questions, comments, compliments, or kerosene, take your pick and lemme know !
:)


kfprimm(Posted 2015) [#2]
If you call EnablePolledInput(), the KeyUp/KeyDown functions should work.

https://github.com/blitz-research/blitzmax/blob/master/mod/brl.mod/polledinput.mod/polledinput.bmx#L87

Also, no need to invoke SystemParametersInfo. Use DesktopWidth() and DesktopHeight().


Kryzon(Posted 2015) [#3]
For PolledInput to work really lightweight with MaxGUI you need to change the "autoPoll" private global to False. Then rebuild this brl.polledinput module.

Then you can call EnablePolledInput() or EnablePolledInput( canvas ) (the latter only processes input events when they come from the canvas gadget).

Then you can use KeyDown and KeyHit inside some polled updating code, usually hooked to a timer set to some frequency like 30 FPS.
Besides animations and AI, you'll also process user input there. Just remember to add a PollSystem call to this main updating function before using KeyDown or KeyHit, so any pending input events are processed.

EDIT: Example of all this below, in post #5.


dw817(Posted 2015) [#4]
Kfprimm:

* Tried the code of "polledinput." Doesn't seem to be getting what I want. Could you please post a working example of a held key that vanishes using canvas screen ?

The desktopwidth() and company are used because I want to know the exact size of the screen minus the taskbar. If this can be done minus a library, I'm all for it.

Kryzon:

* I'm getting some screwy timing when I try enablepolledinput() and hold down a key for a few seconds. When I let go of the key, a message appears it was released a quarter of a second later.

I'll need to stick to my code above which does handle all instances if there isn't a simpler solution out there.

Or can you post an example program to demonstrate where it works in all instances, key tapped, or held ?


Kryzon(Posted 2015) [#5]
Run this program and press the SPACE key. And note the module modifications at the top.




dw817(Posted 2015) [#6]
Okay, before we go too far, Kryzon, you are using:

D3D9Max2DDriver()

Does this have any advantage over

graphics 1024,768

or

CreateCanvas ?

I am using CreateCanvas because in my program I want to be able to drag an image from off of the Internet Window (using CreateHTMLView) and read it in my program.

What precisely is the difference between all 3, and does D3D9Max have any advantage over any other graphic mode ?

Is it faster in terms of lockimage, better, more compatible to graphic cards ? Explain.


Kryzon(Posted 2015) [#7]
Do you mean, explain please?

You need to get acquainted with the Max2D module and its drivers.
CreateCanvas is like a call to Graphics, but instead of creating a window as a display, it creates a panel gadget as a display.
You can fit this panel inside other windows and panels.

If your program is running on Windows, the Direct3D 9 renderer is more likely to have a better performance.


dw817(Posted 2015) [#8]
Sorry, please. :7 I was getting so wordsworthy in there.

I guess I need to clarify something. BlitzMAX and the command FLIP create smooth graphics that use little CPU.

The last time I tried BlitzBasic it staggered all over the place, no smooth motions, and pegged my CPU at 50% for what appeared to be simple animations. Is this still the case please, Kryzon - or should I abandon BlitzMAX ?


Kryzon(Posted 2015) [#9]
I think it's more important to know why it staggers. In the end it's all instructions given to the machine, and if something is staggering then the instructions are causing or telling the machine to do so.
If you're not interested in the internals maybe you should get a higher level engine -- that is, something that expects you to program game behaviour, rather than lower-level things like frame rate control, rendering etc. I don't mean this in a condescending way; some people prefer some tools etc. I myself only use BlitzMax to make quick utilities for me.

Depending on the circumstances the Flip function in BlitzMax does some frame rate control, releasing free time to the CPU. I know this because I looked at the module source code; anyone can do it too.
This isn't exclusive to BlitzMax, you can do this Flip behaviour with other game engines, even Blitz3D.


dw817(Posted 2015) [#10]
Does Blitz3D internalize files too as BlitzMAX does ? I can currently use in BlitzMAX:

global ib$="system\"
?Not debug
ib$="incbin::"
Incbin "media\bgm\$Good Night 1.ogg"
Incbin "media\bgm\$Item 1.ogg"
Incbin "media\bgm\Adventure 1.ogg"
Incbin "media\bgm\Editor.ogg"
Incbin "media\bgm\Village 1.ogg"
Incbin "media\data\edit.var"
Incbin "media\data\Home.var"
Incbin "media\data\newgame.var"
Incbin "media\fog\001-Fog01.jpg"
Incbin "media\fog\003-Shade01.jpg"
Incbin "media\font\Def_20.ttf"
Incbin "media\font\Game_26.ttf"
Incbin "media\font\Title_26.ttf"
Incbin "media\sfx\001-System01.ogg"
Incbin "media\sfx\002-System02.ogg"
Incbin "media\sky\003-StarlitSky01.jpg"
Incbin "media\sky\004-CloudySky01.jpg"
Incbin "media\sys\Cbbgs_256x64x44.png"
Incbin "media\sys\Circle.png"
Incbin "media\sys\Critters_64x64x176.png"
Incbin "media\sys\Energy_128x128x4.png"
Incbin "media\sys\Faces_64x64x176.png"
Incbin "media\sys\Frame.png"
Incbin "media\sys\Glow_200x200x15.png"
Incbin "media\sys\IconSet_24x24x256.png"
Incbin "media\sys\Pick The Tile.png"
Incbin "media\sys\Pick Tile Set.png"
Incbin "media\sys\Sprites_32x32x512.png"
Incbin "media\sys\SysFont_8x8x512.png"
Incbin "media\sys\SysIcons_32x32x64.png"
Incbin "media\sys\Tile Cursor.png"
Incbin "media\sys\Tile Grid.png"
Incbin "media\sys\Tiles_32x32x736.png"
Incbin "media\sys\Torchlit Editor.png"
Incbin "media\sys\Torchlit.png"
Incbin "media\sys\Vector.png"
Incbin "media\sys\View Port.png"
?


And depending upon whether or not I am running in debug or final release, I can read these files internally, graphic, text, and audio, effectively protecting and hiding them.

And does Blitz3D allow you to read and write individual pixels ? I do quite a bit of that in my work.

I admit I am at a complete loss of understanding 3D graphics. I wrote THIS:
Strict
Global i,Global img:TImage=LoadImage("dogs.jpg")
Graphics 1024,768
For i=0 To 383
  SetScale .5+i/1024.0,1
  SetViewport 0,192+i,1024,1
  DrawImage img,384-i/4.0,192
Next
Flip
WaitKey


Find test image HERE:
https://lh4.ggpht.com/pYJ0w6Sy2wzZjuSSTAtCl5TtnQwT1PkUIckiIlYUequ-y61822Yf0PS6wei3k_bG68Q=h900

As a crude way of tilting an image. It works but the scaling looks off. I'd love it if I could really write a true 3D dungeon with custom images for walls that stays on a tight grid like a tiled RPG instead of all the loose movement I've seen in other 3D dungeon example programs.

But I wouldn't want to be locked down to a programming language where everything is polygonal and I have no other options. I need my pixels, scaling with blur, Truetype Fonts, and CreateHTMLView.

It seems if I adopt one programming language over another, I sacrifice the abilities I am familiar with, Kryzon.

Please comment. Which do you think is the best of all of these worlds, Kryzon ?