/* Copyright (c) 2023 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __GamepadMap_H__ #define __GamepadMap_H__ #ifdef __cplusplus extern "C" { #endif typedef struct GamepadMap GamepadMap; #define GamepadMap_superclass StemObject #include "serialization/DeserializationContext.h" #include "serialization/SerializationContext.h" #include "stemobject/StemObject.h" #include "utilities/Atom.h" #include "utilities/HashTable.h" #define VENDOR_ID_MICROSOFT 0x45E #define PRODUCT_ID_XBOX360 0x28E #define PRODUCT_ID_XBOXONE 0x2D1 #define PRODUCT_ID_XBOXSX 0xB12 #define VENDOR_ID_SONY 0x54C #define PRODUCT_ID_DUALSHOCK3 0x268 #define PRODUCT_ID_DUALSHOCK4 0x5C4 #define PRODUCT_ID_DUALSENSE 0xCE6 #define VENDOR_ID_VALVE 0x28DE #define PRODUCT_ID_STEAM_CONTROLLER 0x11FF typedef enum GamepadElement { GAMEPAD_UNKNOWN, // 0 GAMEPAD_DPAD_X, // 1 GAMEPAD_DPAD_Y, // 2 GAMEPAD_DPAD_LEFT, // 3 GAMEPAD_DPAD_RIGHT, // 4 GAMEPAD_DPAD_UP, // 5 GAMEPAD_DPAD_DOWN, // 6 GAMEPAD_LEFT_STICK_X, // 7 GAMEPAD_LEFT_STICK_Y, // 8 GAMEPAD_LEFT_STICK_LEFT, // 9 GAMEPAD_LEFT_STICK_RIGHT, // 10 GAMEPAD_LEFT_STICK_UP, // 11 GAMEPAD_LEFT_STICK_DOWN, // 12 GAMEPAD_RIGHT_STICK_X, // 13 GAMEPAD_RIGHT_STICK_Y, // 14 GAMEPAD_RIGHT_STICK_LEFT, // 15 GAMEPAD_RIGHT_STICK_RIGHT, // 16 GAMEPAD_RIGHT_STICK_UP, // 17 GAMEPAD_RIGHT_STICK_DOWN, // 18 GAMEPAD_LEFT_FACE_BUTTON, // 19 GAMEPAD_RIGHT_FACE_BUTTON, // 20 GAMEPAD_BOTTOM_FACE_BUTTON, // 21 GAMEPAD_TOP_FACE_BUTTON, // 22 GAMEPAD_LEFT_FRONT_SHOULDER, // 23 GAMEPAD_LEFT_BACK_SHOULDER, // 24 GAMEPAD_RIGHT_FRONT_SHOULDER, // 25 GAMEPAD_RIGHT_BACK_SHOULDER, // 26 GAMEPAD_LEFT_CENTER_BUTTON, // 27 GAMEPAD_RIGHT_CENTER_BUTTON, // 28 GAMEPAD_CENTER_BUTTON, // 29 GAMEPAD_LEFT_STICK_BUTTON, // 30 GAMEPAD_RIGHT_STICK_BUTTON, // 31 GAMEPAD_BOTH_BACK_SHOULDERS, // 32 GAMEPAD_ADDITIONAL_BUTTON_1, // 33 GAMEPAD_ADDITIONAL_BUTTON_2, // 34 GAMEPAD_ADDITIONAL_BUTTON_3, // 35 GAMEPAD_ADDITIONAL_BUTTON_4, // 36 GAMEPAD_ADDITIONAL_BUTTON_5, // 37 GAMEPAD_ADDITIONAL_BUTTON_6, // 38 GAMEPAD_ADDITIONAL_BUTTON_7, // 39 GAMEPAD_ADDITIONAL_BUTTON_8, // 40 GAMEPAD_ADDITIONAL_BUTTON_9, // 41 GAMEPAD_ADDITIONAL_BUTTON_10, // 42 GAMEPAD_ADDITIONAL_AXIS_1, // 43 GAMEPAD_ADDITIONAL_AXIS_2, // 44 GAMEPAD_ADDITIONAL_AXIS_3, // 45 GAMEPAD_ADDITIONAL_AXIS_4, // 46 GAMEPAD_ADDITIONAL_AXIS_5, // 47 GAMEPAD_ADDITIONAL_AXIS_6, // 48 GAMEPAD_ADDITIONAL_AXIS_7, // 49 GAMEPAD_ADDITIONAL_AXIS_8, // 50 GAMEPAD_ADDITIONAL_AXIS_9, // 51 GAMEPAD_ADDITIONAL_AXIS_10 // 52 } GamepadElement; typedef enum GamepadElementType { GAMEPAD_ELEMENT_BUTTON, GAMEPAD_ELEMENT_AXIS } GamepadElementType; #define GAMEPAD_ELEMENT_ENUM_VALUES { \ {"dpad_x", GAMEPAD_DPAD_X}, \ {"dpad_y", GAMEPAD_DPAD_Y}, \ {"dpad_left", GAMEPAD_DPAD_LEFT}, \ {"dpad_right", GAMEPAD_DPAD_RIGHT}, \ {"dpad_up", GAMEPAD_DPAD_UP}, \ {"dpad_down", GAMEPAD_DPAD_DOWN}, \ {"left_stick_x", GAMEPAD_LEFT_STICK_X}, \ {"left_stick_y", GAMEPAD_LEFT_STICK_Y}, \ {"left_stick_left", GAMEPAD_LEFT_STICK_LEFT}, \ {"left_stick_right", GAMEPAD_LEFT_STICK_RIGHT}, \ {"left_stick_up", GAMEPAD_LEFT_STICK_UP}, \ {"left_stick_down", GAMEPAD_LEFT_STICK_DOWN}, \ {"right_stick_x", GAMEPAD_RIGHT_STICK_X}, \ {"right_stick_y", GAMEPAD_RIGHT_STICK_Y}, \ {"right_stick_left", GAMEPAD_RIGHT_STICK_LEFT}, \ {"right_stick_right", GAMEPAD_RIGHT_STICK_RIGHT}, \ {"right_stick_up", GAMEPAD_RIGHT_STICK_UP}, \ {"right_stick_down", GAMEPAD_RIGHT_STICK_DOWN}, \ {"left_face_button", GAMEPAD_LEFT_FACE_BUTTON}, \ {"right_face_button", GAMEPAD_RIGHT_FACE_BUTTON}, \ {"bottom_face_button", GAMEPAD_BOTTOM_FACE_BUTTON}, \ {"top_face_button", GAMEPAD_TOP_FACE_BUTTON}, \ {"left_front_shoulder", GAMEPAD_LEFT_FRONT_SHOULDER}, \ {"left_back_shoulder", GAMEPAD_LEFT_BACK_SHOULDER}, \ {"right_front_shoulder", GAMEPAD_RIGHT_FRONT_SHOULDER}, \ {"right_back_shoulder", GAMEPAD_RIGHT_BACK_SHOULDER}, \ {"left_center_button", GAMEPAD_LEFT_CENTER_BUTTON}, \ {"right_center_button", GAMEPAD_RIGHT_CENTER_BUTTON}, \ {"center_button", GAMEPAD_CENTER_BUTTON}, \ {"left_stick_button", GAMEPAD_LEFT_STICK_BUTTON}, \ {"right_stick_button", GAMEPAD_RIGHT_STICK_BUTTON}, \ {"both_back_shoulders", GAMEPAD_BOTH_BACK_SHOULDERS}, \ {"additional_button_1", GAMEPAD_ADDITIONAL_BUTTON_1}, \ {"additional_button_2", GAMEPAD_ADDITIONAL_BUTTON_2}, \ {"additional_button_3", GAMEPAD_ADDITIONAL_BUTTON_3}, \ {"additional_button_4", GAMEPAD_ADDITIONAL_BUTTON_4}, \ {"additional_button_5", GAMEPAD_ADDITIONAL_BUTTON_5}, \ {"additional_button_6", GAMEPAD_ADDITIONAL_BUTTON_6}, \ {"additional_button_7", GAMEPAD_ADDITIONAL_BUTTON_7}, \ {"additional_button_8", GAMEPAD_ADDITIONAL_BUTTON_8}, \ {"additional_button_9", GAMEPAD_ADDITIONAL_BUTTON_9}, \ {"additional_button_10", GAMEPAD_ADDITIONAL_BUTTON_10}, \ {"additional_axis_1", GAMEPAD_ADDITIONAL_AXIS_1}, \ {"additional_axis_2", GAMEPAD_ADDITIONAL_AXIS_2}, \ {"additional_axis_3", GAMEPAD_ADDITIONAL_AXIS_3}, \ {"additional_axis_4", GAMEPAD_ADDITIONAL_AXIS_4}, \ {"additional_axis_5", GAMEPAD_ADDITIONAL_AXIS_5}, \ {"additional_axis_6", GAMEPAD_ADDITIONAL_AXIS_6}, \ {"additional_axis_7", GAMEPAD_ADDITIONAL_AXIS_7}, \ {"additional_axis_8", GAMEPAD_ADDITIONAL_AXIS_8}, \ {"additional_axis_9", GAMEPAD_ADDITIONAL_AXIS_9}, \ {"additional_axis_10", GAMEPAD_ADDITIONAL_AXIS_10} \ } #define GAMEPAD_MAP_SERIALIZATION_FORMAT_TYPE "gamepad_map" #define GAMEPAD_MAP_SERIALIZATION_FORMAT_VERSION 0 #define GamepadMap_ivars \ StemObject_ivars \ \ HashTable * mapData; \ HashTable * aliases; #define GamepadMap_vtable(self_type) \ StemObject_vtable(self_type) stemobject_declare(GamepadMap) GamepadMap * GamepadMap_create(void); bool GamepadMap_init(GamepadMap * self); void GamepadMap_dispose(GamepadMap * self); GamepadMap * GamepadMap_deserialize(compat_type(DeserializationContext *) deserializationContext); bool GamepadMap_loadSerializedData(GamepadMap * self, compat_type(DeserializationContext *) deserializationContext); void GamepadMap_serialize(GamepadMap * self, compat_type(SerializationContext *) serializationContext); void GamepadMap_mergeValuesFrom(GamepadMap * to, GamepadMap * from); void GamepadMap_registerGlobalDefaults(GamepadMap * self); void GamepadMap_registerHardwareElement(GamepadMap * self, int vendorID, int productID, GamepadElementType elementType, unsigned int hardwareID, GamepadElement elementID, int sign); void GamepadMap_unregisterHardwareElement(GamepadMap * self, int vendorID, int productID, GamepadElementType elementType, unsigned int hardwareID); void GamepadMap_blacklistHardwareElement(GamepadMap * self, int vendorID, int productID, GamepadElementType elementType, unsigned int hardwareID); void GamepadMap_registerGamepadAlias(GamepadMap * self, int toVendorID, int toProductID, int fromVendorID, int fromProductID); bool GamepadMap_isDeviceKnown(GamepadMap * self, int vendorID, int productID); // Returns GAMEPAD_ELEMENT_NOT_FOUND if the device is not known or the element is not mapped // Some elements may have both a button and axis associated, such as DualShock 3 pressure sensitive buttons and L2/R2 triggers. // It may be necessary to check for both. D-pads may also be mapped as two axes, four buttons, or four buttons and four axes in // the case of pressure sensitivity. bool GamepadMap_hasHardwareTypeForElement(GamepadMap * self, int vendorID, int productID, GamepadElementType elementType, GamepadElement elementID); // Returns UINT_MAX if the device is not known or the element is not mapped unsigned int GamepadMap_getHardwareIDForElement(GamepadMap * self, int vendorID, int productID, GamepadElementType elementType, GamepadElement elementID); // Conventions: -1 * sign is leftward/downward/outward; 1 * sign is rightward/upward/inward. Sign is only defined for axis elements. Returns 0 if the device is not known or the element is not mapped. int GamepadMap_getAxisSignForElement(GamepadMap * self, int vendorID, int productID, GamepadElement elementID); // Returns GAMEPAD_UNKNOWN if the device is not known or the element is not mapped GamepadElement GamepadMap_getElementForHardwareID(GamepadMap * self, int vendorID, int productID, GamepadElementType elementType, unsigned int hardwareID); bool GamepadMap_isHardwareElementBlacklisted(GamepadMap * self, int vendorID, int productID, GamepadElementType elementType, unsigned int hardwareID); #ifdef __cplusplus } #endif #endif