renaming key events (ONEKEY,TWOKEY, etc.)

Hello,

I was hoping that some one could tell me that there is an easy way to rename key events.
Using it’s full name is kinda silly for a player to look at, so i came up with this piece:


    #weapon text
    weapon_icons = [obj for obj in script.get_scene('Hud').objects if 'weapon_text' in obj]
    
    if weapon_icons:
        for obj in weapon_icons:
            
            button_name = GD[obj['weapon_text']]
            
            if button_name.endswith('KEY'):
                    
                text_to_number = {  'ZERO':'0',
                                    'ONE':'1',
                                    'TWO':'2',
                                    'THREE':'3',
                                    'FOUR':'4',
                                    'FIVE':'5',
                                    'SIX':'6',
                                    'SEVEN':'7',
                                    'EIGHT':'8',
                                    'NINE':'9'
                                            }
                if button_name[:-3] in text_to_number:                            
                    obj['Text'] = text_to_number[button_name[:-3]]

I am using the .endwith function to check the events, then i remove the un needed characters, check the modified name with a dict to grab the right number and display that number on screen.

But to set this up for all the keys ( like numpad, mouse keys etc) it will become a huge dict/script check, so my question is, is there an easier/better way to check/convert it?

Thanks.

Hmm. I did this a while back. Unfortunately I can’t remember where/whatfor, so I can’t look up exactly what I did. From memory It is necessary to do a dict lookup for some keys (eg tabkey, backspace, shift is akward), but ones like ONEKEY, TWOKEY, WKEY and so on can be handled with the bge.events.EventToCharacterfunction. However, that expects a keycode, not a key string. Thankfully you can convert from one to the other with:


key_str = 'WKEY'
key_code = bge.events.__dict__[key_str]

I poll the sensor

if sensor.positive on mouse, keyboard, and joystick

if it has a string I use it, if not I make one up,

then I check the input string vs game command dictionary and spit out a game command
(fun fact this is where multiplayer on 1 computer is easy to setup)

have it spit out a list [ [‘GameCommand’,index] ,Player]

and append the command to the players list then sort by index
then copy string to a list if it does not exist.

now we have serialized input with no doubles.

this makes it easy to setup a ‘player input controls’ screen

This would be the way to go.
Although you could also do:


key_str = 'WKEY'
defaultLookup = 0
key_code = getattr(bge.events, key_str, defaultLookup)

This also allows you to get a default value in case the looked up thing did not exist (mistyping or anything).

Be aware that these game keys are constants that help to read your code. Key codes are numbers.

E.g. bge.events.AKEY is much better to understand than 97.

Nevertheless key codes nor the constants represent what is printed onto the key. They identify the physical object only. The OS knows via configured keyboard layout mapping what is printed onto the key.

Unfortunately neither the BGE nor Python provide access to the keyboard layout mapping of the OS. This makes it nearly impossible to show the user the character that is printed on the key. Example: the BGE never shows “ü” when I press the [Ü] key.

This makes it nearly impossible to show the user the correct key label when not using a keyboard with US-Layout.

I am not in need of the event key number, i have both name and numbers, but the numbers are not the same as the keys so their useless.
What i need is a very simple/effective way to make this event names/numbers readable for everyone.

Like the script i shown takes the event name ONEKEY checks if endswith KEY then remove last 3 characters, then take ONE trough a dict, and here i can rename it to what i like, and this will be shown on screen. So the player does not read press 136 or LEFTSHIFTKEY on screen but just 1 or LEFTSHIFT. (136 is not 1 (or lucky guess) just example)

From memory It is necessary to do a dict lookup for some keys

Ok so its just the ones i want to change needs a dict check. Nice thing about endsWith is it can use tuples so i can check multiple unneeded characters/names at the same time.

Unfortunately neither the BGE nor Python provide access to the keyboard layout mapping of the OS the game is currently running on. This makes it nearly impossible to show the user the character shown at the key. Example: the BGE never shows “Ü” when I press that key.

Ok good to know, so i can just proceed my way then and it should be ok.

This is what ive made of it, working well. Use it if you like.


