Game Player Notes
Attached here are notes, while I am working on the Game Player
Game Player V3
A new approach is being taken for Game Player V3, which will get rid of the hard coded messes that plagued previous implementations, while trying to provide enough compatibility for emulator engines, while presenting the user with the possibility of adding or changing emulators for a given type.
The previous approaches
Previous implementations of the Game player utilized either synthesizing X events to the target emulator, as was the case in all the emulations present under Game Player V1, and in some emulations present under V2.
Synthesis of X11 Events in response to Orbiter Events
Synthesizing X11 events had a number of disadvantages:
- Some emulators utilized UI toolkits that explicitly ignored events synthesized by XSendEvent(), for security reasons
- Utilizing XTEST to synthesize fake keyboard events was subject to changing window focus, which would cause the synthesized event to go to the wrong window.
- Capturing the correct window ID could be problematic due to race conditions with the window ID capture thread, and MAME either starting or stopping too slow, or too fast.
- Dealing with this created a great deal of complexity in latching events, trapping X event errors, and resynthesizing and resending events when these errors occurred, which would potentially mask more serious X errors, leading in the worst possible case to an X server crash.
In short, it was a mess.
Synthesis of commands over FIFO to Emulator in response to Orbiter Events
I tried to deal with this by creating a FIFO socket between the Game Player, and the target emulator, through which I would send a simple protocol of one or more byte commands. This had the advantage of being more reliable, as well as opening up the possibility of sending advanced commands, such as swapping in/out disks on computer emulations. But this presented the problem that it required patched versions of the emulators in question, leading to long term maintenance of these emulators. Again, not a very palatable proposition just to implement Orbiter control.
But it was my work on the Wii Remote Controller device, that gave me insight on how to solve this problem elegantly, namely to use the Userland Input subsystem available in the kernel, also known as uinput.
The uinput approach
uinput is a kernel module that once loaded, exposes a device node, that exposes a number of standard file semantics and some ioctls, which when used, can create what appear to the system as input devices, but that are injected with events from code running in the user space. This has a number of amazing uses. It was used, for example, in my Wii Remote Controller device, to convert the XWiiMote events into kernel input events so that the Wii Remote could appear to be an absolute, or relative input device with a number of buttons. In the case of Game Player, it will create a virtual device for the target emulator, which will look like a virtual keyboard or joystick, so that Orbiter presses can be translated into appropriate events for the emulator. This completely mitigates the various issues of the previous approaches, by providing a simple, straightforward input device, that fools the emulators, without needing any special patching for basic function.
The Game Player has the UInput class, which is called to encapsulate all UInput functionality, to the following functions:
public: UInput(); virtual ~UInput();
// Initialization and done routines virtual bool Init(); virtual bool Done(); virtual void Initialized_set(bool bInitialized); virtual bool IsInitialized(); virtual bool KeyUp(int iEvent); // send a key up event to the UInput device virtual bool KeyDown(int iEvent); // send a key down event to the UInput device virtual bool KeyPress(int iEvent); // Press a key down, then release up, to UInput device, after keypress delay. virtual void KeyPress_Delay_set(int iDelay); // Set the wanted keypress delay virtual int KeyPress_Delay_get(); // Get the current keypress delay.
The individual iEvents are standard Linux input events as specified in <linux/input.h>
Game Player Child Devices
This ability to cleanly control the game players with a singular control device, without the need of special patching, opens up the possibility to specify emulator configuration entirely in the database, and to have each emulator specified as a child device that can be added, removed, or changed under user control
TODO: Flesh out this particular API.