Keybinds

Posted By: Kartoffel

Keybinds - 07/22/16 13:13

Does anyone know a good approach for implementing keybinds?

I already have an idea but there's probably a much better solution.
Posted By: WretchedSid

Re: Keybinds - 07/22/16 13:25

Lookup table if you want to poll, lookup table with function pointers if you want to have callbacks.
Posted By: Anonymous

Re: Keybinds - 07/22/16 13:28

^-- Or that --- Yes definitely THAT!

Str_for_key to ->>TEXT
key_for_str return ->> scancode to array[max_key-in_order]

Key_hit / key_pressed / key_lastpressed /key_any combinations for the rest.
Posted By: Kartoffel

Re: Keybinds - 07/22/16 13:37

@JustSid:
So you mean I create an array of bytes/ints (whichever I need) where each element represents one key of the keyboard (keycode = index) to store an id to what that keyshould do? Sounds good

I thought about it the other way around. Storing the corresponding keycode for each action (jump, walk left, walk right, etc.) and scanning that key everytime the action is needed (or scanning the keys for all actions at the start of each frame and storing the results using a struct).

Edit: I just have to think about how to do this in acknex... afaik there's no function that takes a keycode and returs whether or not this key is pressed.

Edit2: I'll probably go for the windows api and do that stuff myself. Not sure about gamepad input, though.
Posted By: Anonymous

Re: Keybinds - 07/22/16 13:47

Key_hit from keys.c

opps maybe keycode and scancode are different.. Sorry, I'm in over my head and up too many hours awake.
Posted By: Kartoffel

Re: Keybinds - 07/22/16 13:53

@Malice: cool thanks! didn't know about that one (let's hope it actually includes at least most keyboard buttons or otherwise.. winapi)

Edit: google just told me most keyboards have ~104 keys and since acknex is using an array with 256 indices for keypresses it really includes all of them I guess.

keycode, scancode...
Well, I meant the same thing as you. But no idea if there's an actual difference between those two lol
Posted By: WretchedSid

Re: Keybinds - 07/22/16 15:15

Actually I meant that you have a table with an entry for every action that a key can be bound to and then the keycode for the key that is bound to that action. Then you can just poll the corresponding entry if/when needed.

Key binding itself is then as simple as:
Wait for any input
Update the slot in the lookup table

And tada, your keybinding has O(1) lookup time.

Something like this (pseudo-pseudo code):
Code:
enum Action
{
   WalkForward,
   Jump,

   __Max
}

KeyCodeType LookupTable[Action::__Max] = { 0 };

void BindKeyToAction(Action action)
{
   KeyCodeType input = GetNextKeyPress();
   LookupTable[action] = input;
}

