simple userdefined controls

Previous topic - Next topic

kanonet

I created my own simple "key"-management, for user defined keys. A "key" can be a key from keyboard, mousemovement, mousebutton, joystickmovement or joystickbutton, you dont have to care about what the player use, the key-management will do all on its own. Keyboardlayouts are stored in .ini-files, i created one for us/uk and one for german keyboard, but of cause you can convert/create others for other countries (please share them with us/me!).

Its really simple to use:
1. create a new key:
Code (glbasic) Select
LOCAL attack AS Tkey

2. let the player define his key:
Code (glbasic) Select
REPEAT
PRINT "Define control for attack",0,0
SHOWSCREEN
UNTIL attack.SET()
or autoset it (usefull if you load keysettings from a ini-file):
Code (glbasic) Select
attack.SET(1, 57)and you can add a secondary/alternativ key:
Code (glbasic) Select
attack.SET(2) or attack.SET(2, 28)

3. in your mainloop, check whether the player use the key:
Code (glbasic) Select
IF attack.DOWN() THEN DOSOMETHING()This checks primary and secondary key.


TKey now informs you about keyup/-down event.:
//  0 = not pressed / nicht gedrückt
//  2 = just pressed / gerade runtergedrückt
//  1 = pressed / gedrückt (gehalten)
// -1 = release event / wieder losgelassen
Of cause it only works, if you use DOWN() in your loop...


The ini-files for us and german keyboard are attached, here is the code for the key-management:
Code (glbasic) Select
// --------------------------------- //
// Project: MyKey
// Autor: kanonet
// Start: Tuesday, February 08, 2011
// Last Update: December 6, 2012

GLOBAL KEY_mouse_sensitivity% = 2 // sensitivity of the mouse
GLOBAL KEY_joystick_sensitivity# = 0.35 // sensitivity of the joystick
GLOBAL KEY_keymap$[]
GLOBAL KEY_joystick_count% // for intern use, do not change
GLOBAL KEY_ini_file$ = "keymap_us.ini" // which INI file to read for keyboard layout


//! Type of a "key". It is possible to set a primary and a secondary "key".
//! "key" can be a key of the keyboard, a mousemovement, a mousebutton, a joystickmovement or a joystickbutton.
//! After a "key" was set with SET(), you can use DOWN() to check whether the player use it.
//? Typ eines "keys". Es ist möglich einen primären und einen sekundären "key" zu festzulegen.
//? "key" kann eine Taste der Tastatur, eine Mausbewegung, ein Mausbutton, eine Joystickbewegung oder ein Joystickbutton sein.
//? Nachdem ein "key" mit SET() gestzt wurde, kann mit DOWN() geprüft werden, ob er benutzt wird.
TYPE Tkey
code% // eventcode of the "key" if "key" is on the keyboard, code = scancode of the key
name$
code2%
name2$
state%

//! Initialise/sets the "key". Can get used as often as its needed, until played sets a "key".
//! You can change the "key" as often, as you want. You can define a alternativ "key" also.
//? Initialisiert/setzt den "key". Kann beliebig oft aufgerufen werden, bis der Spieler einen "key" gesetzt hat.
//? Ein gesetzter "key" kann beliebig oft geändert werden. Es kann außerdem auch ein alternativer "key" definiert werden.
// \param num% - Optional, use function call to set the primary (num%=1) or secondary (num%=2) "key". | Optional, mit funltionsaufruf wird der primäre (num%=1) oder der sekundäre (num%=2) "key" festgelegt.
// \param code% - Optional, only use this if you want to select a "key", not the player!  | code% - Optional, sollte nur genutz werden, wenn man selbst ein "key" setzen und dies nicht den Spieler überlassen will!
// \return 0 if no "key" was set, otherwise code% of the "key". | 0 wenn kein "key" gesetzt wurde, ansonsten code% des gesetzten "keys".
FUNCTION SET: num%=1, code%=0

