Key remapping system?

E

elsi11

Guest
Hey guys!

I am trying to make a key remapping system, and this is what I have for now. (0) Please tell me which parts are good, and which need changing:
Code:
//STEP

if (keyboard_check_pressed(vk_enter) && !change)
{
    change = 1;
    io_clear();     //prevents haxx with people holding down buttons while we "listen"
                    //clears all input so the next pressed button is the one we use
}

if (change && keyboard_check_pressed(vk_anykey))    // (1) what about controller?
{
    lastkey = keyboard_lastkey;
    keyboard_lastkey = -1;
    change = 0;
}

//DRAW

draw_text(10,10,chr(lastkey));      //chr() gives you a letter instead of number, works with most letters
if (change)
{
    // (2) dimming the screen here would be nice. How do?
    draw_text(view_hview[0]/2,view_wview[0]/2,"assign new key");
}
(3) Where do I find that list of numbers that I need to convert numbers into readable keys? How do I draw it on screen? Do I convert "lastkey" to a string as soon as I get it? The numbers are ascii, right? But chr() gives me random characters for the arrow keys, and nothing for enter and special letters.

(4) Do I have to have some special code for controllers? I don't mind if a generic controller gives me a number instead of "button X", as long as it works. I know people always have problems with controllers and gamemaker games.

(5) Should I have a special key that is constant? Like: enter is always the key for editing a key. But it is kinda meh. But, then again, if someone changes his key to some cyrillyc letter that is alien to modern computing, and then forgets which one he assigned, and he only sees a number or maybe even nothing, and the key he messed up is THE key for changing assignements, what then? Put a disclaimer that you can manually change assignments in the settings file? But again, the game might not recognize a random hieroglyph. Maybe have a special button like F12 or something that resets everything to default, and you have to press it 5 times or smt. But what about people who have a controller? Hardcode the x360 controller to have up button presed for x seconds? What about generic controllers? What If I play the game with a guitar hero guitar? How do you do it?

In short: Please help me make a working key remapping system where if I assign space, it will tell me "Space".

Tnx!
 
W

Whirlpoolio

Guest
Hey guys!

I am trying to make a key remapping system, and this is what I have for now. (0) Please tell me which parts are good, and which need changing:
Code:
//STEP

if (keyboard_check_pressed(vk_enter) && !change)
{
    change = 1;
    io_clear();     //prevents haxx with people holding down buttons while we "listen"
                    //clears all input so the next pressed button is the one we use
}

if (change && keyboard_check_pressed(vk_anykey))    // (1) what about controller?
{
    lastkey = keyboard_lastkey;
    keyboard_lastkey = -1;
    change = 0;
}

//DRAW

draw_text(10,10,chr(lastkey));      //chr() gives you a letter instead of number, works with most letters
if (change)
{
    // (2) dimming the screen here would be nice. How do?
    draw_text(view_hview[0]/2,view_wview[0]/2,"assign new key");
}
(3) Where do I find that list of numbers that I need to convert numbers into readable keys? How do I draw it on screen? Do I convert "lastkey" to a string as soon as I get it? The numbers are ascii, right? But chr() gives me random characters for the arrow keys, and nothing for enter and special letters.

(4) Do I have to have some special code for controllers? I don't mind if a generic controller gives me a number instead of "button X", as long as it works. I know people always have problems with controllers and gamemaker games.

(5) Should I have a special key that is constant? Like: enter is always the key for editing a key. But it is kinda meh. But, then again, if someone changes his key to some cyrillyc letter that is alien to modern computing, and then forgets which one he assigned, and he only sees a number or maybe even nothing, and the key he messed up is THE key for changing assignements, what then? Put a disclaimer that you can manually change assignments in the settings file? But again, the game might not recognize a random hieroglyph. Maybe have a special button like F12 or something that resets everything to default, and you have to press it 5 times or smt. But what about people who have a controller? Hardcode the x360 controller to have up button presed for x seconds? What about generic controllers? What If I play the game with a guitar hero guitar? How do you do it?

In short: Please help me make a working key remapping system where if I assign space, it will tell me "Space".

Tnx!
I'm not really an expert in this stuff but when I was learning, I watched SlasherX's tutorials and he did a big stream which had remapping keys and if I'm not mistaken, he also did a video on it. This may help you, sorry I'm not any good at this! ;)
 
F

float

Guest
I was supposed to say vk_* constants but seems like you know them already. You can't automagically convert them to strings (vk_up does not become "keyboard up") what you can do is use a switch event, or maybe a ds_map. And for gamepad there are different functions for that, separate from the keyboard events.