void GameLoop()
{
   while(1)
   {
      if(HasInput(LookupTable[Action::Jump])
         Jump();
   }
}

Posted By: Kartoffel

Re: Keybinds - 07/22/16 16:59

@JustSid: oh okay, so it's pretty close to what I had in mind at first. However, I think I'll do the polling once every frame for all actions, store the data in a struct and pass it to the game Logic function(s).

Thank you two again for your help.
Posted By: txesmi

Re: Keybinds - 07/22/16 17:09

Are not events on_a, on_b, etc key binds already? Do I missundestood something?
Posted By: Reconnoiter

Re: Keybinds - 07/22/16 17:31

Originally Posted By: txesmi
Are not events on_a, on_b, etc key binds already? Do I missundestood something?
, I think he means customizable keybindings for e.g. player controls (like e.g. default would be WASD for movement but than an user could change it to the arrow keys).

I personally use this method now (super easy to setup and seems to work great): http://www.opserver.de/ubb7/ubbthreads.php?ubb=showflat&Number=188074
However it does not support the mouse(!). But some extra sliders and buttons for some presets could sort of fix that (I think grin ).
Posted By: Kartoffel

Re: Keybinds - 07/22/16 17:58

Well, I'm not a big fan of the on_...-events and I don't think that there's an event for all keys on a normal Keyboard.

Using a custom input system seems more elegant and cleaner to me.

@Reconnoiter: The method I'm going to use is similar to the one you posted. However, I think using strings as keycodes adds unnecessary complexity (parsing the string on every poll...) and makes it harder to implement actual ingame binding (which is important to me aswell).

Edit: I just saw that theres a reverse function for key_for_str() (str_for_key(), I searched for key_to_str()...)
So ingame binding with your method wouldn't be a problem. But it's still just wasted performance imo.. going from the scancode to the key-string just to do the reverse for every key poll crazy
Posted By: Reconnoiter

Re: Keybinds - 07/22/16 19:29

Originally Posted By: Kartoffel
@Reconnoiter: The method I'm going to use is similar to the one you posted. However, I think using strings as keycodes adds unnecessary complexity (parsing the string on every poll...) and makes it harder to implement actual ingame binding (which is important to me aswell).

Edit: I just saw that theres a reverse function for key_for_str() (str_for_key(), I searched for key_to_str()...)
So ingame binding with your method wouldn't be a problem. But it's still just wasted performance imo.. going from the scancode to the key-string just to do the reverse for every key poll crazy
, does your method allow modifying mouse buttons? (if so could you post a simple example how you do it now? (pretty please with sugar ontop))
Posted By: txesmi

Re: Keybinds - 07/22/16 19:54

you have all the key related variables sorted by scancode into arrays already.

Code:
int _i = 1;
for ( ; _i<89; _i+=1 )
{
	key_set ( _i, myEvent );
	if ( *(&on_esc+_i-1) != myEvent )
		error ( str_cat ( str_for_key ( NULL, _i ), " is not into an array???" ) );
	key_set ( _i, NULL );
}

while ( !key_esc )
{
	for ( _i=1; _i<89; _i+=1 )
	{
		if ( *(&key_esc+_i-1) == 1 )
			draw_text ( str_cat ( str_for_key ( NULL, _i ), " key pressed" ), 10, 10, COLOR_WHITE );
	}
	wait(1);
}



but those arrays are not public and due to engines frequent updates and constant evolution use these things is a high risk [buahahaha]

Anyway, if it is a matter of customization, you can use pointers for actions.

Code:
var *keyUp = &key_w;
...
if ( *keyUp ) {...}



Quote:
I don't think that there's an event for all keys on a normal Keyboard.

there are...
Posted By: Kartoffel

Re: Keybinds - 07/22/16 20:24

Quote:
but those arrays are not public and due to engines frequent updates and constant evolution use these things is a high risk [buahahaha]
shots fired laugh

@Reconnoiter: I haven't even started writing the code but it shouldn't be too different when using mouse buttons...
Posted By: Reconnoiter

Re: Keybinds - 07/22/16 21:46

@txesmi, ty!

Originally Posted By: txesmi

but those arrays are not public and due to engines frequent updates and constant evolution use these things is a high risk [buahahaha]
, [black van stopping at the door]
Posted By: JackPell

Re: Keybinds - 07/22/16 23:37

I have an init_keys() function that loads the scan codes for the control keys from external file and set them to variables with meaningful names (like key_jump_scan, key_shoot_scan .. etc.) ,then update_keys() that runs every frame that sets the state of every key to another kind of variable (like: key_jump, key_shoot ... etc.) using key_pressed(scan_code) function:

Code:
while(1)
{
   ...
   key_jump = key_pressed(key_jump_scan); //key_jump_scan was already set to the scan code of the desired key in the previous init_keys() function
   
   ...
   wait(1);
}



Then, inside the main code that controls whatever kind of key-based behaviour, i use the key_something variable like:

Code:
...
movement_speed.x = (key_forward-key_backward)*10*time_step;
...

Posted By: Anonymous

Re: Keybinds - 07/22/16 23:57

Key_pressed with the -1 ability and also key_pressed to key_lastpressed and key_any(x) == X and also the key_hit.

But if you have the pre-mapped key in a array if(i[0]) jump and if(i[1]) walk
then you can remap by recording on the menu page the replacement string i[0]=key_for_str() then forever cycle your array in each frame. But remember to reset key_pressed with the -1 where needed or compare to key_last where needed. And key any() actually helps at times.

Posted By: Kartoffel

Re: Keybinds - 07/23/16 17:31

another related question:

Does anyone know how to get the input from a gamepad's d-pad?
Posted By: alibaba

Re: Keybinds - 07/24/16 04:09

I'm using superKu's Xinput dll
Posted By: Kartoffel

Re: Keybinds - 07/24/16 08:58

Originally Posted By: alibaba
I'm using superKu's Xinput dll
yes, I'm using this one, too (thanks again, superku smile)

However, I also want to support older DirectInput game controllers...
Posted By: Anonymous

Re: Keybinds - 07/24/16 09:45

If I remember - acknex uses 12 up to 32 buttons on the joy and 4 are the dpad.
In the past to get the button numbers i believe I used a calibration app in the windows control panel.

You should be able to use a function to debug_var the joy button numbers.

Check out joy button http://www.conitec.net/beta/joy_buttons.htm
And joy_pressed in key.c
Posted By: Kartoffel

Re: Keybinds - 07/24/16 09:56

I already tested it, the dpad is not included in these 12 buttons.
They only include: 4 buttons on the right (ABXY), 4 shoulder buttons, 2 in the middle (Select/Start) and the 2 thumbstick-buttons
Posted By: Anonymous

Re: Keybinds - 07/24/16 10:01

Hummm... Well there is 32 . LOL then it's joy_hat http://www.conitec.net/beta/ajoy_hat.htm

Edits to come
Posted By: Kartoffel

Re: Keybinds - 07/24/16 10:04

you're right, thanks a lot laugh

but instead of using two variables they used one which stores the angle of the dpad... weird stuff
Posted By: Kartoffel

Re: Keybinds - 07/24/16 10:21

a bit hacky but if anybody needs it:
Code:
#define joy_dpad_up (joy_hat != -1 && (joy_hat < 67.5 || joy_hat > 292.5))
#define joy_dpad_down (joy_hat != -1 && joy_hat > 112.5 && joy_hat < 247.5)
#define joy_dpad_left (joy_hat != -1 && joy_hat > 202.5 && joy_hat < 337.5)
#define joy_dpad_right (joy_hat != -1 && joy_hat > 22.5 && joy_hat < 157.5)

#define joy2_dpad_up (joy2_hat != -1 && joy2_hat < 67.5 || joy2_hat > 292.5)
#define joy2_dpad_down (joy2_hat != -1 && joy2_hat > 112.5 && joy2_hat < 247.5)
#define joy2_dpad_left (joy2_hat != -1 && joy2_hat > 202.5 && joy2_hat < 337.5)
#define joy2_dpad_right (joy2_hat != -1 && joy2_hat > 22.5 && joy2_hat < 157.5)

the only problem left is that gamepads without a d-pad seem to always have joy_hat = 0... (which would be dpad-up)
Posted By: Anonymous

Re: Keybinds - 07/24/16 10:44

No they should have a value of joy_hat == -1; or otherwise 'centered'

If not --->> That's a bug.
Posted By: Kartoffel

Re: Keybinds - 07/24/16 11:28

well the center position is -1... but on my second gamepad (which has no dpad) joy_hat is always 0. However, there are no problems in any games I played with it, yet. smirk
Posted By: Anonymous

Re: Keybinds - 07/24/16 12:03

Well just speaking from general programming logic [Not that I can say much], 0 should not be a valid value and a returned value for the detection of an invalid.

0/1 are common returns for valid/invalid -success/fail but 0 than is both up and invalid in this case. That's kind of poor logic even to a half-a** code want-to-be like me...
Posted By: Kartoffel

Re: Keybinds - 07/24/16 14:07

Yeah, but this might be a problem with direct input itself and not the implementation.

Anyway... thinking about it, a simple workaround would be disabling the dpad's input on startup and only enabling it after the dpad is centered (joy_hat == -1)
Posted By: Kartoffel

Re: Keybinds - 07/24/16 14:42

Okay, so if anyone needs it this one gets the job done:
Code:
#define joy_available (num_joysticks >= 1)
#define joy_dpad_center (joy_available && joy_hat == -1)
#define joy_dpad_up (joy_available && joy_dpad_available && joy_hat != -1 && (joy_hat < 67.5 || joy_hat > 292.5))
#define joy_dpad_down (joy_available && joy_dpad_available && joy_hat != -1 && joy_hat > 112.5 && joy_hat < 247.5)
#define joy_dpad_left (joy_available && joy_dpad_available && joy_hat != -1 && joy_hat > 202.5 && joy_hat < 337.5)
#define joy_dpad_right (joy_available && joy_dpad_available && joy_hat != -1 && joy_hat > 22.5 && joy_hat < 157.5)

#define joy2_available (num_joysticks >= 2)
#define joy2_dpad_center (joy2_available && joy2_hat == -1)
#define joy2_dpad_up (joy2_available && joy2_dpad_available && joy2_hat != -1 && joy2_hat < 67.5 || joy2_hat > 292.5)
#define joy2_dpad_down (joy2_available && joy2_dpad_available && joy2_hat != -1 && joy2_hat > 112.5 && joy2_hat < 247.5)
#define joy2_dpad_left (joy2_available && joy2_dpad_available && joy2_hat != -1 && joy2_hat > 202.5 && joy2_hat < 337.5)
#define joy2_dpad_right (joy2_available && joy2_dpad_available && joy2_hat != -1 && joy2_hat > 22.5 && joy2_hat < 157.5)

byte joy_dpad_available = false;
byte joy2_dpad_available = false;

// no need to call this function yourself!! the engine will do this automatically on startup due to the '_startup' suffix
void __joy_dpad_check_startup()
{
	if(num_joysticks <= 0) // no direct input game controllers connected
		return;
	
	while(!joy_dpad_available || (joy2_available && !joy2_dpad_available))
	{
		if(joy_dpad_center) joy_dpad_available = true;
		if(joy2_dpad_center && joy2_available) joy2_dpad_available = true;
		
		wait(-1);
	}
}

Note that it only checks if a dpad is available every second. If you want it to check every frame you can use wait(1) instead.

edit#3: oops, forgot that there's no 'bool' in standard lite-c so I changed it to byte
also added some safety checks that prevent joy_dpad_up to be true when no gamepad is connected
© 2024 lite-C Forums