LOCAL event%, name$
event=code

IF NOT code // only check for userinput if no key was specified

// check Keyboard
FOR i=1 TO 237
IF i=89 THEN i=153
IF KEY(i)
event=i; BREAK
ENDIF
NEXT


IF NOT event

// check mouse
IF MOUSEAXIS(3); event=331
ELSEIF MOUSEAXIS(4); event=332
ELSEIF MOUSEAXIS(5); event=333
ELSEIF MOUSEAXIS(0)<-KEY_mouse_sensitivity; event=301
ELSEIF MOUSEAXIS(0)>KEY_mouse_sensitivity; event=302
ELSEIF MOUSEAXIS(1)<-KEY_mouse_sensitivity; event=311
ELSEIF MOUSEAXIS(1)>KEY_mouse_sensitivity; event=312
ELSEIF MOUSEAXIS(2)>0; event=321
ELSEIF MOUSEAXIS(2)<0; event=322
ELSE
// check joystick
KEY_joystick_count%=GETNUMJOYSTICKS()-1
FOR i=0 TO KEY_joystick_count
IF GETJOYX(i)<-KEY_joystick_sensitivity; event=401+i*100; BREAK
ELSEIF GETJOYX(i)>KEY_joystick_sensitivity; event=402+i*100; BREAK
ELSEIF GETJOYY(i)<-KEY_joystick_sensitivity; event=411+i*100; BREAK
ELSEIF GETJOYY(i)>KEY_joystick_sensitivity; event=412+i*100; BREAK
ELSEIF GETJOYZ(i)<-KEY_joystick_sensitivity; event=421+i*100; BREAK
ELSEIF GETJOYZ(i)>KEY_joystick_sensitivity; event=422+i*100; BREAK
ELSEIF GETJOYRX(i)<-KEY_joystick_sensitivity; event=403+i*100; BREAK
ELSEIF GETJOYRX(i)>KEY_joystick_sensitivity; event=404+i*100; BREAK
ELSEIF GETJOYRY(i)<-KEY_joystick_sensitivity; event=413+i*100; BREAK
ELSEIF GETJOYRY(i)>KEY_joystick_sensitivity; event=414+i*100; BREAK
ELSEIF GETJOYRZ(i)<-KEY_joystick_sensitivity; event=423+i*100; BREAK
ELSEIF GETJOYRZ(i)>KEY_joystick_sensitivity; event=424+i*100; BREAK
ELSEIF GETDIGIX(i)<-KEY_joystick_sensitivity; event=431+i*100; BREAK
ELSEIF GETDIGIX(i)>KEY_joystick_sensitivity; event=432+i*100; BREAK
ELSEIF GETDIGIY(i)<-KEY_joystick_sensitivity; event=441+i*100; BREAK
ELSEIF GETDIGIY(i)>KEY_joystick_sensitivity; event=442+i*100; BREAK
ELSE
FOR j=0 TO 31
IF GETJOYBUTTON(i, j); event=451+j+i*100; BREAK; ENDIF
NEXT
ENDIF
NEXT
ENDIF

ENDIF

ENDIF

// DIM array for the keyboardlayout
IF KEY_keymap_Str.count <> 324
DIM KEY_keymap$[324]
LOCAL j=0
INIOPEN KEY_ini_file$

FOR i%=0 TO 452
IF i=238
i=301
ELSEIF i=334
i=400
ENDIF
KEY_keymap$[j]=INIGET$("keymap", i, "")
INC j
NEXT
INIOPEN ""
ENDIF

// give readable names
SELECT event
CASE 0 TO 237; name$=KEY_keymap$[event]
CASE 301 TO 333; name$=KEY_keymap$[event-63]
CASE 401 TO (KEY_joystick_count*100+482)
code=MOD(event,100)
name$=GETJOYNAME$(event/100-4)
IF name$="" THEN name$=KEY_keymap$[271]+FORMAT$(2,0,event/100-3)
SELECT code
CASE 1 TO 42; name$=name$+" "+KEY_keymap$[code+271]
CASE 51 TO 82; name$=name$+" "+KEY_keymap$[322]+(code-50)
ENDSELECT
DEFAULT; name$=KEY_keymap$[323]
ENDSELECT

