Key mappings

Goal of this thread:

To gain input from members about where to proceed next as well as any enhancements/features that would need to be added/removed prior to a submission to the code review for approval into the JME engine.

Mojo asked me to start a new thread because the topic of the original thread had become unclear



Goal:

To provide input mapping based on xml documents.



Implementation:

I used the EXML xml jar for xml i/o. I have defined a lot more than just the games key mappings, but for this thread I only want to deal with the key mappings, not the rest of the example (which does include the window sizing, what type of game you want to create and what renderer you want to use - in case you don’t want to do something with JME, but J2ME).



For the implementation, I have three variables mapped via an xml attribute or an xml element… either is valid.

Those variables are:

char – what character the action is going to be mapped to a key

action – what action should be performed when this key is pressed

display – what is displayed to the user in help or in the configuration utility.



below you’ll see the sample implementation from my base game.


    <!-- an example of an xml attribute listing -->
    <key char="A" action="playAudio(1)" display="play sound 1"/>
    <!-- an example of an xml element listing -->
    <key>
        <char>L</char>
        <action>playAudio(1)</action>
        <display>play sound 1</display>
    </key>



How the code works -- What we do is actually read in the keys.xml file and figure out what key needs to go where. We use a KeyInfo object to map a key to each of its attributes. We pass the char field (from the xml attribute/element) to the KeyMapping object... if we can't find a VK_ value in the KeyEvent object then we check the hashmap to see if the value is there. One of those two ways will give us an integer that we can later on turn into something the user can configure.

The SwingOptions panel opens up a Tabbed display that shows you the dynamically populated list of what action we're going to perform (the display) and what key it's mapped to (the char). You can change the character mapping by clicking in the field and typing a new key, then saving the changes. Currently, for testing/debugging the save goes out to a different xml file, but that would be changed for implementation.

The BSD licensed code can be checked out at: http://www.gerbildrop.com/programming/java/gerblidropEngine.zip and http://www.gerbildrop.com/programming/java/EXML.jar

If you all would like for me to post only the code that will be in the code review I can do that, however, I also post the gerbildropEngine.zip pieces because there may be something in it that someone else might want to add to jme or this particular portion of the project.

In the com.gerbildrop.core.input portion of this packaging is a class called JmeInputHandler. This contains a basic representation of the game classes like GameObject that holds all of the key mappings from game inception to game conclusion.

I think the rest you can read for yourselves. The classes that are part of this review are KeyDisplay, XmlProcessor, IoManager, XmlUtil, the errors package and KeysProcessor. and KeyMapping. For the actual key mapping only KeyDisplay, KeysProcessor and KeyMapping are needed The rest actually belong in their own thread for how to include them with the JME engine. Which begs this question, should EXML.jar be used or is there another 3rd party library that is preferential.... like dom4j or axis or some other variation of dom or sax. I found that EXML was very easy to use and its licensing wasn't bad, but I am open to other ideas.

In anycase, it's late at night for me, well, it's late being 2300 and I've had two rather well made drinks, so I'm starting to not be so... sober.

I'm looking for any suggestions from anyone about inclusion into the JME engine... as well as any questions.

I've written enough for now, I'm going to go to the couch and drool on myself:)

There are two things I would like to mention:

First, you should make the “display” element/attribute contain a symbolic name which references to a resource bundle, because eg. in my game I would want to display “Ton 1 abspielen” instead of “play sound 1”.



Secondly, how do you handle keys without a char name, like “right control”, “caps lock” etc? In the options pane, you will have to internationalize them, too, but the keyboard layouts are different for different national keyboards. EG. my keyboard here has keys named “ö” and “ä” where yours has square brackets.



I haven’t yet downloaded your code, I will do this sometimes later this day. I still have to recover from my drinks yesterday evening

Great questions. On the first one, you’re right there may have to be a resource bundle mapping for the display. I hadn’t really thought much about internationalization because I was stuck in one mode on my game engine efforts… getting it done right so I could make a working game.



<Talking out loud> This could be done in the base.xml file by stating that we’re going to have a <supportedLanguages> element/attribute which would take a <supportedLanguage> array of elements/attributes and somewhere in there the default would have to be given… though we could say that the first one shown is the default without defining a default tag of some sort.

e.g.

<supportedLanguages lang="en" lang="de" lang="es"/>
<supportedLanguages>
 <lang>en</lang>
 <lang>es></lang>
 <lang>de</lang>
</supportedLanguages>



after that, I would say that the keyMappings would have to be listed still in xml files, but the names of the xml files would be en_keys.xml or keys_es.xml something to that effect.

Whatever is decided will have to be something scalable because it'll affect everyone.

I'm going to look at this option today and come up with an architecture definition that might work for everyone
</talkingoutloud>



