Callers (i.e., OEHIDEvent) now pass an expected middle value to the
scaledValue function, so scaledValue doesn't have to learn the middle. We
assume the middle is in fact the middle of the IOKit range for the HID
class.
This fixes the drift problem where the character would sometimes walk
slowly if the user had only fully trained the calibration in one direction
on an axis.
The only remaining limitation at this point is: you must run before you
can walk. If you only ever push the joystick to 25%, the scaler will
assume 25% is the max and will scale it to +1.0 instead of +0.25. I think
it's rare users will even notice (most games push the analog stick to its
extremes most of the time), and if they do, pushing the stick to its
extreme just once solves the problem.
This can be used for computer system plugins as a way to ignore system media key presses, so that F1-F12 keys may only register if Fn is pressed. The downside is this does not respect OS keyboard preferences if a user has changed the default settings, but seems to be the best we can do without relying on CGEventTap to track events which will require accessibility access. Attempted app-side workarounds by overriding sendEvent: or checking NSApp.currentEvent to block NSSystemDefined type NSEvent's proved to be useless due to syncing.
There are two issues in this case:
1. XPC messages are processed in a private queue making OEDeviceManager calls unsafe when retrieving device handlers. We solve this problem by making thread safe operations.
2. Sometimes we may receive binding updates on the emulator process before the process has had the time to recognize a device that is connected. This is solved by using placeholder device objects that we replace with real devices in OEHIDEvent when the device is finally parsed. This is possible because if a device is added to the UI process it will be added to the emulator process eventually.