// write the key on specified slot
IF num=2
IF event=self.code
event=0
name$=KEY_keymap$[0]
ENDIF
self.code2%=event
self.name2$=name$
ELSE
IF event=self.code2
event=0
name$=KEY_keymap$[0]
ENDIF
self.code%=event
self.name$=name$
ENDIF
RETURN event

ENDFUNCTION

//! Detect whether a "key" is used by the player or not.
//? Ermittelt ob ein "key" vom Spieler genutzt wird.
// \return 0 if "key" is not in use, otherwise >0. (if "key" is mouse or joystick movementspeed will be returned)  | 0 wenn "key" nicht genutzt wird, ansonsten >0. (ist "key" Maus oder Joystick, wird die Bewegungsgeschwindigleit zurück gegeben)
// \return TKey.state% will tell you, if key was used before: 0=not pressed, 2=just pressed, 1=pressed, -1=release event. | TKey.state% gibt zurück, ob key genutzt wurde: 0=nicht gedrückt, 2=gerade runtergedrückt, 1=gedrückt (gehalten), -1=wieder losgelassen.
FUNCTION DOWN:

STATIC joy, event%, KEY_joystick_sensitivity=0.2
FOR i=0 TO 1
IF i=0
event=self.code
ELSE
event=self.code2
ENDIF