Code:
//like so
map = ds_map_create();
ds_map_add(map,vk_left,"Keyboard Left");
ds_map_add(map,vk_right,"Keyboard Right");
ds_map_add(map,vk_up,"Keyboard Up");
ds_map_add(map,vk_down,"Keyboard Down");
ds_map_add(map,vk_enter,"Enter");
ds_map_add(map,vk_escape,"Escape");
ds_map_add(map,vk_f1,"Keyboard F1");
ds_map_add(map,vk_numpad0,"Num0");

out = ds_map_find_value(map,keyboard_lastkey);
if !is_undefined(out){
    show_message(out);
} else {
    show_message("Erro, key not recognized");
}
 
Last edited by a moderator:
E

elsi11

Guest
Can virtual keyboard constants also be written as numbers, like the rest of the buttons? I thought, If I need a database of every single letter (because chr() doesn't recognize banana characters with accents), I might aswell do it with every button. Do keyboards have a similar number of keys? Does the letter Z on a qwertz keyboard, and the letter Y on a qwerty keyboard have the same number? Where can I find a list of those numbers? Am I supposed to write up a script and log every button and see which number it gives me :p ? What if a keyboard has more buttons or some random fifth button above shift? What number does it get? How do those numbers work?

I tried to peek at some game codes I got from a humble bundle but, like always, other peoples games are literally unreadable xD
 

hogwater

Member
As I understand it, you can use keyboard_key to get the real number associated with a key on your keyboard. However it may not be the same on every keyboard. So you just have to pick the most common standard for where you will release the game and hope for the best.

I believe this would allow most anyone to map any key they press, but your in-game description would only be accurate for the standard that you choose.
 

Hyomoto

Member
It's questions like these that have made me decide it would be worthwhile to release a personal asset I use a lot. The simplest answer is you could save the key as a variable, and then simply call that:
Code:
myKey = vk_space;

if keyboard_check( myKey ) { //do }
This is as simple as a reassignment of keys can possibly get. But to be honest, controls are one of those things people overlook because it seems so simple: "hey, just check the key!" Well, what if you have two objects that both respond to the same key press. For example, you pause the game and now there is a menu on screen. What should respond to your key presses? What if you want both keyboard and gamepad support? What if you want mouse controls? Should the joystick behave like the control pad? Suddenly just handling controls can become very complex, very quickly. Not to mention the overhead of having a bunch of objects having to check control states each step. And ironically, I've never seen someone provide a particularly good solution to this problem, because to really solve this, you would need a very comprehensive solution.

However, to answer your most recent question: when it comes to multiple keyboard layouts it doesn't matter. Even keyboards in Japan have english key equivalents. A DVORAK keyboard still returns the same inputs as a QWERTY or AZERTY keyboard, these are all ASCII and UNICODE values, which are standard across most of computing. It was decided a long time ago that it would be awfully inconvenient to have to account for every possible type of keyboard out there, so by the type it reaches Windows or GM, the key has been identified as a common identifier (which is a number). Now, some keyboards don't have numpads, for example, so it's always possible a keyboard may be lacking a key, but you don't need to worry about the Z key being a Y key on someone else's keyboard unless they've intentionally moved that key. At which case, you'd be insane to try to cater to hypothetical people.
 
If you're looking to get input up and running quickly, I like to use Input Dog, a free extension on the YoYo MarketPlace.

https://marketplace.yoyogames.com/assets/243/input-dog

It supports keyboard and controllers, multiple players, and has a demo room setup to handle remapping.

It's made for GMS 1.4, but I've found it can be imported into GMS 2 automatically as well.

At the least, you could check to see how they handle remapping for an example of how to do it.
 
E

elsi11

Guest
Input dog seemed to do the trick. It uses a system where it first converts the input to chr(), and then runs through all the vk_constants in a switch statement. That's good enough for now, I guess. That's the answer I was searching for. I'll try to bug it out to see the possible problems. Later I can fiddle with gamepad controls.

Tnx!

Edit:
I found a weird thing where it won't give me any string if I check for vk_alt, but it will give me if I have vk_lalt and vk_ralt, even though it says on wiki that left and right ctrl, shift and space constants "can only be used with keyboard_check_direct():"
So I have no idea what's up with that.
AND a major discovery: If you put the button numbers into the switch, you can even have odd keys that gamemaker doesnt have a constant for like tab and tilde. I used nr 192 and gave it the "tilde" string, and used nr 9 for tab and gave it the "tab" string, and they both work. That means we can map every possible key.

Edit2:
And now I used 160, 162 and 164 for shift, ctrl and alt, and they all worked. Should I just use numbers? Is there some benefit to using vk_something since it handles only a few keys, besides readability? Is switch the best way to do it (case 192: return "tilde"; break;) ? I jsut had an idea. What if you made an array, and every corresponding number carries a string like: array[192] = "tilde". That way, you wouldn't have to iterate through billions of lines. Any comments on that? :p
 
Last edited by a moderator:
It's a good idea, but don't focus too heavily on how many lines the switch has and spend a lot of time trying to optimise it. 99% of the time the speed increase you get from heavily optimising something like that is far outweighed by the time you could've spent being genuinely productive in creating new content for your game, so just find something that you feel comfortable with, plop it in and don't worry about optimisation until you literally hit a point where that specific code is causing noticeable slowdown in your game.
 
E

elsi11

Guest
It's a good idea, but don't focus too heavily on how many lines the switch has and spend a lot of time trying to optimise it. 99% of the time the speed increase you get from heavily optimising something like that is far outweighed by the time you could've spent being genuinely productive in creating new content for your game, so just find something that you feel comfortable with, plop it in and don't worry about optimisation until you literally hit a point where that specific code is causing noticeable slowdown in your game.
Yea, you are right. There are lots of unused or unnecessary numbers in the virtual keyboard system. I got my info from here http://cherrytree.at/misc/vk.htm
Here is my script for people to use if they want. I put in a bunch of buttons people will never use, but didnt put in buttons people will absolutely never ever use - like the printscreen or calculator button. I ordered the switch by chance of a key being used.
Maybe I should also put in an if statement which checks if the number is between 48 and 90 (0 - Z), and just skip the whole switch in that case. I'm not sure which set of buttons chr() encompasses, but I guess it would be ok enough. What do you think?

Here it is:
Code:
///scr_keycodes(last key)
var key = argument0;
char = chr(key);
if (key < 48 && key > 90) //buttons 0 to Z
{
    switch(key)
    {
        case vk_left: return "LEFT"; break;
        case vk_right: return "RIGHT"; break;
        case vk_up: return "UP"; break;
        case vk_down: return "DOWN"; break;
     
        case vk_lcontrol: return "L CTRL"; break;
        case vk_rcontrol: return "R CTRL"; break;
        case vk_space: return "SPACE"; break;
        case vk_lshift: return "L SHIFT"; break;
        case vk_rshift: return "R SHIFT"; break;
        case vk_lalt: return "L ALT"; break;
        case vk_ralt: return "R ALT"; break;
        case vk_enter: return "ENTER"; break;
        case vk_escape: return "ESC"; break;
 
        case 8: return "BACKSPACE"; break;
        case 9: return "TAB"; break;
        case 20: return "CAPS LOCK"; break;
     
        case 1: return "MOUSE LEFT"; break;
        case 2: return "MOUSE RIGHT"; break;
        case 4: return "MOUSE MID"; break;
        case 5: return "MOUSE X1"; break;
        case 6: return "MOUSE X2"; break;
     
        case vk_numpad0: return "NUM 0"; break;
        case vk_numpad1: return "NUM 1"; break;
        case vk_numpad2: return "NUM 2"; break;
        case vk_numpad3: return "NUM 3"; break;
        case vk_numpad4: return "NUM 4"; break;
        case vk_numpad5: return "NUM 5"; break;
        case vk_numpad6: return "NUM 6"; break;
        case vk_numpad7: return "NUM 7"; break;
        case vk_numpad8: return "NUM 8"; break;
        case vk_numpad9: return "NUM 9"; break;  
       
        case 33: return "PAGE UP"; break;
        case 34: return "PAGE DOWN"; break;
        case 35: return "END"; break;
        case 36: return "HOME"; break;
        case 45: return "INSERT"; break;
     
        case vk_decimal: return "."; break;
        case vk_delete: return "DELETE"; break;
        case vk_add: return "+"; break;
        case vk_subtract: return "-"; break;
        case vk_multiply: return "*"; break;
        case vk_divide: return "/"; break;
     
        case 144: return "NUM LOCK"; break;
        case 145: return "SCR LOCK"; break;
     
        case 186: return "';:' (US)"; break;
        case 187: return "'+' (US)"; break;
        case 188: return "',' (US)"; break;
     
        case 189: return "'-' (US)"; break;
        case 190: return "'.' (US)"; break;
        case 191: return "'/?' (US)"; break;
        case 192: return "TILDE"; break;
     
        case 219: return "'[{' US"; break;
        case 220: return "'\|' US"; break;
        case 221: return "']}' US"; break;
        case 222: return "QUOTE US"; break;
     
        case 112: return "F1"; break;
        case 113: return "F2"; break;
        case 114: return "F3"; break;
        case 115: return "F4"; break;
        case 116: return "F5"; break;
        case 117: return "F6"; break;
        case 118: return "F7"; break;
        case 119: return "F8"; break;
        case 120: return "F9"; break;
        case 121: return "F10"; break;
        case 122: return "F11"; break;
        case 123: return "F12"; break;
    }
}
return char;
Haven't tried it yet, though :p
 
Last edited by a moderator:

kburkhart84

Firehammer Games
In my FHInput extension, I actually had to take the time to map out all of those constants. Instead of using the 'vk_' constants, I just directly use the numbers themselves at a certain point, meaning I literally test for all 256 possible keys(except some of the first couple dozen that don't apply to anything, or in GMS actually check the mouse buttons for whatever reason, or work as a combination of left/right shift/alt/control). Since some of those numbers are for things like media keys on some people's keyboards, I just had to write something like "undefined" for the description. In any case, the key still works if the player wants to use it, you just can't get a proper description, and if you could, it would probably be different for other keyboards anyway.

BTW, you can look up some documentation(typically for other languages like C++). I've used those references to figure out what most of the keycode/key combinations are. Those keycodes are an actual standard used everywhere, which includes gamemaker(since it boils down to using the same code underneath anyway).
 

Yal

🐧 *penguin noises*
GMC Elder
I second the "use variables" approach, that's what I do myself. It also makes gamepad support really easy... have an "input source" variable (keyboard, gamepad1, gamepad2, ...) and when you read key status, call gamepad functions instead of keyboard_check(). Since input status is now independent of what the player uses to control the game, adding new hardware support is really easy.

Also, you'll probably eventually run into an "now I want to track keypresses and key releases too, not just the current key status" issue. That's pretty easy to solve by just adding a second variable for each input, which is a counter of how long each key has been pressed. My input processing script looks something like this:
upload_2017-11-12_15-26-53.png
Basically, the p_* variables is the Pressed status, the k_* variables is the Key status. I use these EVERYWHERE in my code, that's why the names are so short :p
To check if a key is pressed this step, you'd e.g. check if(k_a && !p_a); to check if a key was released this step, you'd check if(!k_a && p_a).
 
E

elsi11

Guest
I second the "use variables" approach, that's what I do myself. It also makes gamepad support really easy... have an "input source" variable (keyboard, gamepad1, gamepad2, ...) and when you read key status, call gamepad functions instead of keyboard_check(). Since input status is now independent of what the player uses to control the game, adding new hardware support is really easy.

Also, you'll probably eventually run into an "now I want to track keypresses and key releases too, not just the current key status" issue. That's pretty easy to solve by just adding a second variable for each input, which is a counter of how long each key has been pressed. My input processing script looks something like this:
View attachment 14201
Basically, the p_* variables is the Pressed status, the k_* variables is the Key status. I use these EVERYWHERE in my code, that's why the names are so short :p
To check if a key is pressed this step, you'd e.g. check if(k_a && !p_a); to check if a key was released this step, you'd check if(!k_a && p_a).
Wow, that key press and release trick is pretty good. I love it when you can simulate stuff with math and logic :D
On the other hand, I'm not completely sure I understand the first part. My handler script looks liek this: global.left = keyboard_check(global.contLft); (contLft is the variable I load the key into, and then I check for whatever key is in that variable.). I don't understand how I can read if a key is pressed, before I check for it with gamepad or keyboard check? When remapping keys, should I also log into a 2d map whether the key is from a gamepad or keyboard? Like: array[0,0] = vk:left; array[0,1] = keyboard, array[0,2] = gp_padl, array[0,3] = gamepad. And then when I need to listen for keys.. well, I still don't get it :oops: . I tried to use that wolf guy's new remapping video, but keyboard_set_map doesnt seem to work with variables holding actual keys.

I dunno...
 

Yal

🐧 *penguin noises*
GMC Elder
I'm doing it like this:
  • In the create event, run init_keys(), which sets up all variables.
  • In the begin step event, run get_keys(), which updates all variables based on the input, and the global variable that stores the active input.
  • In the step event, instead of checking key status, I just use the k_* and p_* variables directly.
  • Variables store the current key status: k_* variables are either true or false (key is pressed vs key is not pressed), p_* variables is the number of steps the key has been pressed before this step.
So basically, the script I showed you didn't have the "input type" part, you'd want something like this for the complete picture (the full script is massive so this still is just a part of it):
upload_2017-11-12_16-13-0.png

Also, note that my k_* and p_* variables are not global, I found that it was more harm than good since state would carry over between rooms and stuff and mess up menus and stuff :p Also, each object having their own set of these makes it easier to add in multiplayer later if you'd so like... you'd just spawn one object per player, give them different 'input type' variables, and then they can all do the same thing with no extra work from your part.

EDIT: Oh, and note that the p_* = k_* thing is the same. We're just worrying about the previous state when computing that, not what that state actually was fetched from.
 
E

elsi11

Guest

Tnx for the effort. I think I may begin to kinda get it now. You have this code in every playable object, and depending on which controller you assigned to it, the code automatically listens to only inputs coming from that device.

I thought you meant that you can a priori determine from which device an input came (like vk_anykey - which doesnt seem to exist for controllers), and then you would channel the input into either keyboard_check, or gamepad_button_check. I thought you were telling me that you can play with a keyboard and controller at the same time, and interchangeably - controlling the same guy.

I was planning on having 2 bindings for the same guy, where you would presumably use one column for keyboard keys, and the other for controller. Maybe that's why I assumed you were talkign about that. I play some games sometimes with the gamepad, and sometimes with the controller, so 2 sets of bindings looked cool.

Haha, I'm now totally confused about everything. End of message :p
 

Yal

🐧 *penguin noises*
GMC Elder
You have this code in every playable object, and depending on which controller you assigned to it, the code automatically listens to only inputs coming from that device.
Yeah, except I have a script so I don't need to manually copy the code everywhere... that's what makes using scripts so powerful~

And indeed, when you're checking for inputs via code, you don't really "react when an event happens"... you instead check whether a particular event ("is input X currently active?") is happening right now, and get a yes or no response. So if you want to only react to controller input, you only check for controller input, because that's the only one you're interested in at the moment.

Also, a lot of games actually check both keyboard and controller input at once and use both at the same time. I just ignore unused inputs because I map each input source to a player (and it would be confusing if players started interfering with each other randomly), but for single player games you might wanna use all inputs at once so the player can switch back and forth as they see fit (e.g. if they accidentally unplug the controller). It's really just an UX thing and there's no right or wrong.

But those games still just use one set of variables most of the time... set all the k_* variables to false once per step, then read all inputs, and if any is active, set the corresponding k_* variable to true (no matter if it was true or false before). Still pretty easy to code if you want this effect, too: use |= instead of = when assigning the k_* variables, and add extra code right after assigning p_* variables to set all k_* variables to false in beforehand.

(basically, |= is the logic version of +=, if you're familiar with the latter... it adds the logic values together using bitwise or and uses that for the thing you're assigning; or-ing together something with a value of 1 sets it to 1, or-ing together something with a value of 0 doesn't change it. Understanding this is kinda outta the scope of what we're talking about right now so sorry if I'm just confusing you even more :p)
 
E

elsi11

Guest
But those games still just use one set of variables most of the time... set all the k_* variables to false once per step, then read all inputs, and if any is active, set the corresponding k_* variable to true (no matter if it was true or false before). Still pretty easy to code if you want this effect, too: use |= instead of = when assigning the k_* variables, and add extra code right after assigning p_* variables to set all k_* variables to false in beforehand.

(basically, |= is the logic version of +=, if you're familiar with the latter... it adds the logic values together using bitwise or and uses that for the thing you're assigning; or-ing together something with a value of 1 sets it to 1, or-ing together something with a value of 0 doesn't change it. Understanding this is kinda outta the scope of what we're talking about right now so sorry if I'm just confusing you even more :p)
I read the last 2 paragraphs about 35 times, and I think I get it now xD I was still thinking about my global variables, so it didnt make sense :p I have some experience with bits and hex, so I kinda understood the last part :) Amazing how many tricks you can do with ones and zeroes :p

Final question:
How would you check for 2 keyboard keys at the same time? The following is just a bad ad hoc thing I made up:
Code:
k_u = sign(keyboard_check(vk_up) + keyboard_check(ord('W'));
Tnx for all the patience and amazing advice :D
 

Yal

🐧 *penguin noises*
GMC Elder
How would you check for 2 keyboard keys at the same time? The following is just a bad ad hoc thing I made up:
This would work, but it'd be more elegant (and perhaps faster, since we strip away one function call) to use boolean or for this:
Code:
k_u = keyboard_check(vk_up) || keyboard_check(ord('W'));
As you can see, we use the same symbol | here, but twice in a row. || is used to OR entire values, while | is used to OR each bit separately. (There's similar things with && and & for the logical and, and ^^ and ^ for the logical exclusive-or). Generally you'd use || for more or less every situation, except when you specifically want to do binary operations (and |=, &= and ^= happen to have their uses). When you only have true/false values, || and | have the same effect because values of 1 and 0 just need one bit to be stored, but || also has the benefit that they can be used on any value that's true or false with the same effect: 2 is a true value, 1 is a true value, but (2 & 1) is 0 because the bits representing 2 and 1 don't overlap (2 is 0010 in binary, 1 is 0001 in binary).

Kinda forgot what I was going for here, but the TLDR is "sorry for being confusing with all these symbols, here's some explanations for why I use different combinations of them all the time". Feel free to ask more questions if this made you even more confused :p

Oh, and the term "boolean" or "bool" refers to the true/false logic and its operations, btw. GM doesn't have a boolean data type, and treats every value >= 1 (0.5 in legacy versions) as true and every other value as false, with true being defined as 1 and false being defined as 0. Generally you want to try to make your if-statements have a comparison of some sort just to be sure you have the logic value you want in the end, though (&&, ||, >, ==, etc)
 
Last edited:
E

elsi11

Guest
k_u = keyboard_check(vk_up) || keyboard_check(ord('W'));
Hey, this is the first thing I tried, and it didn't work, so I thought you couldnt use comparisons outside an "if" (or similar) statement. But I messed with something else at the time too, so maybe something went wrong.
I tried it now and it works. Thank you very much.

Does an OR comparison stop checking the second part if the first part is true?

Those binary tricks are pretty interesting. Maybe some day I will know enough to use them. Till now I only used the binary trick where you wipe the right 4 or 5 numbers to 0, so you get a number divisible by 16 or 32 every time. That's grid collision. Had a rough time wrapping my head around that one :p

Tnx again, I think I have most of the pieces now for my control change menu :D

Edit: actually, I wrote a sketch yesterday while I was still on sign(), and I just changed it to OR now. What do you think about something like this:
Code:
array[0,0] = input.keyboard;    //enum
array[0,1] = vk_up;
array[0,2] = input.gamepad;
array[0,3] = gp_padu;

k_u = scr_stuffcheck(array[0,0], array[0,1]) || scr_stuffcheck(array[0,2], array[0,3])
                        
// scr_stuffcheck (input type , key binding )
if argument 0 == input.keyboard)
    var blabla= keyboard_check (argument1);
else if argument 0 == input.gamepad
    var blalba = gamepad_check (argument 1);
return blabla;
Haha, I think I'll focus on sprites in the next few days xD This logic stuff makes my brain go :confused:
 

Yal

🐧 *penguin noises*
GMC Elder
Does an OR comparison stop checking the second part if the first part is true?
Yes, but only if you've enabled it in the game settings (it's called something like "short-circuit evaluations"). I think it's default off to make games more stable, but I might misremember it. Should be on the first Preferences page in GMS1, not sure where it is in GMS2.

Also worth noting is some useful ways to abuse short-circuiting:
  • if(instance_exists(obj_player) && obj_player.variable > 30){ do_stuff() }
  • if(cooldown < 0 && check_complicated_AI_thing() ){ do_stuff() }
Aka, check if a resource exists before accessing it right in the if-statement, or abort early before doing complicated computations that could slow down the game if you do them when you don't need to. When used right, this could make your code a bit more readable (since you can sort of merge two if statements together this way when one of them is just a "support check" like those two, that just distracts from the 'real' if statement).
 
E

elsi11

Guest
Hey @Yal . Sorry for bothering you.
I am in need of a keyboard_check_pressed, and remembered your awesome trick with k_* and p_* . Just wanted to ask if you had some mathematical, logical trick to simulate this, without using conditions like:
Code:
if (p_u != 1) p_u = 0;
?
Actually, this looks pretty ok, I just made it up :p Though , I don't know how it would logically work. Maybe a third varible for kb_check_pressed:
Code:
if (p_u == 1) kcp_u = 1;
else kcp_u = 0;
Please advice :oops:
Tnx!
 

Yal

🐧 *penguin noises*
GMC Elder
Check if it's currently pressed and wasn't pressed last step:
Code:
if(k_u && !p_u){
 

TheouAegis

Member
keyboard_set_map worked for me when I played around with it.... But to be honest, I don't think I tested for when, say, key1 got mapped to key2 and key3 got mapped to key1. And, well, I didn't really test it that thoroughly...

I don't worry about keys so much as I worry about the actual inputs. I pretend all my controls will be on a gamepad (games for Windows don't need this limitation, but they can be handled differently anyway). So then I'd just make a set of variables to hold all the keys used as well as whether it's a mouse input, gamepad button input, or gamepad axis input.

if io_fetch == true
if keyboard_check(vk_anykey) { io_fetch = false; io_list[command] = keyboard_lastkey << 2; }
else
if mouse_check_button(mb_any) { io_fetch = false; io_list[command] = mouse_button << 2 | 1; }
else
etc.

So gamepad button would be |2 and gamepad axis would be |3. Then I'd have a script which loops through the io_list, gets the input type, then checks if it's pressed, then sets a variable accordingly. The rest of the code in the game would just check that variable.
 

Yal

🐧 *penguin noises*
GMC Elder
keyboard_set_map worked for me when I played around with it.... But to be honest, I don't think I tested for when, say, key1 got mapped to key2 and key3 got mapped to key1. And, well, I didn't really test it that thoroughly...
Last time I checked, it basically sets up an alias for the default input keys, so you can't override the "original" input keys (they'll always do their actions no matter what you map them to) but you can add an alternate input set or such. But skipping the default key system altogether makes it easier to add in alternate controls for gamepads and such anyway, IMO, and that's as big of an usecase as keyboard remapping. Might as well get two birds with one stone.
 
E

elsi11

Guest
if(k_u && !p_u){
Thank you very much. You actually wrote this before, but I looked over it because I somehow thought it would stay 1.
if(k_u && !p_u){ needs to come before we change p_u this step, right? We need this step's k_u and last step's p_u, right?
Code:
// initial p_u = 0;

//Version 1 - BAD
p_u = (p_u+1)*k_u       //p_u = 1
if (k_u && !p_u){}      //FALSE

//Version 2 - GOOD?
if (k_u && !p_u){}      //TRUE because p_u is still 0
p_u = (p_u+1)*k_u       //p_u = 1
I might be missing something, so I'm double checking :)
Tnx <3
 

Yal

🐧 *penguin noises*
GMC Elder
needs to come before we change p_u this step, right? We need this step's k_u and last step's p_u, right?
I usually do get_keys() before I do anything else (usually in Begin Step alongside stuff like "check if there's ground under our feet"), so I'd say the opposite: we need this step's k_u and this step's p_u. (Note that in my script, I update p_u and the other p_* variables using the last step's k_* variables, then update the k_* variables to the current input situation. It's for precisely this reason: the press-history variables wouldn't be much use if they had the same information as the current input situation variables :p).

Sorry for being confusing, it took me ages of experimentation to figure out this approach so I'm skipping over the logic behind it a bit and just going straight for the results x3
 
P

Pere

Guest
Yea, you are right. There are lots of unused or unnecessary numbers in the virtual keyboard system. I got my info from here http://cherrytree.at/misc/vk.htm
Here is my script for people to use if they want. I put in a bunch of buttons people will never use, but didnt put in buttons people will absolutely never ever use - like the printscreen or calculator button. I ordered the switch by chance of a key being used.
Maybe I should also put in an if statement which checks if the number is between 48 and 90 (0 - Z), and just skip the whole switch in that case. I'm not sure which set of buttons chr() encompasses, but I guess it would be ok enough. What do you think?

Here it is:
Code:
///scr_keycodes(last key)
var key = argument0;
char = chr(key);
if (key < 48 && key > 90) //buttons 0 to Z
{
    switch(key)
    {
        case vk_left: return "LEFT"; break;
        case vk_right: return "RIGHT"; break;
        case vk_up: return "UP"; break;
        case vk_down: return "DOWN"; break;
    
        case vk_lcontrol: return "L CTRL"; break;
        case vk_rcontrol: return "R CTRL"; break;
        case vk_space: return "SPACE"; break;
        case vk_lshift: return "L SHIFT"; break;
        case vk_rshift: return "R SHIFT"; break;
        case vk_lalt: return "L ALT"; break;
        case vk_ralt: return "R ALT"; break;
        case vk_enter: return "ENTER"; break;
        case vk_escape: return "ESC"; break;
 
        case 8: return "BACKSPACE"; break;
        case 9: return "TAB"; break;
        case 20: return "CAPS LOCK"; break;
    
        case 1: return "MOUSE LEFT"; break;
        case 2: return "MOUSE RIGHT"; break;
        case 4: return "MOUSE MID"; break;
        case 5: return "MOUSE X1"; break;
        case 6: return "MOUSE X2"; break;
    
        case vk_numpad0: return "NUM 0"; break;
        case vk_numpad1: return "NUM 1"; break;
        case vk_numpad2: return "NUM 2"; break;
        case vk_numpad3: return "NUM 3"; break;
        case vk_numpad4: return "NUM 4"; break;
        case vk_numpad5: return "NUM 5"; break;
        case vk_numpad6: return "NUM 6"; break;
        case vk_numpad7: return "NUM 7"; break;
        case vk_numpad8: return "NUM 8"; break;
        case vk_numpad9: return "NUM 9"; break; 
      
        case 33: return "PAGE UP"; break;
        case 34: return "PAGE DOWN"; break;
        case 35: return "END"; break;
        case 36: return "HOME"; break;
        case 45: return "INSERT"; break;
    
        case vk_decimal: return "."; break;
        case vk_delete: return "DELETE"; break;
        case vk_add: return "+"; break;
        case vk_subtract: return "-"; break;
        case vk_multiply: return "*"; break;
        case vk_divide: return "/"; break;
    
        case 144: return "NUM LOCK"; break;
        case 145: return "SCR LOCK"; break;
    
        case 186: return "';:' (US)"; break;
        case 187: return "'+' (US)"; break;
        case 188: return "',' (US)"; break;
    
        case 189: return "'-' (US)"; break;
        case 190: return "'.' (US)"; break;
        case 191: return "'/?' (US)"; break;
        case 192: return "TILDE"; break;
    
        case 219: return "'[{' US"; break;
        case 220: return "'\|' US"; break;
        case 221: return "']}' US"; break;
        case 222: return "QUOTE US"; break;
    
        case 112: return "F1"; break;
        case 113: return "F2"; break;
        case 114: return "F3"; break;
        case 115: return "F4"; break;
        case 116: return "F5"; break;
        case 117: return "F6"; break;
        case 118: return "F7"; break;
        case 119: return "F8"; break;
        case 120: return "F9"; break;
        case 121: return "F10"; break;
        case 122: return "F11"; break;
        case 123: return "F12"; break;
    }
}
return char;
Haven't tried it yet, though :p

I know this is old but thanks for the code anyways. There was a && instead of an ||. I changed that. Also the vk_lshift/vk_rshift dont work with normal keyboard_check function or the keyboard_key keyword, so I added the normal vk_shift too. left control /right control did work for some reason, same for left alt / right alt. But I added them anyways.
BTW you dont need break after return ;)

Here's the code changed.
Code:
///keyboard_key_get_string(key);
var key = argument0;
char = chr(key);
if (key < 48 || key > 90) //buttons 0 to Z
{
    switch(key)
    {
        case vk_left: return "LEFT";
        case vk_right: return "RIGHT";
        case vk_up: return "UP";
        case vk_down: return "DOWN";
     
        case vk_lcontrol: return "L CTRL";
        case vk_rcontrol: return "R CTRL";
        case vk_control: return "CTRL";
        case vk_space: return "SPACE";
        case vk_lshift: return "L SHIFT";
        case vk_rshift: return "R SHIFT";
        case vk_shift: return "SHIFT";
        case vk_lalt: return "L ALT";
        case vk_ralt: return "R ALT";
        case vk_alt: return "ALT";
        case vk_enter: return "ENTER";
        case vk_escape: return "ESC";

        case 8: return "BACKSPACE";
        case 9: return "TAB";
        case 20: return "CAPS LOCK";
     
        case 1: return "MOUSE LEFT";
        case 2: return "MOUSE RIGHT";
        case 4: return "MOUSE MID";
        case 5: return "MOUSE X1";
        case 6: return "MOUSE X2";
     
        case vk_numpad0: return "NUM 0";
        case vk_numpad1: return "NUM 1";
        case vk_numpad2: return "NUM 2";
        case vk_numpad3: return "NUM 3";
        case vk_numpad4: return "NUM 4";
        case vk_numpad5: return "NUM 5";
        case vk_numpad6: return "NUM 6";
        case vk_numpad7: return "NUM 7";
        case vk_numpad8: return "NUM 8";
        case vk_numpad9: return "NUM 9";  
       
        case 33: return "PAGE UP";
        case 34: return "PAGE DOWN";
        case 35: return "END";
        case 36: return "HOME";
        case 45: return "INSERT";
     
        case vk_decimal: return ".";
        case vk_delete: return "DELETE";
        case vk_add: return "+";
        case vk_subtract: return "-";
        case vk_multiply: return "*";
        case vk_divide: return "/";
     
        case 144: return "NUM LOCK";
        case 145: return "SCR LOCK";
     
        case 186: return "';:' (US)";
        case 187: return "'+' (US)";
        case 188: return "',' (US)";
     
        case 189: return "'-' (US)";
        case 190: return "'.' (US)";
        case 191: return "'/?' (US)";
        case 192: return "TILDE";
     
        case 219: return "'[{' US";
        case 220: return "'\|' US";
        case 221: return "']}' US";
        case 222: return "QUOTE US";
     
        case 112: return "F1";
        case 113: return "F2";
        case 114: return "F3";
        case 115: return "F4";
        case 116: return "F5";
        case 117: return "F6";
        case 118: return "F7";
        case 119: return "F8";
        case 120: return "F9";
        case 121: return "F10";
        case 122: return "F11";
        case 123: return "F12";
    }
}
return char;
 
Top