Regarding the keyboard mapping:
I don't know how, exactly, Java handles the keyboard mappings. I use the English and Arabic keyboards on my machine all the time, but When I type in an Arabic letter it always displays the English keyboard representation (in my SwingOptions class). Obviously in MS Word, or a txt file or anything else I'll see the Arabic text, so I need to dig into the Java KeyEvent a little more. There may need to be a translation map set up for unicode characters like the Arabic alif is the English h key, but the English H key is another mapping.

We will definately have to think around those events.

As far as Right Control and Caps Lock and a few other keys, I did not map them directly for the configuration. I was going to, and wanted to test the hashmapping first, and then forgot to go back, because I don't have a few keys mapped like tab, r control, caps lock, l control, r & L alt, enter, however those won't be hard to add.

In the KeyMapping class the hashtable defines camelback (humpback, hungarian, whatever you want to call it) notation eg PageUp, PageDown, etc. The KeyEvent defines those fields a little differently.
KeyMapping KeyEvent
PageUp = VK_Page_Up
PageDown = VK_Page_Down

in the xml you can thus define the char attribute/element "page up " as:
char=PageUp
char=VK_Page_Up
char=Page_Up.

what the code does in shorthand is:
look for the indexOf VK_
true - return KeyEvent equivalent
false - check the KeyEvent Fields for VK_ plus the char passed in
if there return the representation
if not there look up the representation in the hashmap
if in hashmap return the hashmap representation

if not in hashmap then convert the java char type to an
integer and return

Originally the logic went and checked the hashmap for keys, if they weren't there then it assumed they must be an alphanumeric key. The new logic tries to find it in anyway possible via the KeyEvent Fields, if it's not there, then it checks the hashmap, if it's not in the hashmap, then try to parseInt... if you can't then it blows up cause an invalid representation was passed. Granted, my code just does an e.printStackTrace(), which will have to be handled gracefully.

What I am assuming, and what I need to do more research on, from my tests with my keyboard and arabic are that Java maps each key in a set to a predefined map... eg. the English A position and Arabic SH keys are always mapped to VK_A, and in the case you mentioned, germanic "ö" and "ä" are English [ and ] and Arabic j and d are mapped to VK_OPEN_BRACKET and VK_CLOSE_BRACKET respectively

http://java.sun.com/j2se/1.5.0/docs/api/java/awt/event/KeyEvent.html
according to the jdk docs 14 or 15, it does provide the low level mapping, in which case we would need to get the higher level unicode representation.

So, what that means for me is that today, I am going to do some unicode checks with my code and see if I can get it to map to English, Arabic and German, Russian equivalents.

Ok, yesterday I did a lot of research and work to figure out the better way for some of the i18n stuff that batman.ac brought up.



Here are the results:

For the key mappings in other languages (mainly keyboard layouts) the hashmap in KeyMapping will have to be changed to take a KeyMap object

e.g. hm.put(“PageUp”, new KeyMap(<values>)); where <values> are the language mappings for page up. for “page up” it may be an umlaut o or arabic sh or whatever the actual mapping is. In our case we pass it in and then based on the languages set in base.xml we can pull that value out for the keyinfo object to be used in the game.



For the SwingOptions config, I didn’t have time to test it fully, but the umlaut vowels üöä and e showed up along with ß just fine in the labels. However, I was not able to do the same with the arabic letters. I didn’t set a Locale correctly or soemthing because the unicode representation was not working out right.



I’m going to make the KeyMapping changes and get a few examples in another language set up so that you can test it and make sure that it’s what you want… if there are other options that I don’t know about regarding the i18n of the labels, please let me know and I’ll adjust those as well.



Another issue – I don’t think it’s a bad thing that the key mapping code relies on some information from base.xml, however, JME does not rely on any of it. Therefore, some of these changes are going to have to be moved around to specifically only apply to KeyMapping… what I’ll probably do is add the options to keys.xml inside the root element.



I will do my best to have these changes done today and uploaded… I’ll post when they’re uploaded.

I will definitely check this out and have a look at it - there are some days without work waiting for me at this weekend :slight_smile:

Apologies.



I didn’t have the chance that I thought I would to make the changes that I needed to. One of the things that I was looking at and did notice was not working I’m going to have to fix. I went back and tried to get my changes for I18n in German to work and nada. I don’t know what I changed, but it won’t work now. I think that you may be right in that we’ll have to set the keys in the keys.xml then look them up in i18n resource bundles… if so, no prob. I’ll work on that in the next few days… getting ready to travel back home from the holidays, so I may not have that chance 'til then.



I did do some refactoring and some other things, and won’t have the latest code changes uploaded until I get back to my house…



That’s what the apologies are for.



Happy/Merry Christmas to those that celebrate.



timo