SELECT event
CASE 0; joy=0
CASE 1 TO 237 // check keyboard
joy=KEY(event)
CASE 301 TO 350 // check mouse
SELECT event
CASE 301; joy=MOUSEAXIS(0)/20.; IF joy<0; joy=-joy; ELSE; joy=0; ENDIF
CASE 302; joy=MOUSEAXIS(0)/20.; IF joy<0 THEN joy=0
CASE 311; joy=MOUSEAXIS(1)/20.; IF joy<0; joy=-joy; ELSE; joy=0; ENDIF
CASE 312; joy=MOUSEAXIS(1)/20.; IF joy<0 THEN joy=0
CASE 321; joy=MOUSEAXIS(2)>0
CASE 322; joy=MOUSEAXIS(2)<0
CASE 331; joy=MOUSEAXIS(3)
CASE 332; joy=MOUSEAXIS(4)
CASE 333; joy=MOUSEAXIS(5)
ENDSELECT
CASE 401 TO (KEY_joystick_count*100+482) // check joytick
joy=MOD(event,100)
event=event/100-4
SELECT joy
CASE 1; joy=GETJOYX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 2; joy=GETJOYX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 11; joy=GETJOYY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 12; joy=GETJOYY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 21; joy=GETJOYZ(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 22; joy=GETJOYZ(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 3; joy=GETJOYRX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 4; joy=GETJOYRX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 13; joy=GETJOYRY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 14; joy=GETJOYRY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 23; joy=GETJOYRZ(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 24; joy=GETJOYRZ(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 31; joy=GETDIGIX(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 32; joy=GETDIGIX(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 41; joy=GETDIGIY(event); IF joy<-KEY_joystick_sensitivity; joy=-joy; ELSE; joy=0; ENDIF
CASE 42; joy=GETDIGIY(event); IF joy<KEY_joystick_sensitivity THEN joy=0
CASE 51 TO 82; joy=SGN(GETJOYBUTTON(event, joy-51))
DEFAULT; joy=0
ENDSELECT
DEFAULT; joy=0
ENDSELECT
IF joy THEN BREAK
NEXT
// check if key was used before
IF joy
IF self.state
self.state=1
ELSE
self.state=2
ENDIF
ELSE
IF self.state>0
self.state=-1
ELSE
self.state=0
ENDIF
ENDIF
RETURN joy

ENDFUNCTION

ENDTYPE

Please let me know what you think about this and report bugs. I dont have a real joystick/gamepad (i just used a virtual one) and my keyboard has no numpad/mediakeys, so it would be really nice if someone could test this for me. EDIT: Testing done by Ragaril, thank you!
EDIT2: small Update.
EDIT3: small Update. :P
EDIT4: there was a small typo in last Update. :-[

[attachment deleted by admin]
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Wampus

The numpad works fine. The joystick registers as expected but the gamepad controls work up to a point. One simple gamepad I have works perfectly but I also have a Logitech Dual Rumple Gamepad and all the controls work with that except the second analogue stick cannot be read as up or down. Left and right with RX- and RX+ can be read but not up and down with RY-, RY+, RZ- or RZ+ so that means can't be read at all! This isn't your routine though, its GLBasic. I suppose I should report it as a minor nuisance since the style of Gamepad I have, the type with two analogue sticks and one digital stick, is the most common for the PC.

Wampus

Oh, I also can't get the buttons to register. I've tried SET(451) upwards SET(460) because my gamepad has 10 buttons and none of them were registering.

kanonet

Thank you very much for your imput, Ragaril. :good:
There was one line of code missing... no idea how this happend... :'( Buttons should work now.
Too bad that there are problems with gamepads, if this is really 'cuz of GLB please let Kitty know about that. Can you please test if there are problems, if there is more than one joystick/gamepad in use?

----------------------------------


Updated code in first post; bugfix and new feature:
For one "key" you can now set two controls. Sometimes players like to switch between two setups.
You need two calls to define both [SET(1) and SET(2)] but both will get checked with one call of DOWN(). Look at code/comments for details.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Moru

Very nice work! I'm just missing one thing, be able to detect when user just pressed a key, just relesed the key or keeps pressing a key and return the statuscode in the same way Gernots keyhit code.

//  0 = not pressed / nicht gedrückt
//  2 = just pressed / gerade runtergedrückt
//  1 = pressed / gedrückt (gehalten)
// -1 = release event / wieder losgelassen

See this post about how to do it:
http://www.glbasic.com/forum/index.php?topic=679.0

Wampus

Yep, gamepad keys working ok now. There are no problems with another gamepad connected. Also I think I must have made a mistake before since now all four directions are working with the second analogue stick so nothing wrong with GLB.

Regarding controls, just in case its any use I wrote a routine to check for combination moves as seen in many fighting games here: http://www.glbasic.com/forum/index.php?topic=4358.0 The code is probably in dire need of optimisation because it was one of the first things I did in GLB. The basic concept of how to do it works just fine though.

kanonet

Again, thank you for all the testing work! :happy:
Nice to see, if everything works like it should do.

@Moru: I implemented what you asked for, but maybe in a different way... You will get the information not from RETURN, but its stored in TKey.state and of cause it only works, if you use DOWN() in your loop. I hope this will help you anyways? But RETURN and .state can get changed easiely, if you want that... Update is in first Post.

@Ragaril: Interessting information. But i think this is to big and to special to implement it in my functions. But i think it should be possible to use both together, if someone needs this, i can look into the code again.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Moru

#7
Nice, thanks :-)

r0ber7

I wish I had searched the forums before I started coding my own key binding routines.  :|

But, now that I've found this, I think I'll use it instead of my own. I'd have to change it a bit for it to suit into my code, but yeah. So, thanks!  :good:

bigsofty

I missed this too, thanks for bringing it to the fore.  :)
Cheers,

Ian.

"It is practically impossible to teach good programming style to students that have had prior exposure to BASIC.  As potential programmers, they are mentally mutilated beyond hope of regeneration."
(E. W. Dijkstra)

kanonet

Published a small Update:
- drastically lower memory consumption
- all settings (like mouse sensitivity etc.) can now be done in the GLOBALs on the top of the project
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64