With the Simplicity project I’m trying to work out an input abstraction layer which should be able to support multiple input APIs (JInput, AWT, LWJGL). What’s killing me is how to handle translation of key constants.
Mapping Simplicity’s constants to the API constants is not the issue. The problem lies in going the other way. For example, I could number the Simplicity contants (0…n), then the concrete implementation would load an array which could be used for mapping. Since I can’t rely on API key constants being sequential, or even within a sane range (wouldn’t want an array of 1000 ints if I’m only going to use 100 of them), then that method is out for the reverse mapping.
A few ideas I’ve thought of:
-
The obvious switch statement. This is ugly, bulky, and not something I favor.
-
A hashmap - API constants as keys, Simplicity constants as values. I could still use the array for mapping Simplicity to API constants. This would require an Integer object to be created for each constant (both keys and values) at startup, then the cost for searching the hashmap, fetching the Integer and pulling the int value each time I want to lookup a keycode.
-
Simplicity constants could be non-final statics. Each concrete implementation would set them at load time to the appropriate API constant value. The drawback is that they could be accidently modified during runtime causing the input handling to break.
-
No Simplicity constants. Instead, define an interface with methods such as getKeyA(), getKeyUp(), etc… Implementations could simply return the appropriate API constant. The only drawbacks I see here are that the class created to implement the interface would likely take up more memory than constants would (nothing major), and implementations would require a lot more typing!
Performance doesn’t really concern me as Simplicity’s input system is event based, so there won’t be needless polling of every key each frame. I’m also not concerned about memory overhead, as it is miniscule in the grand scheme of things (although it does just feel icky redefining constants that are already defined elsewhere - the price of abstraction).
So, with the exception of number 1, all of these techniques are viable for me. I really prefer #3, and it’s currently how I plan to implement it. This is often done in C++ (externed constants in a header initialized in the source file of a concrete implementation, for example). I’m curious if anyone has any other suggestions/comments on how to go about it.