def key_event_readable(key_event_name):
        
    text_to_number = {  
                        #keyboard
                        'ZEROKEY'           :"0",
                        'ONEKEY'            :"1",
                        'TWOKEY'            :"2",
                        'THREEKEY'          :"3",
                        'FOURKEY'           :"4",
                        'FIVEKEY'           :"5",
                        'SIXKEY'            :"6",
                        'SEVENKEY'          :"7",
                        'EIGHTKEY'          :"8",
                        'NINEKEY'           :"9",
                        
                        'ACCENTGRAVEKEY'    :"`",
                        'BACKSPACEKEY'      :"<-",
                        'COMMAKEY'          :",",
                        'EQUALKEY'          :"=",
                        'LEFTBRACKETKEY'    :"[",
                        'RIGHTBRACKETKEY'   :"]",
                        'MINUSKEY'          :"-",
                        'PERIODKEY'         :".",
                        'SEMICOLONKEY'      :";",
                        'SLASHKEY'          :"/",
                        'BACKSLASHKEY'      :"\\",
                        'QUOTEKEY'          :"'",
                        'RETKEY'            :"Return",
                        
                        'PADPLUSKEY'        :"Pad +",
                        'PADSLASHKEY'       :"Pad /",
                        'PADASTERKEY'       :"Pad *",
                        'PADPERIOD'         :"Pad .",
                        'PADMINUS'          :"Pad -",


                        #mouse
                        'WHEELUPMOUSE'      :"Scroll up",
                        'WHEELDOWNMOUSE'    :"Scroll down",
                        'LEFTMOUSE'         :"LB",
                        'RIGHTMOUSE'        :"RB",
                        'MIDDLEMOUSE'       :"MMB"
                    }
                                
    if key_event_name in text_to_number:
        return text_to_number[key_event_name]
    elif key_event_name.endswith('KEY'):
        return key_event_name[:-3]
    elif key_event_name.endswith('MOUSE'):
        return key_event_name[:-5]
    else: 
        return key_event_name

bge.events.EventToString will return the string character, you can batch process all active keys at once


ms = bge.logic.mouse.active_events
kb  = bge.logic.keyboard.active_events
l = [bge.events.EventToString(k) for k,state in {**ms,**kb}.items()]
print(l)

As i said 2 times before, i dont need key event names or numbers, i got them already.
What you do is just checking the active_events, if its there you convert number to text, so you get ZEROKEY again while i want 0 instead of ZEROKEY.

my example(code) is so hard to read… that i convert it to readable, player friendly text to show on screen.

so atm there is no way around my solution.

I’m sorry, use chr instead will get you ascii string

NP, i tried that but using the character works in some cases, due to not all buttons are converted, like SPACEBAR becomes ’ ’ (just a white space). So we still need to convert it to the right symbol. I guess ill stick with my dict solution, i can rename it however i like that way.

There are two functions: EventToString and EventToCharacter. EventToString returns ‘WKEY’ ‘SKEY’ from the key number. EventToCharacter returns the character. So EventToCharacter(bge.events.ONEKEY) will return “1”
But this does not work for all keys. So I tend to do a dict lookup, and fall back on EventToCharacter.

Something like:


READABLE_MAPPING = {
    bge.events.BACKSPACEKEY: '<-'
}
def to_char(keycode):
    char = READABLE_MAPPING.get(keycode, bge.events.EventToCharacter(keycode))
    if not char:
        char = bge.events.EventToString(keycode)
    return char

That will return whatever is in the dictionary. Failing that it will do EventToChar. If that returns an empty string, it returns the long name (eg UPARROWKEY)

so basically it’s the same as me, look in dict else return the full name / alter and return

anyway i’m thinking about keeping this:


    if key_event_name in text_to_number:
        return text_to_number[key_event_name]
    elif key_event_name.endswith('KEY'):
        return key_event_name[:-3]
    elif key_event_name.endswith('MOUSE'):
        return key_event_name[:-5]
    else: 
        return key_event_name

Ill convert it and going to use it for thumbnail reference as well, so it’s actually good to have all keys in a dict (keys that don’t need a modifier key)