Index: .fossil-settings/ignore-glob ================================================================== --- .fossil-settings/ignore-glob +++ .fossil-settings/ignore-glob @@ -28,10 +28,11 @@ extra.mk generators/library/gen_libraries generators/unicode/gen_tables src/Info.plist src/bridge/Info.plist +src/hid/Info.plist src/libobjfw.* src/objfw-defs.h src/runtime/Info.plist src/runtime/libobjfwrt.* src/test/libobjfwtest.a Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -411,12 +411,15 @@ AC_SUBST(OBJFW_SHARED_LIB, '${LIB_PREFIX}objfw${LIB_SUFFIX}') AC_SUBST(EXCEPTIONS_LIB_A, "exceptions.lib.a") AC_SUBST(FORWARDING_LIB_A, "forwarding.lib.a") AC_SUBST(LOOKUP_ASM_LIB_A, "lookup-asm.lib.a") + AC_SUBST(OBJFWHID_SHARED_LIB, '${LIB_PREFIX}objfwhid${LIB_SUFFIX}') + BUILDSYS_FRAMEWORK([ AC_SUBST(OBJFW_FRAMEWORK, "ObjFW.framework") + AC_SUBST(OBJFWHID_FRAMEWORK, "ObjFWHID.framework") build_framework="yes" ]) BUILDSYS_BUNDLE([ AC_SUBST(TESTPLUGIN_BUNDLE, "TestPlugin.bundle") @@ -423,19 +426,22 @@ ]) ], [ AC_DEFINE(OF_NO_SHARED, 1, [Whether no shared library was built]) AC_SUBST(LIBOBJFW_DEP, "../src/libobjfw.a") AC_SUBST(LIBOBJFW_DEP_LVL2, "../../src/libobjfw.a") + AC_SUBST(LIBOBJFWHID_DEP, "../src/libobjfwhid.a") + AC_SUBST(LIBOBJFWHID_DEP_LVL2, "../../src/libobjfwhid.a") ]) AS_IF([test x"$build_framework" = x"yes"], [ TESTS_LIBS="-framework ObjFW \${RUNTIME_FRAMEWORK_LIBS} $TESTS_LIBS" + TESTS_LIBS="-framework ObjFWHID $TESTS_LIBS" TESTS_LIBS="-F../src -F../src/runtime $TESTS_LIBS" ], [ TESTS_LIBS="\${RUNTIME_LIBS} $TESTS_LIBS" TESTS_LIBS="-L../src/runtime $TESTS_LIBS" - TESTS_LIBS="-L../src -lobjfw $TESTS_LIBS" + TESTS_LIBS="-L../src -lobjfwhid -lobjfw $TESTS_LIBS" ]) AC_ARG_ENABLE(static, AS_HELP_STRING([--enable-static], [build static library])) AS_IF([test x"$enable_shared" = x"no"], [ enable_static="yes" @@ -443,10 +449,12 @@ AS_IF([test x"$enable_static" = x"yes"], [ AC_SUBST(OBJFW_STATIC_LIB, "libobjfw.a") AC_SUBST(EXCEPTIONS_A, "exceptions.a") AC_SUBST(FORWARDING_A, "forwarding.a") AC_SUBST(LOOKUP_ASM_A, "lookup-asm.a") + + AC_SUBST(OBJFWHID_STATIC_LIB, "libobjfwhid.a") ]) AC_DEFINE_UNQUOTED(PLUGIN_SUFFIX, "$PLUGIN_SUFFIX", [Suffix for plugins]) AS_IF([test x"$enable_files" != x"no" -a x"$PLUGIN_SUFFIX" != x""], [ AC_SUBST(USE_SRCS_PLUGINS, '${SRCS_PLUGINS}') @@ -2364,10 +2372,11 @@ AC_CONFIG_FILES([ buildsys.mk extra.mk src/Info.plist + src/hid/Info.plist tests/Info.plist utils/objfw-config ]) AC_CONFIG_HEADERS([config.h src/objfw-defs.h]) AC_OUTPUT Index: extra.mk.in ================================================================== --- extra.mk.in +++ extra.mk.in @@ -25,10 +25,17 @@ OBJFWTLS_STATIC_LIB = @OBJFWTLS_STATIC_LIB@ OBJFWTLS_FRAMEWORK = @OBJFWTLS_FRAMEWORK@ OBJFWTLS_LIB_MAJOR = 1 OBJFWTLS_LIB_MINOR = 0 OBJFWTLS_LIB_PATCH = 2 + +OBJFWHID_SHARED_LIB = @OBJFWHID_SHARED_LIB@ +OBJFWHID_STATIC_LIB = @OBJFWHID_STATIC_LIB@ +OBJFWHID_FRAMEWORK = @OBJFWHID_FRAMEWORK@ +OBJFWHID_LIB_MAJOR = 1 +OBJFWHID_LIB_MINOR = 0 +OBJFWHID_LIB_PATCH = 0 BIN_PREFIX = @BIN_PREFIX@ BRIDGE = @BRIDGE@ CVINCLUDE_INLINE_H = @CVINCLUDE_INLINE_H@ ENCODINGS_A = @ENCODINGS_A@ @@ -37,10 +44,12 @@ EXCEPTIONS_A = @EXCEPTIONS_A@ EXCEPTIONS_LIB_A = @EXCEPTIONS_LIB_A@ FORWARDING_A = @FORWARDING_A@ FORWARDING_LIB_A = @FORWARDING_LIB_A@ LIBBASES_M = @LIBBASES_M@ +LIBOBJFWHID_DEP = @LIBOBJFWHID_DEP@ +LIBOBJFWHID_DEP_LVL2 = @LIBOBJFWHID_DEP_LVL2@ LIBOBJFWRT_DEP = @LIBOBJFWRT_DEP@ LIBOBJFWRT_DEP_LVL2 = @LIBOBJFWRT_DEP_LVL2@ LIBOBJFW_DEP = @LIBOBJFW_DEP@ LIBOBJFW_DEP_LVL2 = @LIBOBJFW_DEP_LVL2@ LOOKUP_ASM_A = @LOOKUP_ASM_A@ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -1,9 +1,9 @@ include ../extra.mk SUBDIRS = ${RUNTIME} exceptions encodings forwarding -SUBDIRS_AFTER = ${BRIDGE} ${TLS} test +SUBDIRS_AFTER = ${BRIDGE} ${TLS} hid test DISTCLEAN = Info.plist objfw-defs.h SHARED_LIB = ${OBJFW_SHARED_LIB} STATIC_LIB = ${OBJFW_STATIC_LIB} FRAMEWORK = ${OBJFW_FRAMEWORK} @@ -23,11 +23,10 @@ OFData+MessagePackParsing.m \ OFDate.m \ OFDictionary.m \ OFEnumerator.m \ OFFileManager.m \ - OFGameController.m \ OFGZIPStream.m \ OFHMAC.m \ OFINICategory.m \ OFINIFile.m \ OFIRI.m \ DELETED src/OFGameController.h Index: src/OFGameController.h ================================================================== --- src/OFGameController.h +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3.0 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * version 3.0 for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * version 3.0 along with this program. If not, see - * . - */ - -#import "OFObject.h" -#import "OFString.h" - -OF_ASSUME_NONNULL_BEGIN - -/** @file */ - -@class OFArray OF_GENERIC(ObjectType); -@class OFMutableSet OF_GENERIC(ObjectType); -@class OFNumber; -@class OFSet OF_GENERIC(ObjectType); - -/** - * @brief A button on a controller. - * - * Possible values are: - * - * * @ref OFGameControllerButtonA - * * @ref OFGameControllerButtonB - * * @ref OFGameControllerButtonC - * * @ref OFGameControllerButtonX - * * @ref OFGameControllerButtonY - * * @ref OFGameControllerButtonZ - * * @ref OFGameControllerButtonL - * * @ref OFGameControllerButtonR - * * @ref OFGameControllerButtonZL - * * @ref OFGameControllerButtonZR - * * @ref OFGameControllerButtonSelect - * * @ref OFGameControllerButtonStart - * * @ref OFGameControllerButtonHome - * * @ref OFGameControllerButtonCapture - * * @ref OFGameControllerButtonLeftStick - * * @ref OFGameControllerButtonRightStick - * * @ref OFGameControllerButtonDPadUp - * * @ref OFGameControllerButtonDPadDown - * * @ref OFGameControllerButtonDPadLeft - * * @ref OFGameControllerButtonDPadRight - * * @ref OFGameControllerButtonCPadUp - * * @ref OFGameControllerButtonCPadDown - * * @ref OFGameControllerButtonCPadLeft - * * @ref OFGameControllerButtonCPadRight - * * @ref OFGameControllerButtonSL - * * @ref OFGameControllerButtonSR - * * @ref OFGameControllerButtonMode - */ -typedef OFConstantString *OFGameControllerButton; - -#ifdef __cplusplus -extern "C" { -#endif -/** - * @brief The A button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonA; - -/** - * @brief The B button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonB; - -/** - * @brief The C button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonC; - -/** - * @brief The X button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonX; - -/** - * @brief The Y button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonY; - -/** - * @brief The Z button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonZ; - -/** - * @brief The L button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonL; - -/** - * @brief The R button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonR; - -/** - * @brief The ZL button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonZL; - -/** - * @brief The ZR button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonZR; - -/** - * @brief The Select button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonSelect; - -/** - * @brief The Start button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonStart; - -/** - * @brief The Home button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonHome; - -/** - * @brief The Capture button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonCapture; - -/** - * @brief The left stick button (pressing the left stick) on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonLeftStick; - -/** - * @brief The right stick button (pressing the right stick) on a game - * controller. - */ -extern const OFGameControllerButton OFGameControllerButtonRightStick; - -/** - * @brief The D-Pad Up button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonDPadUp; - -/** - * @brief The D-Pad Down button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonDPadDown; - -/** - * @brief The D-Pad Left button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonDPadLeft; - -/** - * @brief The D-Pad Right button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonDPadRight; - -/** - * @brief The C-Pad Up button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonCPadUp; - -/** - * @brief The C-Pad Down button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonCPadDown; - -/** - * @brief The C-Pad Left button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonCPadLeft; - -/** - * @brief The C-Pad Right button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonCPadRight; - -/** - * @brief The + button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonPlus; - -/** - * @brief The - button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonMinus; - -/** - * @brief The SL button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonSL; - -/** - * @brief The SR button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonSR; - -/** - * @brief The Mode button on a game controller. - */ -extern const OFGameControllerButton OFGameControllerButtonMode; -#ifdef __cplusplus -} -#endif - -/** - * @brief A class for reading state from a game controller. - */ -OF_SUBCLASSING_RESTRICTED -@interface OFGameController: OFObject -{ -#if defined(OF_LINUX) - OFString *_path; - int _fd; - uint16_t _vendorID, _productID; - OFString *_name; - OFMutableSet *_buttons, *_pressedButtons; - bool _hasLeftAnalogStick, _hasRightAnalogStick; - bool _hasZLPressure, _hasZRPressure; - OFPoint _leftAnalogStickPosition, _rightAnalogStickPosition; - float _ZLPressure, _ZRPressure; - int32_t _leftAnalogStickMinX, _leftAnalogStickMaxX; - int32_t _leftAnalogStickMinY, _leftAnalogStickMaxY; - int32_t _rightAnalogStickMinX, _rightAnalogStickMaxX; - int32_t _rightAnalogStickMinY, _rightAnalogStickMaxY; - int32_t _ZLMinPressure, _ZLMaxPressure, _ZRMinPressure, _ZRMaxPressure; -#elif defined(OF_NINTENDO_DS) - OFMutableSet *_pressedButtons; -#elif defined(OF_NINTENDO_3DS) - OFMutableSet *_pressedButtons; - OFPoint _leftAnalogStickPosition; -#elif defined(OF_WINDOWS) - DWORD _index; - OFNumber *_Nullable _vendorID, *_Nullable productID; - OFMutableSet *_pressedButtons; - OFPoint _leftAnalogStickPosition, _rightAnalogStickPosition; - float _ZLPressure, _ZRPressure; -#endif -} - -#ifdef OF_HAVE_CLASS_PROPERTIES -@property (class, readonly, nonatomic) - OFArray *controllers; -#endif - -/** - * @brief The name of the controller. - */ -@property (readonly, nonatomic, copy) OFString *name; - -/** - * @brief The vendor ID of the controller or `nil` if unavailable. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFNumber *vendorID; - -/** - * @brief The product ID of the controller or `nil` if unavailable. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFNumber *productID; - -/** - * @brief The buttons the controller has. - */ -@property (readonly, nonatomic, copy) - OFSet OF_GENERIC(OFGameControllerButton) *buttons; - -/** - * @brief The currently pressed buttons on the controller. - */ -@property (readonly, nonatomic, copy) - OFSet OF_GENERIC(OFGameControllerButton) *pressedButtons; - -/** - * @brief Whether the controller has a left analog stick. - */ -@property (readonly, nonatomic) bool hasLeftAnalogStick; - -/** - * @brief The position of the left analog stick. - * - * The range is from (-1, -1) to (1, 1). - */ -@property (readonly, nonatomic) OFPoint leftAnalogStickPosition; - -/** - * @brief Whether the controller has a right analog stick. - */ -@property (readonly, nonatomic) bool hasRightAnalogStick; - -/** - * @brief The position of the right analog stick. - * - * The range is from (-1, -1) to (1, 1). - */ -@property (readonly, nonatomic) OFPoint rightAnalogStickPosition; - -/** - * @brief The north button on the right diamond pad or `nil` if there is none. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - OFGameControllerButton northButton; - -/** - * @brief The south button on the right diamond pad or `nil` if there is none. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - OFGameControllerButton southButton; - -/** - * @brief The west button on the right diamond pad or `nil` if there is none. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - OFGameControllerButton westButton; - -/** - * @brief The east button on the right diamond pad or `nil` if there is none. - */ -@property OF_NULLABLE_PROPERTY (readonly, nonatomic) - OFGameControllerButton eastButton; - -/** - * @brief Returns the available controllers. - * - * @return The available controllers - */ -+ (OFArray OF_GENERIC(OFGameController *) *)controllers; - -- (instancetype)init OF_UNAVAILABLE; - -/** - * @brief Retrieve the current state from the game controller. - * - * The state returned by @ref OFGameController's messages does not change until - * this method is called. - * - * @throw OFReadFailedException The controller's state could not be read - */ -- (void)retrieveState; - -/** - * @brief Returns how hard the specified button is pressed. - * - * The returned value is in the range from 0 to 1. - * - * @param button The button for which to return how hard it is pressed. - * @return How hard the specified button is pressed - */ -- (float)pressureForButton: (OFGameControllerButton)button; -@end - -OF_ASSUME_NONNULL_END DELETED src/OFGameController.m Index: src/OFGameController.m ================================================================== --- src/OFGameController.m +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3.0 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * version 3.0 for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * version 3.0 along with this program. If not, see - * . - */ - -#include "config.h" - -#import "OFGameController.h" -#import "OFArray.h" - -const OFGameControllerButton OFGameControllerButtonA = @"A"; -const OFGameControllerButton OFGameControllerButtonB = @"B"; -const OFGameControllerButton OFGameControllerButtonC = @"C"; -const OFGameControllerButton OFGameControllerButtonX = @"X"; -const OFGameControllerButton OFGameControllerButtonY = @"Y"; -const OFGameControllerButton OFGameControllerButtonZ = @"Z"; -const OFGameControllerButton OFGameControllerButtonL = @"L"; -const OFGameControllerButton OFGameControllerButtonR = @"R"; -const OFGameControllerButton OFGameControllerButtonZL = @"ZL"; -const OFGameControllerButton OFGameControllerButtonZR = @"ZR"; -const OFGameControllerButton OFGameControllerButtonSelect = @"Select"; -const OFGameControllerButton OFGameControllerButtonStart = @"Start"; -const OFGameControllerButton OFGameControllerButtonHome = @"Home"; -const OFGameControllerButton OFGameControllerButtonCapture = @"Capture"; -const OFGameControllerButton OFGameControllerButtonLeftStick = @"Left Stick"; -const OFGameControllerButton OFGameControllerButtonRightStick = @"Right Stick"; -const OFGameControllerButton OFGameControllerButtonDPadUp = @"D-Pad Up"; -const OFGameControllerButton OFGameControllerButtonDPadDown = @"D-Pad Down"; -const OFGameControllerButton OFGameControllerButtonDPadLeft = @"D-Pad Left"; -const OFGameControllerButton OFGameControllerButtonDPadRight = @"D-Pad Right"; -const OFGameControllerButton OFGameControllerButtonCPadUp = @"C-Pad Up"; -const OFGameControllerButton OFGameControllerButtonCPadDown = @"C-Pad Down"; -const OFGameControllerButton OFGameControllerButtonCPadLeft = @"C-Pad Left"; -const OFGameControllerButton OFGameControllerButtonCPadRight = @"C-Pad Right"; -const OFGameControllerButton OFGameControllerButtonPlus = @"+"; -const OFGameControllerButton OFGameControllerButtonMinus = @"-"; -const OFGameControllerButton OFGameControllerButtonSL = @"SL"; -const OFGameControllerButton OFGameControllerButtonSR = @"SR"; -const OFGameControllerButton OFGameControllerButtonMode = @"Mode"; - -#if defined(OF_LINUX) && defined(OF_HAVE_FILES) -# include "platform/Linux/OFGameController.m" -#elif defined(OF_WINDOWS) -# include "platform/Windows/OFGameController.m" -#elif defined(OF_NINTENDO_DS) -# include "platform/NintendoDS/OFGameController.m" -#elif defined(OF_NINTENDO_3DS) -# include "platform/Nintendo3DS/OFGameController.m" -#else -@implementation OFGameController -@dynamic name, buttons, pressedButtons, hasLeftAnalogStick; -@dynamic leftAnalogStickPosition, hasRightAnalogStick, rightAnalogStickPosition; -@dynamic northButton, southButton, westButton, eastButton; - -+ (OFArray OF_GENERIC(OFGameController *) *)controllers -{ - return [OFArray array]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (OFNumber *)vendorID -{ - return nil; -} - -- (OFNumber *)productID -{ - return nil; -} - -- (void)retrieveState -{ -} - -- (float)pressureForButton: (OFGameControllerButton)button -{ - return 0; -} -@end -#endif Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -146,11 +146,10 @@ #import "OFOptionsParser.h" #import "OFTimer.h" #import "OFRunLoop.h" #import "OFMatrix4x4.h" -#import "OFGameController.h" #ifdef OF_WINDOWS # import "OFWindowsRegistryKey.h" #endif ADDED src/hid/Info.plist.in Index: src/hid/Info.plist.in ================================================================== --- /dev/null +++ src/hid/Info.plist.in @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + ObjFWHID + CFBundleName + ObjFWHID + CFBundleIdentifier + im.nil.objfw.hid + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleVersion + @BUNDLE_VERSION@ + CFBundleShortVersionString + @BUNDLE_SHORT_VERSION@ + MinimumOSVersion + 9.0 + + ADDED src/hid/Makefile Index: src/hid/Makefile ================================================================== --- /dev/null +++ src/hid/Makefile @@ -0,0 +1,50 @@ +include ../../extra.mk + +DISTCLEAN = Info.plist + +SHARED_LIB = ${OBJFWHID_SHARED_LIB} +STATIC_LIB = ${OBJFWHID_STATIC_LIB} +FRAMEWORK = ${OBJFWHID_FRAMEWORK} +LIB_MAJOR = ${OBJFWHID_LIB_MAJOR} +LIB_MINOR = ${OBJFWHID_LIB_MINOR} +LIB_PATCH = ${OBJFWHID_LIB_PATCH} + +SRCS = OFGameController.m + +INCLUDES := ${SRCS:.m=.h} \ + ObjFWHID.h + +includesubdir = ObjFWHID + +include ../../buildsys.mk + +install-extra: + i=ObjFWHID.oc; \ + ${INSTALL_STATUS}; \ + if ${MKDIR_P} ${DESTDIR}${libdir}/objfw-config && \ + ${INSTALL} -m 644 $$i ${DESTDIR}${libdir}/objfw-config/$$i; then \ + ${INSTALL_OK}; \ + else \ + ${INSTALL_FAILED}; \ + fi + +uninstall-extra: + i=ObjFWHID.oc; \ + if test -f ${DESTDIR}${libdir}/objfw-config/$$i; then \ + if rm -f ${DESTDIR}${libdir}/objfw-config/$$i; then \ + ${DELETE_OK}; \ + else \ + ${DELETE_FAILED}; \ + fi \ + fi + rmdir ${DESTDIR}${libdir}/objfw-config >/dev/null 2>&1 || true + +CPPFLAGS += -I. \ + -I.. \ + -I../.. \ + -I../exceptions \ + -I../runtime \ + -DOBJFWHID_LOCAL_INCLUDES +LD = ${OBJC} +FRAMEWORK_LIBS := -F.. -framework ObjFW ${LIBS} +LIBS := -L.. -lobjfw -L../runtime ${RUNTIME_LIBS} ${LIBS} ADDED src/hid/OFGameController.h Index: src/hid/OFGameController.h ================================================================== --- /dev/null +++ src/hid/OFGameController.h @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3.0 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3.0 along with this program. If not, see + * . + */ + +#ifdef OBJFWHID_LOCAL_INCLUDES +# import "OFObject.h" +# import "OFString.h" +#else +# if defined(__has_feature) && __has_feature(modules) +@import ObjFW; +# else +# import +# import +# endif +#endif + +OF_ASSUME_NONNULL_BEGIN + +/** @file */ + +@class OFArray OF_GENERIC(ObjectType); +@class OFMutableSet OF_GENERIC(ObjectType); +@class OFNumber; +@class OFSet OF_GENERIC(ObjectType); + +/** + * @brief A button on a controller. + * + * Possible values are: + * + * * @ref OFGameControllerButtonA + * * @ref OFGameControllerButtonB + * * @ref OFGameControllerButtonC + * * @ref OFGameControllerButtonX + * * @ref OFGameControllerButtonY + * * @ref OFGameControllerButtonZ + * * @ref OFGameControllerButtonL + * * @ref OFGameControllerButtonR + * * @ref OFGameControllerButtonZL + * * @ref OFGameControllerButtonZR + * * @ref OFGameControllerButtonSelect + * * @ref OFGameControllerButtonStart + * * @ref OFGameControllerButtonHome + * * @ref OFGameControllerButtonCapture + * * @ref OFGameControllerButtonLeftStick + * * @ref OFGameControllerButtonRightStick + * * @ref OFGameControllerButtonDPadUp + * * @ref OFGameControllerButtonDPadDown + * * @ref OFGameControllerButtonDPadLeft + * * @ref OFGameControllerButtonDPadRight + * * @ref OFGameControllerButtonCPadUp + * * @ref OFGameControllerButtonCPadDown + * * @ref OFGameControllerButtonCPadLeft + * * @ref OFGameControllerButtonCPadRight + * * @ref OFGameControllerButtonSL + * * @ref OFGameControllerButtonSR + * * @ref OFGameControllerButtonMode + */ +typedef OFConstantString *OFGameControllerButton; + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief The A button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonA; + +/** + * @brief The B button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonB; + +/** + * @brief The C button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonC; + +/** + * @brief The X button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonX; + +/** + * @brief The Y button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonY; + +/** + * @brief The Z button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonZ; + +/** + * @brief The L button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonL; + +/** + * @brief The R button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonR; + +/** + * @brief The ZL button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonZL; + +/** + * @brief The ZR button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonZR; + +/** + * @brief The Select button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonSelect; + +/** + * @brief The Start button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonStart; + +/** + * @brief The Home button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonHome; + +/** + * @brief The Capture button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonCapture; + +/** + * @brief The left stick button (pressing the left stick) on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonLeftStick; + +/** + * @brief The right stick button (pressing the right stick) on a game + * controller. + */ +extern const OFGameControllerButton OFGameControllerButtonRightStick; + +/** + * @brief The D-Pad Up button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonDPadUp; + +/** + * @brief The D-Pad Down button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonDPadDown; + +/** + * @brief The D-Pad Left button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonDPadLeft; + +/** + * @brief The D-Pad Right button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonDPadRight; + +/** + * @brief The C-Pad Up button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonCPadUp; + +/** + * @brief The C-Pad Down button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonCPadDown; + +/** + * @brief The C-Pad Left button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonCPadLeft; + +/** + * @brief The C-Pad Right button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonCPadRight; + +/** + * @brief The + button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonPlus; + +/** + * @brief The - button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonMinus; + +/** + * @brief The SL button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonSL; + +/** + * @brief The SR button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonSR; + +/** + * @brief The Mode button on a game controller. + */ +extern const OFGameControllerButton OFGameControllerButtonMode; +#ifdef __cplusplus +} +#endif + +/** + * @brief A class for reading state from a game controller. + */ +OF_SUBCLASSING_RESTRICTED +@interface OFGameController: OFObject +{ +#if defined(OF_LINUX) + OFString *_path; + int _fd; + uint16_t _vendorID, _productID; + OFString *_name; + OFMutableSet *_buttons, *_pressedButtons; + bool _hasLeftAnalogStick, _hasRightAnalogStick; + bool _hasZLPressure, _hasZRPressure; + OFPoint _leftAnalogStickPosition, _rightAnalogStickPosition; + float _ZLPressure, _ZRPressure; + int32_t _leftAnalogStickMinX, _leftAnalogStickMaxX; + int32_t _leftAnalogStickMinY, _leftAnalogStickMaxY; + int32_t _rightAnalogStickMinX, _rightAnalogStickMaxX; + int32_t _rightAnalogStickMinY, _rightAnalogStickMaxY; + int32_t _ZLMinPressure, _ZLMaxPressure, _ZRMinPressure, _ZRMaxPressure; +#elif defined(OF_NINTENDO_DS) + OFMutableSet *_pressedButtons; +#elif defined(OF_NINTENDO_3DS) + OFMutableSet *_pressedButtons; + OFPoint _leftAnalogStickPosition; +#elif defined(OF_WINDOWS) + DWORD _index; + OFNumber *_Nullable _vendorID, *_Nullable productID; + OFMutableSet *_pressedButtons; + OFPoint _leftAnalogStickPosition, _rightAnalogStickPosition; + float _ZLPressure, _ZRPressure; +#endif +} + +#ifdef OF_HAVE_CLASS_PROPERTIES +@property (class, readonly, nonatomic) + OFArray *controllers; +#endif + +/** + * @brief The name of the controller. + */ +@property (readonly, nonatomic, copy) OFString *name; + +/** + * @brief The vendor ID of the controller or `nil` if unavailable. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFNumber *vendorID; + +/** + * @brief The product ID of the controller or `nil` if unavailable. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) OFNumber *productID; + +/** + * @brief The buttons the controller has. + */ +@property (readonly, nonatomic, copy) + OFSet OF_GENERIC(OFGameControllerButton) *buttons; + +/** + * @brief The currently pressed buttons on the controller. + */ +@property (readonly, nonatomic, copy) + OFSet OF_GENERIC(OFGameControllerButton) *pressedButtons; + +/** + * @brief Whether the controller has a left analog stick. + */ +@property (readonly, nonatomic) bool hasLeftAnalogStick; + +/** + * @brief The position of the left analog stick. + * + * The range is from (-1, -1) to (1, 1). + */ +@property (readonly, nonatomic) OFPoint leftAnalogStickPosition; + +/** + * @brief Whether the controller has a right analog stick. + */ +@property (readonly, nonatomic) bool hasRightAnalogStick; + +/** + * @brief The position of the right analog stick. + * + * The range is from (-1, -1) to (1, 1). + */ +@property (readonly, nonatomic) OFPoint rightAnalogStickPosition; + +/** + * @brief The north button on the right diamond pad or `nil` if there is none. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) + OFGameControllerButton northButton; + +/** + * @brief The south button on the right diamond pad or `nil` if there is none. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) + OFGameControllerButton southButton; + +/** + * @brief The west button on the right diamond pad or `nil` if there is none. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) + OFGameControllerButton westButton; + +/** + * @brief The east button on the right diamond pad or `nil` if there is none. + */ +@property OF_NULLABLE_PROPERTY (readonly, nonatomic) + OFGameControllerButton eastButton; + +/** + * @brief Returns the available controllers. + * + * @return The available controllers + */ ++ (OFArray OF_GENERIC(OFGameController *) *)controllers; + +- (instancetype)init OF_UNAVAILABLE; + +/** + * @brief Retrieve the current state from the game controller. + * + * The state returned by @ref OFGameController's messages does not change until + * this method is called. + * + * @throw OFReadFailedException The controller's state could not be read + */ +- (void)retrieveState; + +/** + * @brief Returns how hard the specified button is pressed. + * + * The returned value is in the range from 0 to 1. + * + * @param button The button for which to return how hard it is pressed. + * @return How hard the specified button is pressed + */ +- (float)pressureForButton: (OFGameControllerButton)button; +@end + +OF_ASSUME_NONNULL_END ADDED src/hid/OFGameController.m Index: src/hid/OFGameController.m ================================================================== --- /dev/null +++ src/hid/OFGameController.m @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3.0 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3.0 along with this program. If not, see + * . + */ + +#include "config.h" + +#import "OFGameController.h" +#import "OFArray.h" + +const OFGameControllerButton OFGameControllerButtonA = @"A"; +const OFGameControllerButton OFGameControllerButtonB = @"B"; +const OFGameControllerButton OFGameControllerButtonC = @"C"; +const OFGameControllerButton OFGameControllerButtonX = @"X"; +const OFGameControllerButton OFGameControllerButtonY = @"Y"; +const OFGameControllerButton OFGameControllerButtonZ = @"Z"; +const OFGameControllerButton OFGameControllerButtonL = @"L"; +const OFGameControllerButton OFGameControllerButtonR = @"R"; +const OFGameControllerButton OFGameControllerButtonZL = @"ZL"; +const OFGameControllerButton OFGameControllerButtonZR = @"ZR"; +const OFGameControllerButton OFGameControllerButtonSelect = @"Select"; +const OFGameControllerButton OFGameControllerButtonStart = @"Start"; +const OFGameControllerButton OFGameControllerButtonHome = @"Home"; +const OFGameControllerButton OFGameControllerButtonCapture = @"Capture"; +const OFGameControllerButton OFGameControllerButtonLeftStick = @"Left Stick"; +const OFGameControllerButton OFGameControllerButtonRightStick = @"Right Stick"; +const OFGameControllerButton OFGameControllerButtonDPadUp = @"D-Pad Up"; +const OFGameControllerButton OFGameControllerButtonDPadDown = @"D-Pad Down"; +const OFGameControllerButton OFGameControllerButtonDPadLeft = @"D-Pad Left"; +const OFGameControllerButton OFGameControllerButtonDPadRight = @"D-Pad Right"; +const OFGameControllerButton OFGameControllerButtonCPadUp = @"C-Pad Up"; +const OFGameControllerButton OFGameControllerButtonCPadDown = @"C-Pad Down"; +const OFGameControllerButton OFGameControllerButtonCPadLeft = @"C-Pad Left"; +const OFGameControllerButton OFGameControllerButtonCPadRight = @"C-Pad Right"; +const OFGameControllerButton OFGameControllerButtonPlus = @"+"; +const OFGameControllerButton OFGameControllerButtonMinus = @"-"; +const OFGameControllerButton OFGameControllerButtonSL = @"SL"; +const OFGameControllerButton OFGameControllerButtonSR = @"SR"; +const OFGameControllerButton OFGameControllerButtonMode = @"Mode"; + +#if defined(OF_LINUX) && defined(OF_HAVE_FILES) +# include "platform/Linux/OFGameController.m" +#elif defined(OF_WINDOWS) +# include "platform/Windows/OFGameController.m" +#elif defined(OF_NINTENDO_DS) +# include "platform/NintendoDS/OFGameController.m" +#elif defined(OF_NINTENDO_3DS) +# include "platform/Nintendo3DS/OFGameController.m" +#else +@implementation OFGameController +@dynamic name, buttons, pressedButtons, hasLeftAnalogStick; +@dynamic leftAnalogStickPosition, hasRightAnalogStick, rightAnalogStickPosition; +@dynamic northButton, southButton, westButton, eastButton; + ++ (OFArray OF_GENERIC(OFGameController *) *)controllers +{ + return [OFArray array]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (OFNumber *)vendorID +{ + return nil; +} + +- (OFNumber *)productID +{ + return nil; +} + +- (void)retrieveState +{ +} + +- (float)pressureForButton: (OFGameControllerButton)button +{ + return 0; +} +@end +#endif ADDED src/hid/ObjFWHID.h Index: src/hid/ObjFWHID.h ================================================================== --- /dev/null +++ src/hid/ObjFWHID.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3.0 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3.0 along with this program. If not, see + * . + */ + +#import "OFGameController.h" ADDED src/hid/ObjFWHID.oc Index: src/hid/ObjFWHID.oc ================================================================== --- /dev/null +++ src/hid/ObjFWHID.oc @@ -0,0 +1,4 @@ +package_format 1 +LIBS="-lobjfwhid $LIBS" +FRAMEWORK_LIBS="-framework ObjFWHID $FRAMEWORK_LIBS" +STATIC_LIBS="${libdir}/libobjfwhid.a $STATIC_LIBS" ADDED src/hid/platform/Linux/OFGameController.m Index: src/hid/platform/Linux/OFGameController.m ================================================================== --- /dev/null +++ src/hid/platform/Linux/OFGameController.m @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3.0 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3.0 along with this program. If not, see + * . + */ + +#include "config.h" + +#include +#include +#include + +#import "OFGameController.h" +#import "OFArray.h" +#import "OFFileManager.h" +#import "OFLocale.h" +#import "OFNumber.h" +#import "OFSet.h" + +#include +#include + +#import "OFInitializationFailedException.h" +#import "OFInvalidArgumentException.h" +#import "OFOpenItemFailedException.h" +#import "OFOutOfRangeException.h" +#import "OFReadFailedException.h" + +static const uint16_t vendorIDNintendo = 0x057E; +static const uint16_t productIDLeftJoycon = 0x2006; +static const uint16_t productIDRightJoycon = 0x2007; +static const uint16_t productIDN64Controller = 0x2019; + +@interface OFGameController () +- (instancetype)of_initWithPath: (OFString *)path OF_METHOD_FAMILY(init); +@end + +static const uint16_t buttons[] = { + BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, + BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_THUMBL, BTN_THUMBR, + BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT +}; + +static OFGameControllerButton +buttonToName(uint16_t button, uint16_t vendorID, uint16_t productID) +{ + if (vendorID == vendorIDNintendo && + productID == productIDLeftJoycon) { + switch (button) { + case BTN_SELECT: + return OFGameControllerButtonMinus; + case BTN_Z: + return OFGameControllerButtonCapture; + case BTN_TR: + return OFGameControllerButtonSL; + case BTN_TR2: + return OFGameControllerButtonSR; + } + } else if (vendorID == vendorIDNintendo && + productID == productIDRightJoycon) { + switch (button) { + case BTN_B: + return OFGameControllerButtonA; + case BTN_A: + return OFGameControllerButtonB; + case BTN_START: + return OFGameControllerButtonPlus; + case BTN_TL: + return OFGameControllerButtonSL; + case BTN_TL2: + return OFGameControllerButtonSR; + } + } else if (vendorID == vendorIDNintendo && + productID == productIDN64Controller) { + switch (button) { + case BTN_TL2: + return OFGameControllerButtonZ; + case BTN_Y: + return OFGameControllerButtonCPadLeft; + case BTN_C: + return OFGameControllerButtonCPadRight; + case BTN_SELECT: + return OFGameControllerButtonCPadUp; + case BTN_X: + return OFGameControllerButtonCPadDown; + case BTN_MODE: + return OFGameControllerButtonHome; + case BTN_Z: + return OFGameControllerButtonCapture; + } + } + + switch (button) { + case BTN_A: + return OFGameControllerButtonA; + case BTN_B: + return OFGameControllerButtonB; + case BTN_C: + return OFGameControllerButtonC; + case BTN_X: + return OFGameControllerButtonX; + case BTN_Y: + return OFGameControllerButtonY; + case BTN_Z: + return OFGameControllerButtonZ; + case BTN_TL: + return OFGameControllerButtonL; + case BTN_TR: + return OFGameControllerButtonR; + case BTN_TL2: + return OFGameControllerButtonZL; + case BTN_TR2: + return OFGameControllerButtonZR; + case BTN_SELECT: + return OFGameControllerButtonSelect; + case BTN_START: + return OFGameControllerButtonStart; + case BTN_MODE: + return OFGameControllerButtonHome; + case BTN_THUMBL: + return OFGameControllerButtonLeftStick; + case BTN_THUMBR: + return OFGameControllerButtonRightStick; + case BTN_DPAD_UP: + return OFGameControllerButtonDPadUp; + case BTN_DPAD_DOWN: + return OFGameControllerButtonDPadDown; + case BTN_DPAD_LEFT: + return OFGameControllerButtonDPadLeft; + case BTN_DPAD_RIGHT: + return OFGameControllerButtonDPadRight; + } + + return nil; +} + +static float +scale(float value, float min, float max) +{ + if (value < min) + value = min; + if (value > max) + value = max; + + return ((value - min) / (max - min) * 2) - 1; +} + +@implementation OFGameController +@synthesize name = _name, buttons = _buttons; +@synthesize hasLeftAnalogStick = _hasLeftAnalogStick; +@synthesize hasRightAnalogStick = _hasRightAnalogStick; +@synthesize leftAnalogStickPosition = _leftAnalogStickPosition; +@synthesize rightAnalogStickPosition = _rightAnalogStickPosition; + ++ (OFArray OF_GENERIC(OFGameController *) *)controllers +{ + OFMutableArray *controllers = [OFMutableArray array]; + void *pool = objc_autoreleasePoolPush(); + + for (OFString *device in [[OFFileManager defaultManager] + contentsOfDirectoryAtPath: @"/dev/input"]) { + OFString *path; + OFGameController *controller; + + if (![device hasPrefix: @"event"]) + continue; + + path = [@"/dev/input" stringByAppendingPathComponent: device]; + + @try { + controller = [[[OFGameController alloc] + of_initWithPath: path] autorelease]; + } @catch (OFOpenItemFailedException *e) { + if (e.errNo == EACCES) + continue; + + @throw e; + } @catch (OFInvalidArgumentException *e) { + /* Not a game controller. */ + continue; + } + + [controllers addObject: controller]; + } + + [controllers sort]; + [controllers makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return controllers; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)of_initWithPath: (OFString *)path +{ + self = [super init]; + + @try { + OFStringEncoding encoding = [OFLocale encoding]; + unsigned long evBits[OFRoundUpToPowerOf2(OF_ULONG_BIT, + EV_MAX) / OF_ULONG_BIT] = { 0 }; + unsigned long keyBits[OFRoundUpToPowerOf2(OF_ULONG_BIT, + KEY_MAX) / OF_ULONG_BIT] = { 0 }; + unsigned long absBits[OFRoundUpToPowerOf2(OF_ULONG_BIT, + ABS_MAX) / OF_ULONG_BIT] = { 0 }; + struct input_id inputID; + char name[128]; + + _path = [path copy]; + + if ((_fd = open([_path cStringWithEncoding: encoding], + O_RDONLY | O_NONBLOCK)) == -1) + @throw [OFOpenItemFailedException + exceptionWithPath: _path + mode: @"r" + errNo: errno]; + + if (ioctl(_fd, EVIOCGBIT(0, sizeof(evBits)), evBits) == -1) + @throw [OFInitializationFailedException exception]; + + if (!OFBitSetIsSet(evBits, EV_KEY)) + @throw [OFInvalidArgumentException exception]; + + if (ioctl(_fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) == + -1) + @throw [OFInitializationFailedException exception]; + + if (!OFBitSetIsSet(keyBits, BTN_GAMEPAD) && + !OFBitSetIsSet(keyBits, BTN_DPAD_UP)) + @throw [OFInvalidArgumentException exception]; + + if (ioctl(_fd, EVIOCGID, &inputID) == -1) + @throw [OFInvalidArgumentException exception]; + + _vendorID = inputID.vendor; + _productID = inputID.product; + + if (ioctl(_fd, EVIOCGNAME(sizeof(name)), name) == -1) + @throw [OFInitializationFailedException exception]; + + _name = [[OFString alloc] initWithCString: name + encoding: encoding]; + + _buttons = [[OFMutableSet alloc] init]; + for (size_t i = 0; i < sizeof(buttons) / sizeof(*buttons); + i++) + if (OFBitSetIsSet(keyBits, buttons[i])) + [_buttons addObject: buttonToName( + buttons[i], _vendorID, _productID)]; + + _pressedButtons = [[OFMutableSet alloc] init]; + + if (OFBitSetIsSet(evBits, EV_ABS)) { + if (ioctl(_fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), + absBits) == -1) + @throw [OFInitializationFailedException + exception]; + + if (OFBitSetIsSet(absBits, ABS_X) && + OFBitSetIsSet(absBits, ABS_Y)) { + struct input_absinfo infoX, infoY; + + _hasLeftAnalogStick = true; + + if (ioctl(_fd, EVIOCGABS(ABS_X), &infoX) == -1) + @throw [OFInitializationFailedException + exception]; + + if (ioctl(_fd, EVIOCGABS(ABS_Y), &infoY) == -1) + @throw [OFInitializationFailedException + exception]; + + _leftAnalogStickMinX = infoX.minimum; + _leftAnalogStickMaxX = infoX.maximum; + _leftAnalogStickMinY = infoY.minimum; + _leftAnalogStickMaxY = infoY.maximum; + } + + if (OFBitSetIsSet(absBits, ABS_RX) && + OFBitSetIsSet(absBits, ABS_RY)) { + struct input_absinfo infoX, infoY; + + _hasRightAnalogStick = true; + + if (ioctl(_fd, EVIOCGABS(ABS_RX), &infoX) == -1) + @throw [OFInitializationFailedException + exception]; + + if (ioctl(_fd, EVIOCGABS(ABS_RY), &infoY) == -1) + @throw [OFInitializationFailedException + exception]; + + _rightAnalogStickMinX = infoX.minimum; + _rightAnalogStickMaxX = infoX.maximum; + _rightAnalogStickMinY = infoY.minimum; + _rightAnalogStickMaxY = infoY.maximum; + } + + if (OFBitSetIsSet(absBits, ABS_HAT0X) && + OFBitSetIsSet(absBits, ABS_HAT0Y)) { + [_buttons addObject: + OFGameControllerButtonDPadLeft]; + [_buttons addObject: + OFGameControllerButtonDPadRight]; + [_buttons addObject: + OFGameControllerButtonDPadUp]; + [_buttons addObject: + OFGameControllerButtonDPadDown]; + } + + if (OFBitSetIsSet(absBits, ABS_Z)) { + struct input_absinfo info; + + _hasZLPressure = true; + + if (ioctl(_fd, EVIOCGABS(ABS_Z), &info) == -1) + @throw [OFInitializationFailedException + exception]; + + _ZLMinPressure = info.minimum; + _ZLMaxPressure = info.maximum; + + [_buttons addObject: OFGameControllerButtonZL]; + } + + if (OFBitSetIsSet(absBits, ABS_RZ)) { + struct input_absinfo info; + + _hasZRPressure = true; + + if (ioctl(_fd, EVIOCGABS(ABS_RZ), &info) == -1) + @throw [OFInitializationFailedException + exception]; + + _ZRMinPressure = info.minimum; + _ZRMaxPressure = info.maximum; + + [_buttons addObject: OFGameControllerButtonZR]; + } + } + + [_buttons makeImmutable]; + + [self retrieveState]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_path release]; + + if (_fd != -1) + close(_fd); + + [_name release]; + [_buttons release]; + [_pressedButtons release]; + + [super dealloc]; +} + +- (OFNumber *)vendorID +{ + return [OFNumber numberWithUnsignedShort: _vendorID]; +} + +- (OFNumber *)productID +{ + return [OFNumber numberWithUnsignedShort: _productID]; +} + +- (void)retrieveState +{ + struct input_event event; + + for (;;) { + errno = 0; + + if (read(_fd, &event, sizeof(event)) < (int)sizeof(event)) { + if (errno == EWOULDBLOCK) + return; + + @throw [OFReadFailedException + exceptionWithObject: self + requestedLength: sizeof(event) + errNo: errno]; + } + + switch (event.type) { + case EV_KEY: + if (event.value) + [_pressedButtons addObject: buttonToName( + event.code, _vendorID, _productID)]; + else + [_pressedButtons removeObject: buttonToName( + event.code, _vendorID, _productID)]; + break; + case EV_ABS: + switch (event.code) { + case ABS_X: + _leftAnalogStickPosition.x = scale(event.value, + _leftAnalogStickMinX, _leftAnalogStickMaxX); + break; + case ABS_Y: + _leftAnalogStickPosition.y = scale(event.value, + _leftAnalogStickMinY, _leftAnalogStickMaxY); + break; + case ABS_RX: + _rightAnalogStickPosition.x = scale(event.value, + _rightAnalogStickMinX, + _rightAnalogStickMaxX); + break; + case ABS_RY: + _rightAnalogStickPosition.y = scale(event.value, + _rightAnalogStickMinY, + _rightAnalogStickMaxY); + break; + case ABS_HAT0X: + if (event.value < 0) { + [_pressedButtons addObject: + OFGameControllerButtonDPadLeft]; + [_pressedButtons removeObject: + OFGameControllerButtonDPadRight]; + } else if (event.value > 0) { + [_pressedButtons addObject: + OFGameControllerButtonDPadRight]; + [_pressedButtons removeObject: + OFGameControllerButtonDPadLeft]; + } else { + [_pressedButtons removeObject: + OFGameControllerButtonDPadLeft]; + [_pressedButtons removeObject: + OFGameControllerButtonDPadRight]; + } + break; + case ABS_HAT0Y: + if (event.value < 0) { + [_pressedButtons addObject: + OFGameControllerButtonDPadUp]; + [_pressedButtons removeObject: + OFGameControllerButtonDPadDown]; + } else if (event.value > 0) { + [_pressedButtons addObject: + OFGameControllerButtonDPadDown]; + [_pressedButtons removeObject: + OFGameControllerButtonDPadUp]; + } else { + [_pressedButtons removeObject: + OFGameControllerButtonDPadUp]; + [_pressedButtons removeObject: + OFGameControllerButtonDPadDown]; + } + break; + case ABS_Z: + _ZLPressure = scale(event.value, + _ZLMinPressure, _ZLMaxPressure); + + if (_ZLPressure > 0) + [_pressedButtons addObject: + OFGameControllerButtonZL]; + else + [_pressedButtons removeObject: + OFGameControllerButtonZL]; + break; + case ABS_RZ: + _ZRPressure = scale(event.value, + _ZRMinPressure, _ZRMaxPressure); + + if (_ZRPressure > 0) + [_pressedButtons addObject: + OFGameControllerButtonZR]; + else + [_pressedButtons removeObject: + OFGameControllerButtonZR]; + break; + } + + break; + } + } +} + +- (OFComparisonResult)compare: (OFGameController *)otherController +{ + unsigned long long selfIndex, otherIndex; + + if (![otherController isKindOfClass: [OFGameController class]]) + @throw [OFInvalidArgumentException exception]; + + selfIndex = [_path substringFromIndex: 16].unsignedLongLongValue; + otherIndex = [otherController->_path substringFromIndex: 16] + .unsignedLongLongValue; + + if (selfIndex > otherIndex) + return OFOrderedDescending; + if (selfIndex < otherIndex) + return OFOrderedAscending; + + return OFOrderedSame; +} + +- (OFSet *)pressedButtons +{ + return [[_pressedButtons copy] autorelease]; +} + +- (float)pressureForButton: (OFGameControllerButton)button +{ + if (button == OFGameControllerButtonZL && _hasZLPressure) + return _ZLPressure; + if (button == OFGameControllerButtonZR && _hasZRPressure) + return _ZRPressure; + + return ([self.pressedButtons containsObject: button] ? 1 : 0); +} + +- (OFGameControllerButton)northButton +{ + if (_vendorID == vendorIDNintendo && _productID == productIDLeftJoycon) + return nil; + if (_vendorID == vendorIDNintendo && _productID == productIDRightJoycon) + return OFGameControllerButtonX; + if (_vendorID == vendorIDNintendo && + _productID == productIDN64Controller) + return nil; + + return OFGameControllerButtonY; +} + +- (OFGameControllerButton)southButton +{ + if (_vendorID == vendorIDNintendo && _productID == productIDLeftJoycon) + return nil; + if (_vendorID == vendorIDNintendo && _productID == productIDRightJoycon) + return OFGameControllerButtonB; + if (_vendorID == vendorIDNintendo && + _productID == productIDN64Controller) + return nil; + + return OFGameControllerButtonA; +} + +- (OFGameControllerButton)westButton +{ + if (_vendorID == vendorIDNintendo && _productID == productIDLeftJoycon) + return nil; + if (_vendorID == vendorIDNintendo && _productID == productIDRightJoycon) + return OFGameControllerButtonY; + if (_vendorID == vendorIDNintendo && + _productID == productIDN64Controller) + return nil; + + return OFGameControllerButtonX; +} + +- (OFGameControllerButton)eastButton +{ + if (_vendorID == vendorIDNintendo && _productID == productIDLeftJoycon) + return nil; + if (_vendorID == vendorIDNintendo && _productID == productIDRightJoycon) + return OFGameControllerButtonA; + if (_vendorID == vendorIDNintendo && + _productID == productIDN64Controller) + return nil; + + return OFGameControllerButtonB; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; +} +@end ADDED src/hid/platform/Nintendo3DS/OFGameController.m Index: src/hid/platform/Nintendo3DS/OFGameController.m ================================================================== --- /dev/null +++ src/hid/platform/Nintendo3DS/OFGameController.m @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3.0 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3.0 along with this program. If not, see + * . + */ + +#include "config.h" + +#import "OFGameController.h" +#import "OFArray.h" +#import "OFSet.h" + +#import "OFOutOfRangeException.h" + +#define id id_3ds +#include <3ds.h> +#undef id + +@interface OFGameController () +- (instancetype)of_init OF_METHOD_FAMILY(init); +@end + +static OFArray OF_GENERIC(OFGameController *) *controllers; + +static void +initControllers(void) +{ + void *pool = objc_autoreleasePoolPush(); + + controllers = [[OFArray alloc] initWithObject: + [[[OFGameController alloc] of_init] autorelease]]; + + objc_autoreleasePoolPop(pool); +} + +@implementation OFGameController +@synthesize leftAnalogStickPosition = _leftAnalogStickPosition; +@dynamic rightAnalogStickPosition; + ++ (OFArray OF_GENERIC(OFGameController *) *)controllers +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + + OFOnce(&onceControl, initControllers); + + return [[controllers retain] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)of_init +{ + self = [super init]; + + @try { + _pressedButtons = [[OFMutableSet alloc] initWithCapacity: 18]; + + [self retrieveState]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_pressedButtons release]; + + [super dealloc]; +} + +- (void)retrieveState +{ + u32 keys; + circlePosition pos; + + hidScanInput(); + + keys = hidKeysHeld(); + hidCircleRead(&pos); + + [_pressedButtons removeAllObjects]; + + if (keys & KEY_A) + [_pressedButtons addObject: OFGameControllerButtonA]; + if (keys & KEY_B) + [_pressedButtons addObject: OFGameControllerButtonB]; + if (keys & KEY_SELECT) + [_pressedButtons addObject: OFGameControllerButtonSelect]; + if (keys & KEY_START) + [_pressedButtons addObject: OFGameControllerButtonStart]; + if (keys & KEY_DRIGHT) + [_pressedButtons addObject: OFGameControllerButtonDPadRight]; + if (keys & KEY_DLEFT) + [_pressedButtons addObject: OFGameControllerButtonDPadLeft]; + if (keys & KEY_DUP) + [_pressedButtons addObject: OFGameControllerButtonDPadUp]; + if (keys & KEY_DDOWN) + [_pressedButtons addObject: OFGameControllerButtonDPadDown]; + if (keys & KEY_R) + [_pressedButtons addObject: OFGameControllerButtonR]; + if (keys & KEY_L) + [_pressedButtons addObject: OFGameControllerButtonL]; + if (keys & KEY_X) + [_pressedButtons addObject: OFGameControllerButtonX]; + if (keys & KEY_Y) + [_pressedButtons addObject: OFGameControllerButtonY]; + if (keys & KEY_ZL) + [_pressedButtons addObject: OFGameControllerButtonZL]; + if (keys & KEY_ZR) + [_pressedButtons addObject: OFGameControllerButtonZR]; + if (keys & KEY_CSTICK_RIGHT) + [_pressedButtons addObject: OFGameControllerButtonCPadRight]; + if (keys & KEY_CSTICK_LEFT) + [_pressedButtons addObject: OFGameControllerButtonCPadLeft]; + if (keys & KEY_CSTICK_UP) + [_pressedButtons addObject: OFGameControllerButtonCPadUp]; + if (keys & KEY_CSTICK_DOWN) + [_pressedButtons addObject: OFGameControllerButtonCPadDown]; + + _leftAnalogStickPosition = OFMakePoint( + (float)pos.dx / (pos.dx < 0 ? -INT16_MIN : INT16_MAX), + (float)pos.dy / (pos.dy < 0 ? -INT16_MIN : INT16_MAX)); +} + +- (OFString *)name +{ + return @"Nintendo 3DS"; +} + +- (OFNumber *)vendorID +{ + return nil; +} + +- (OFNumber *)productID +{ + return nil; +} + +- (OFSet OF_GENERIC(OFGameControllerButton) *)buttons +{ + return [OFSet setWithObjects: OFGameControllerButtonA, + OFGameControllerButtonB, OFGameControllerButtonSelect, + OFGameControllerButtonStart, OFGameControllerButtonDPadRight, + OFGameControllerButtonDPadLeft, OFGameControllerButtonDPadUp, + OFGameControllerButtonDPadDown, OFGameControllerButtonR, + OFGameControllerButtonL, OFGameControllerButtonX, + OFGameControllerButtonY, OFGameControllerButtonZL, + OFGameControllerButtonZR, OFGameControllerButtonCPadRight, + OFGameControllerButtonCPadLeft, OFGameControllerButtonCPadUp, + OFGameControllerButtonCPadDown, nil]; +} + +- (OFSet OF_GENERIC(OFGameControllerButton) *)pressedButtons +{ + return [[_pressedButtons copy] autorelease]; +} + +- (bool)hasLeftAnalogStick +{ + return true; +} + +- (bool)hasRightAnalogStick +{ + return false; +} + +- (float)pressureForButton: (OFGameControllerButton)button +{ + return ([self.pressedButtons containsObject: button] ? 1 : 0); +} + +- (OFGameControllerButton)northButton +{ + return OFGameControllerButtonX; +} + +- (OFGameControllerButton)southButton +{ + return OFGameControllerButtonB; +} + +- (OFGameControllerButton)westButton +{ + return OFGameControllerButtonY; +} + +- (OFGameControllerButton)eastButton +{ + return OFGameControllerButtonA; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; +} +@end ADDED src/hid/platform/NintendoDS/OFGameController.m Index: src/hid/platform/NintendoDS/OFGameController.m ================================================================== --- /dev/null +++ src/hid/platform/NintendoDS/OFGameController.m @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3.0 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3.0 along with this program. If not, see + * . + */ + +#include "config.h" + +#import "OFGameController.h" +#import "OFArray.h" +#import "OFSet.h" + +#import "OFOutOfRangeException.h" + +#define asm __asm__ +#include +#undef asm + +@interface OFGameController () +- (instancetype)of_init OF_METHOD_FAMILY(init); +@end + +static OFArray OF_GENERIC(OFGameController *) *controllers; + +static void +initControllers(void) +{ + void *pool = objc_autoreleasePoolPush(); + + controllers = [[OFArray alloc] initWithObject: + [[[OFGameController alloc] of_init] autorelease]]; + + objc_autoreleasePoolPop(pool); +} + +@implementation OFGameController +@dynamic leftAnalogStickPosition, rightAnalogStickPosition; + ++ (OFArray OF_GENERIC(OFGameController *) *)controllers +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + + OFOnce(&onceControl, initControllers); + + return [[controllers retain] autorelease]; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)of_init +{ + self = [super init]; + + @try { + _pressedButtons = [[OFMutableSet alloc] initWithCapacity: 12]; + + [self retrieveState]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_pressedButtons release]; + + [super dealloc]; +} + +- (void)retrieveState +{ + uint32 keys; + + scanKeys(); + keys = keysCurrent(); + + [_pressedButtons removeAllObjects]; + + if (keys & KEY_A) + [_pressedButtons addObject: OFGameControllerButtonA]; + if (keys & KEY_B) + [_pressedButtons addObject: OFGameControllerButtonB]; + if (keys & KEY_SELECT) + [_pressedButtons addObject: OFGameControllerButtonSelect]; + if (keys & KEY_START) + [_pressedButtons addObject: OFGameControllerButtonStart]; + if (keys & KEY_RIGHT) + [_pressedButtons addObject: OFGameControllerButtonDPadRight]; + if (keys & KEY_LEFT) + [_pressedButtons addObject: OFGameControllerButtonDPadLeft]; + if (keys & KEY_UP) + [_pressedButtons addObject: OFGameControllerButtonDPadUp]; + if (keys & KEY_DOWN) + [_pressedButtons addObject: OFGameControllerButtonDPadDown]; + if (keys & KEY_R) + [_pressedButtons addObject: OFGameControllerButtonR]; + if (keys & KEY_L) + [_pressedButtons addObject: OFGameControllerButtonL]; + if (keys & KEY_X) + [_pressedButtons addObject: OFGameControllerButtonX]; + if (keys & KEY_Y) + [_pressedButtons addObject: OFGameControllerButtonY]; +} + +- (OFString *)name +{ + return @"Nintendo DS"; +} + +- (OFNumber *)vendorID +{ + return nil; +} + +- (OFNumber *)productID +{ + return nil; +} + +- (OFSet OF_GENERIC(OFGameControllerButton) *)buttons +{ + return [OFSet setWithObjects: OFGameControllerButtonA, + OFGameControllerButtonB, OFGameControllerButtonSelect, + OFGameControllerButtonStart, OFGameControllerButtonDPadRight, + OFGameControllerButtonDPadLeft, OFGameControllerButtonDPadUp, + OFGameControllerButtonDPadDown, OFGameControllerButtonR, + OFGameControllerButtonL, OFGameControllerButtonX, + OFGameControllerButtonY, nil]; +} + +- (OFSet OF_GENERIC(OFGameControllerButton) *)pressedButtons +{ + return [[_pressedButtons copy] autorelease]; +} + +- (bool)hasLeftAnalogStick +{ + return false; +} + +- (bool)hasRightAnalogStick +{ + return false; +} + +- (float)pressureForButton: (OFGameControllerButton)button +{ + return ([self.pressedButtons containsObject: button] ? 1 : 0); +} + +- (OFGameControllerButton)northButton +{ + return OFGameControllerButtonX; +} + +- (OFGameControllerButton)southButton +{ + return OFGameControllerButtonB; +} + +- (OFGameControllerButton)westButton +{ + return OFGameControllerButtonY; +} + +- (OFGameControllerButton)eastButton +{ + return OFGameControllerButtonA; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; +} +@end ADDED src/hid/platform/Windows/OFGameController.m Index: src/hid/platform/Windows/OFGameController.m ================================================================== --- /dev/null +++ src/hid/platform/Windows/OFGameController.m @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2008-2024 Jonathan Schleifer + * + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3.0 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * version 3.0 for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * version 3.0 along with this program. If not, see + * . + */ + +#include "config.h" + +#import "OFGameController.h" +#import "OFArray.h" +#import "OFNumber.h" +#import "OFSet.h" + +#import "OFInitializationFailedException.h" +#import "OFReadFailedException.h" + +#include + +@interface OFGameController () +- (instancetype)of_initWithIndex: (DWORD)index OF_METHOD_FAMILY(init); +@end + +struct XInputCapabilitiesEx { + XINPUT_CAPABILITIES capabilities; + WORD vendorID; + WORD productID; + WORD versionNumber; + WORD unknown1; + DWORD unknown2; +}; + +static WINAPI DWORD (*XInputGetStateFuncPtr)(DWORD, XINPUT_STATE *); +static WINAPI DWORD (*XInputGetCapabilitiesExFuncPtr)(DWORD, DWORD, DWORD, + struct XInputCapabilitiesEx *); + +@implementation OFGameController +@synthesize vendorID = _vendorID, productID = _productID; +@synthesize leftAnalogStickPosition = _leftAnalogStickPosition; +@synthesize rightAnalogStickPosition = _rightAnalogStickPosition; + ++ (void)initialize +{ + HMODULE module; + + if (self != [OFGameController class]) + return; + + if ((module = LoadLibraryA("xinput1_4.dll")) != NULL) { + XInputGetStateFuncPtr = + (WINAPI DWORD (*)(DWORD, XINPUT_STATE *)) + GetProcAddress(module, "XInputGetState"); + XInputGetCapabilitiesExFuncPtr = (WINAPI DWORD (*)(DWORD, DWORD, + DWORD, struct XInputCapabilitiesEx *)) + GetProcAddress(module, "XInputGetCapabilitiesEx"); + } +} + ++ (OFArray OF_GENERIC(OFGameController *) *)controllers +{ + OFMutableArray *controllers = [OFMutableArray array]; + + if (XInputGetStateFuncPtr != NULL) { + void *pool = objc_autoreleasePoolPush(); + + for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) { + OFGameController *controller; + + @try { + controller = [[[OFGameController alloc] + of_initWithIndex: i] autorelease]; + } @catch (OFInitializationFailedException *e) { + /* Controller does not exist. */ + continue; + } + + [controllers addObject: controller]; + } + + objc_autoreleasePoolPop(pool); + } + + [controllers makeImmutable]; + + return controllers; +} + +- (instancetype)init +{ + OF_INVALID_INIT_METHOD +} + +- (instancetype)of_initWithIndex: (DWORD)index +{ + self = [super init]; + + @try { + XINPUT_STATE state = { 0 }; + + if (XInputGetStateFuncPtr(index, &state) == + ERROR_DEVICE_NOT_CONNECTED) + @throw [OFInitializationFailedException exception]; + + _index = index; + + if (XInputGetCapabilitiesExFuncPtr != NULL) { + struct XInputCapabilitiesEx capabilities; + + if (XInputGetCapabilitiesExFuncPtr(1, _index, + XINPUT_FLAG_GAMEPAD, &capabilities) == + ERROR_SUCCESS) { + _vendorID = [[OFNumber alloc] + initWithUnsignedShort: + capabilities.vendorID]; + _productID = [[OFNumber alloc] + initWithUnsignedShort: + capabilities.productID]; + } + } + + _pressedButtons = [[OFMutableSet alloc] initWithCapacity: 16]; + + [self retrieveState]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_vendorID release]; + [_productID release]; + [_pressedButtons release]; + + [super dealloc]; +} + +- (void)retrieveState +{ + XINPUT_STATE state = { 0 }; + + if (XInputGetStateFuncPtr(_index, &state) != ERROR_SUCCESS) + @throw [OFReadFailedException exceptionWithObject: self + requestedLength: sizeof(state) + errNo: 0]; + + [_pressedButtons removeAllObjects]; + + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) + [_pressedButtons addObject: OFGameControllerButtonDPadUp]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) + [_pressedButtons addObject: OFGameControllerButtonDPadDown]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) + [_pressedButtons addObject: OFGameControllerButtonDPadLeft]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) + [_pressedButtons addObject: OFGameControllerButtonDPadRight]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) + [_pressedButtons addObject: OFGameControllerButtonStart]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) + [_pressedButtons addObject: OFGameControllerButtonSelect]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) + [_pressedButtons addObject: OFGameControllerButtonLeftStick]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) + [_pressedButtons addObject: OFGameControllerButtonRightStick]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) + [_pressedButtons addObject: OFGameControllerButtonL]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) + [_pressedButtons addObject: OFGameControllerButtonR]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) + [_pressedButtons addObject: OFGameControllerButtonA]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) + [_pressedButtons addObject: OFGameControllerButtonB]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) + [_pressedButtons addObject: OFGameControllerButtonX]; + if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) + [_pressedButtons addObject: OFGameControllerButtonY]; + + _ZLPressure = (float)state.Gamepad.bLeftTrigger / 255; + _ZRPressure = (float)state.Gamepad.bRightTrigger / 255; + + if (_ZLPressure > 0) + [_pressedButtons addObject: OFGameControllerButtonZL]; + if (_ZRPressure > 0) + [_pressedButtons addObject: OFGameControllerButtonZR]; + + _leftAnalogStickPosition = OFMakePoint( + (float)state.Gamepad.sThumbLX / + (state.Gamepad.sThumbLX < 0 ? -INT16_MIN : INT16_MAX), + -(float)state.Gamepad.sThumbLY / + (state.Gamepad.sThumbLY < 0 ? -INT16_MIN : INT16_MAX)); + _rightAnalogStickPosition = OFMakePoint( + (float)state.Gamepad.sThumbRX / + (state.Gamepad.sThumbRX < 0 ? -INT16_MIN : INT16_MAX), + -(float)state.Gamepad.sThumbRY / + (state.Gamepad.sThumbRY < 0 ? -INT16_MIN : INT16_MAX)); +} + +- (OFString *)name +{ + return @"XInput 1.3"; +} + +- (OFSet OF_GENERIC(OFGameControllerButton) *)buttons +{ + return [OFSet setWithObjects: + OFGameControllerButtonA, OFGameControllerButtonB, + OFGameControllerButtonX, OFGameControllerButtonY, + OFGameControllerButtonL, OFGameControllerButtonR, + OFGameControllerButtonZL, OFGameControllerButtonZR, + OFGameControllerButtonStart, OFGameControllerButtonSelect, + OFGameControllerButtonLeftStick, OFGameControllerButtonRightStick, + OFGameControllerButtonDPadLeft, OFGameControllerButtonDPadRight, + OFGameControllerButtonDPadUp, OFGameControllerButtonDPadDown, nil]; +} + +- (OFSet OF_GENERIC(OFGameControllerButton) *)pressedButtons +{ + return [[_pressedButtons copy] autorelease]; +} + +- (bool)hasLeftAnalogStick +{ + return true; +} + +- (bool)hasRightAnalogStick +{ + return true; +} + +- (float)pressureForButton: (OFGameControllerButton)button +{ + if (button == OFGameControllerButtonZL) + return _ZLPressure; + if (button == OFGameControllerButtonZR) + return _ZRPressure; + + return ([self.pressedButtons containsObject: button] ? 1 : 0); +} + +- (OFGameControllerButton)northButton +{ + return OFGameControllerButtonY; +} + +- (OFGameControllerButton)southButton +{ + return OFGameControllerButtonA; +} + +- (OFGameControllerButton)westButton +{ + return OFGameControllerButtonX; +} + +- (OFGameControllerButton)eastButton +{ + return OFGameControllerButtonB; +} + +- (OFString *)description +{ + return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; +} +@end DELETED src/platform/Linux/OFGameController.m Index: src/platform/Linux/OFGameController.m ================================================================== --- src/platform/Linux/OFGameController.m +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3.0 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * version 3.0 for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * version 3.0 along with this program. If not, see - * . - */ - -#include "config.h" - -#include -#include -#include - -#import "OFGameController.h" -#import "OFArray.h" -#import "OFFileManager.h" -#import "OFLocale.h" -#import "OFNumber.h" -#import "OFSet.h" - -#include -#include - -#import "OFInitializationFailedException.h" -#import "OFInvalidArgumentException.h" -#import "OFOpenItemFailedException.h" -#import "OFOutOfRangeException.h" -#import "OFReadFailedException.h" - -static const uint16_t vendorIDNintendo = 0x057E; -static const uint16_t productIDLeftJoycon = 0x2006; -static const uint16_t productIDRightJoycon = 0x2007; -static const uint16_t productIDN64Controller = 0x2019; - -@interface OFGameController () -- (instancetype)of_initWithPath: (OFString *)path OF_METHOD_FAMILY(init); -@end - -static const uint16_t buttons[] = { - BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, - BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_THUMBL, BTN_THUMBR, - BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT -}; - -static OFGameControllerButton -buttonToName(uint16_t button, uint16_t vendorID, uint16_t productID) -{ - if (vendorID == vendorIDNintendo && - productID == productIDLeftJoycon) { - switch (button) { - case BTN_SELECT: - return OFGameControllerButtonMinus; - case BTN_Z: - return OFGameControllerButtonCapture; - case BTN_TR: - return OFGameControllerButtonSL; - case BTN_TR2: - return OFGameControllerButtonSR; - } - } else if (vendorID == vendorIDNintendo && - productID == productIDRightJoycon) { - switch (button) { - case BTN_B: - return OFGameControllerButtonA; - case BTN_A: - return OFGameControllerButtonB; - case BTN_START: - return OFGameControllerButtonPlus; - case BTN_TL: - return OFGameControllerButtonSL; - case BTN_TL2: - return OFGameControllerButtonSR; - } - } else if (vendorID == vendorIDNintendo && - productID == productIDN64Controller) { - switch (button) { - case BTN_TL2: - return OFGameControllerButtonZ; - case BTN_Y: - return OFGameControllerButtonCPadLeft; - case BTN_C: - return OFGameControllerButtonCPadRight; - case BTN_SELECT: - return OFGameControllerButtonCPadUp; - case BTN_X: - return OFGameControllerButtonCPadDown; - case BTN_MODE: - return OFGameControllerButtonHome; - case BTN_Z: - return OFGameControllerButtonCapture; - } - } - - switch (button) { - case BTN_A: - return OFGameControllerButtonA; - case BTN_B: - return OFGameControllerButtonB; - case BTN_C: - return OFGameControllerButtonC; - case BTN_X: - return OFGameControllerButtonX; - case BTN_Y: - return OFGameControllerButtonY; - case BTN_Z: - return OFGameControllerButtonZ; - case BTN_TL: - return OFGameControllerButtonL; - case BTN_TR: - return OFGameControllerButtonR; - case BTN_TL2: - return OFGameControllerButtonZL; - case BTN_TR2: - return OFGameControllerButtonZR; - case BTN_SELECT: - return OFGameControllerButtonSelect; - case BTN_START: - return OFGameControllerButtonStart; - case BTN_MODE: - return OFGameControllerButtonHome; - case BTN_THUMBL: - return OFGameControllerButtonLeftStick; - case BTN_THUMBR: - return OFGameControllerButtonRightStick; - case BTN_DPAD_UP: - return OFGameControllerButtonDPadUp; - case BTN_DPAD_DOWN: - return OFGameControllerButtonDPadDown; - case BTN_DPAD_LEFT: - return OFGameControllerButtonDPadLeft; - case BTN_DPAD_RIGHT: - return OFGameControllerButtonDPadRight; - } - - return nil; -} - -static float -scale(float value, float min, float max) -{ - if (value < min) - value = min; - if (value > max) - value = max; - - return ((value - min) / (max - min) * 2) - 1; -} - -@implementation OFGameController -@synthesize name = _name, buttons = _buttons; -@synthesize hasLeftAnalogStick = _hasLeftAnalogStick; -@synthesize hasRightAnalogStick = _hasRightAnalogStick; -@synthesize leftAnalogStickPosition = _leftAnalogStickPosition; -@synthesize rightAnalogStickPosition = _rightAnalogStickPosition; - -+ (OFArray OF_GENERIC(OFGameController *) *)controllers -{ - OFMutableArray *controllers = [OFMutableArray array]; - void *pool = objc_autoreleasePoolPush(); - - for (OFString *device in [[OFFileManager defaultManager] - contentsOfDirectoryAtPath: @"/dev/input"]) { - OFString *path; - OFGameController *controller; - - if (![device hasPrefix: @"event"]) - continue; - - path = [@"/dev/input" stringByAppendingPathComponent: device]; - - @try { - controller = [[[OFGameController alloc] - of_initWithPath: path] autorelease]; - } @catch (OFOpenItemFailedException *e) { - if (e.errNo == EACCES) - continue; - - @throw e; - } @catch (OFInvalidArgumentException *e) { - /* Not a game controller. */ - continue; - } - - [controllers addObject: controller]; - } - - [controllers sort]; - [controllers makeImmutable]; - - objc_autoreleasePoolPop(pool); - - return controllers; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)of_initWithPath: (OFString *)path -{ - self = [super init]; - - @try { - OFStringEncoding encoding = [OFLocale encoding]; - unsigned long evBits[OFRoundUpToPowerOf2(OF_ULONG_BIT, - EV_MAX) / OF_ULONG_BIT] = { 0 }; - unsigned long keyBits[OFRoundUpToPowerOf2(OF_ULONG_BIT, - KEY_MAX) / OF_ULONG_BIT] = { 0 }; - unsigned long absBits[OFRoundUpToPowerOf2(OF_ULONG_BIT, - ABS_MAX) / OF_ULONG_BIT] = { 0 }; - struct input_id inputID; - char name[128]; - - _path = [path copy]; - - if ((_fd = open([_path cStringWithEncoding: encoding], - O_RDONLY | O_NONBLOCK)) == -1) - @throw [OFOpenItemFailedException - exceptionWithPath: _path - mode: @"r" - errNo: errno]; - - if (ioctl(_fd, EVIOCGBIT(0, sizeof(evBits)), evBits) == -1) - @throw [OFInitializationFailedException exception]; - - if (!OFBitSetIsSet(evBits, EV_KEY)) - @throw [OFInvalidArgumentException exception]; - - if (ioctl(_fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) == - -1) - @throw [OFInitializationFailedException exception]; - - if (!OFBitSetIsSet(keyBits, BTN_GAMEPAD) && - !OFBitSetIsSet(keyBits, BTN_DPAD_UP)) - @throw [OFInvalidArgumentException exception]; - - if (ioctl(_fd, EVIOCGID, &inputID) == -1) - @throw [OFInvalidArgumentException exception]; - - _vendorID = inputID.vendor; - _productID = inputID.product; - - if (ioctl(_fd, EVIOCGNAME(sizeof(name)), name) == -1) - @throw [OFInitializationFailedException exception]; - - _name = [[OFString alloc] initWithCString: name - encoding: encoding]; - - _buttons = [[OFMutableSet alloc] init]; - for (size_t i = 0; i < sizeof(buttons) / sizeof(*buttons); - i++) - if (OFBitSetIsSet(keyBits, buttons[i])) - [_buttons addObject: buttonToName( - buttons[i], _vendorID, _productID)]; - - _pressedButtons = [[OFMutableSet alloc] init]; - - if (OFBitSetIsSet(evBits, EV_ABS)) { - if (ioctl(_fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), - absBits) == -1) - @throw [OFInitializationFailedException - exception]; - - if (OFBitSetIsSet(absBits, ABS_X) && - OFBitSetIsSet(absBits, ABS_Y)) { - struct input_absinfo infoX, infoY; - - _hasLeftAnalogStick = true; - - if (ioctl(_fd, EVIOCGABS(ABS_X), &infoX) == -1) - @throw [OFInitializationFailedException - exception]; - - if (ioctl(_fd, EVIOCGABS(ABS_Y), &infoY) == -1) - @throw [OFInitializationFailedException - exception]; - - _leftAnalogStickMinX = infoX.minimum; - _leftAnalogStickMaxX = infoX.maximum; - _leftAnalogStickMinY = infoY.minimum; - _leftAnalogStickMaxY = infoY.maximum; - } - - if (OFBitSetIsSet(absBits, ABS_RX) && - OFBitSetIsSet(absBits, ABS_RY)) { - struct input_absinfo infoX, infoY; - - _hasRightAnalogStick = true; - - if (ioctl(_fd, EVIOCGABS(ABS_RX), &infoX) == -1) - @throw [OFInitializationFailedException - exception]; - - if (ioctl(_fd, EVIOCGABS(ABS_RY), &infoY) == -1) - @throw [OFInitializationFailedException - exception]; - - _rightAnalogStickMinX = infoX.minimum; - _rightAnalogStickMaxX = infoX.maximum; - _rightAnalogStickMinY = infoY.minimum; - _rightAnalogStickMaxY = infoY.maximum; - } - - if (OFBitSetIsSet(absBits, ABS_HAT0X) && - OFBitSetIsSet(absBits, ABS_HAT0Y)) { - [_buttons addObject: - OFGameControllerButtonDPadLeft]; - [_buttons addObject: - OFGameControllerButtonDPadRight]; - [_buttons addObject: - OFGameControllerButtonDPadUp]; - [_buttons addObject: - OFGameControllerButtonDPadDown]; - } - - if (OFBitSetIsSet(absBits, ABS_Z)) { - struct input_absinfo info; - - _hasZLPressure = true; - - if (ioctl(_fd, EVIOCGABS(ABS_Z), &info) == -1) - @throw [OFInitializationFailedException - exception]; - - _ZLMinPressure = info.minimum; - _ZLMaxPressure = info.maximum; - - [_buttons addObject: OFGameControllerButtonZL]; - } - - if (OFBitSetIsSet(absBits, ABS_RZ)) { - struct input_absinfo info; - - _hasZRPressure = true; - - if (ioctl(_fd, EVIOCGABS(ABS_RZ), &info) == -1) - @throw [OFInitializationFailedException - exception]; - - _ZRMinPressure = info.minimum; - _ZRMaxPressure = info.maximum; - - [_buttons addObject: OFGameControllerButtonZR]; - } - } - - [_buttons makeImmutable]; - - [self retrieveState]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_path release]; - - if (_fd != -1) - close(_fd); - - [_name release]; - [_buttons release]; - [_pressedButtons release]; - - [super dealloc]; -} - -- (OFNumber *)vendorID -{ - return [OFNumber numberWithUnsignedShort: _vendorID]; -} - -- (OFNumber *)productID -{ - return [OFNumber numberWithUnsignedShort: _productID]; -} - -- (void)retrieveState -{ - struct input_event event; - - for (;;) { - errno = 0; - - if (read(_fd, &event, sizeof(event)) < (int)sizeof(event)) { - if (errno == EWOULDBLOCK) - return; - - @throw [OFReadFailedException - exceptionWithObject: self - requestedLength: sizeof(event) - errNo: errno]; - } - - switch (event.type) { - case EV_KEY: - if (event.value) - [_pressedButtons addObject: buttonToName( - event.code, _vendorID, _productID)]; - else - [_pressedButtons removeObject: buttonToName( - event.code, _vendorID, _productID)]; - break; - case EV_ABS: - switch (event.code) { - case ABS_X: - _leftAnalogStickPosition.x = scale(event.value, - _leftAnalogStickMinX, _leftAnalogStickMaxX); - break; - case ABS_Y: - _leftAnalogStickPosition.y = scale(event.value, - _leftAnalogStickMinY, _leftAnalogStickMaxY); - break; - case ABS_RX: - _rightAnalogStickPosition.x = scale(event.value, - _rightAnalogStickMinX, - _rightAnalogStickMaxX); - break; - case ABS_RY: - _rightAnalogStickPosition.y = scale(event.value, - _rightAnalogStickMinY, - _rightAnalogStickMaxY); - break; - case ABS_HAT0X: - if (event.value < 0) { - [_pressedButtons addObject: - OFGameControllerButtonDPadLeft]; - [_pressedButtons removeObject: - OFGameControllerButtonDPadRight]; - } else if (event.value > 0) { - [_pressedButtons addObject: - OFGameControllerButtonDPadRight]; - [_pressedButtons removeObject: - OFGameControllerButtonDPadLeft]; - } else { - [_pressedButtons removeObject: - OFGameControllerButtonDPadLeft]; - [_pressedButtons removeObject: - OFGameControllerButtonDPadRight]; - } - break; - case ABS_HAT0Y: - if (event.value < 0) { - [_pressedButtons addObject: - OFGameControllerButtonDPadUp]; - [_pressedButtons removeObject: - OFGameControllerButtonDPadDown]; - } else if (event.value > 0) { - [_pressedButtons addObject: - OFGameControllerButtonDPadDown]; - [_pressedButtons removeObject: - OFGameControllerButtonDPadUp]; - } else { - [_pressedButtons removeObject: - OFGameControllerButtonDPadUp]; - [_pressedButtons removeObject: - OFGameControllerButtonDPadDown]; - } - break; - case ABS_Z: - _ZLPressure = scale(event.value, - _ZLMinPressure, _ZLMaxPressure); - - if (_ZLPressure > 0) - [_pressedButtons addObject: - OFGameControllerButtonZL]; - else - [_pressedButtons removeObject: - OFGameControllerButtonZL]; - break; - case ABS_RZ: - _ZRPressure = scale(event.value, - _ZRMinPressure, _ZRMaxPressure); - - if (_ZRPressure > 0) - [_pressedButtons addObject: - OFGameControllerButtonZR]; - else - [_pressedButtons removeObject: - OFGameControllerButtonZR]; - break; - } - - break; - } - } -} - -- (OFComparisonResult)compare: (OFGameController *)otherController -{ - unsigned long long selfIndex, otherIndex; - - if (![otherController isKindOfClass: [OFGameController class]]) - @throw [OFInvalidArgumentException exception]; - - selfIndex = [_path substringFromIndex: 16].unsignedLongLongValue; - otherIndex = [otherController->_path substringFromIndex: 16] - .unsignedLongLongValue; - - if (selfIndex > otherIndex) - return OFOrderedDescending; - if (selfIndex < otherIndex) - return OFOrderedAscending; - - return OFOrderedSame; -} - -- (OFSet *)pressedButtons -{ - return [[_pressedButtons copy] autorelease]; -} - -- (float)pressureForButton: (OFGameControllerButton)button -{ - if (button == OFGameControllerButtonZL && _hasZLPressure) - return _ZLPressure; - if (button == OFGameControllerButtonZR && _hasZRPressure) - return _ZRPressure; - - return ([self.pressedButtons containsObject: button] ? 1 : 0); -} - -- (OFGameControllerButton)northButton -{ - if (_vendorID == vendorIDNintendo && _productID == productIDLeftJoycon) - return nil; - if (_vendorID == vendorIDNintendo && _productID == productIDRightJoycon) - return OFGameControllerButtonX; - if (_vendorID == vendorIDNintendo && - _productID == productIDN64Controller) - return nil; - - return OFGameControllerButtonY; -} - -- (OFGameControllerButton)southButton -{ - if (_vendorID == vendorIDNintendo && _productID == productIDLeftJoycon) - return nil; - if (_vendorID == vendorIDNintendo && _productID == productIDRightJoycon) - return OFGameControllerButtonB; - if (_vendorID == vendorIDNintendo && - _productID == productIDN64Controller) - return nil; - - return OFGameControllerButtonA; -} - -- (OFGameControllerButton)westButton -{ - if (_vendorID == vendorIDNintendo && _productID == productIDLeftJoycon) - return nil; - if (_vendorID == vendorIDNintendo && _productID == productIDRightJoycon) - return OFGameControllerButtonY; - if (_vendorID == vendorIDNintendo && - _productID == productIDN64Controller) - return nil; - - return OFGameControllerButtonX; -} - -- (OFGameControllerButton)eastButton -{ - if (_vendorID == vendorIDNintendo && _productID == productIDLeftJoycon) - return nil; - if (_vendorID == vendorIDNintendo && _productID == productIDRightJoycon) - return OFGameControllerButtonA; - if (_vendorID == vendorIDNintendo && - _productID == productIDN64Controller) - return nil; - - return OFGameControllerButtonB; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; -} -@end DELETED src/platform/Nintendo3DS/OFGameController.m Index: src/platform/Nintendo3DS/OFGameController.m ================================================================== --- src/platform/Nintendo3DS/OFGameController.m +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3.0 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * version 3.0 for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * version 3.0 along with this program. If not, see - * . - */ - -#include "config.h" - -#import "OFGameController.h" -#import "OFArray.h" -#import "OFSet.h" - -#import "OFOutOfRangeException.h" - -#define id id_3ds -#include <3ds.h> -#undef id - -@interface OFGameController () -- (instancetype)of_init OF_METHOD_FAMILY(init); -@end - -static OFArray OF_GENERIC(OFGameController *) *controllers; - -static void -initControllers(void) -{ - void *pool = objc_autoreleasePoolPush(); - - controllers = [[OFArray alloc] initWithObject: - [[[OFGameController alloc] of_init] autorelease]]; - - objc_autoreleasePoolPop(pool); -} - -@implementation OFGameController -@synthesize leftAnalogStickPosition = _leftAnalogStickPosition; -@dynamic rightAnalogStickPosition; - -+ (OFArray OF_GENERIC(OFGameController *) *)controllers -{ - static OFOnceControl onceControl = OFOnceControlInitValue; - - OFOnce(&onceControl, initControllers); - - return [[controllers retain] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)of_init -{ - self = [super init]; - - @try { - _pressedButtons = [[OFMutableSet alloc] initWithCapacity: 18]; - - [self retrieveState]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_pressedButtons release]; - - [super dealloc]; -} - -- (void)retrieveState -{ - u32 keys; - circlePosition pos; - - hidScanInput(); - - keys = hidKeysHeld(); - hidCircleRead(&pos); - - [_pressedButtons removeAllObjects]; - - if (keys & KEY_A) - [_pressedButtons addObject: OFGameControllerButtonA]; - if (keys & KEY_B) - [_pressedButtons addObject: OFGameControllerButtonB]; - if (keys & KEY_SELECT) - [_pressedButtons addObject: OFGameControllerButtonSelect]; - if (keys & KEY_START) - [_pressedButtons addObject: OFGameControllerButtonStart]; - if (keys & KEY_DRIGHT) - [_pressedButtons addObject: OFGameControllerButtonDPadRight]; - if (keys & KEY_DLEFT) - [_pressedButtons addObject: OFGameControllerButtonDPadLeft]; - if (keys & KEY_DUP) - [_pressedButtons addObject: OFGameControllerButtonDPadUp]; - if (keys & KEY_DDOWN) - [_pressedButtons addObject: OFGameControllerButtonDPadDown]; - if (keys & KEY_R) - [_pressedButtons addObject: OFGameControllerButtonR]; - if (keys & KEY_L) - [_pressedButtons addObject: OFGameControllerButtonL]; - if (keys & KEY_X) - [_pressedButtons addObject: OFGameControllerButtonX]; - if (keys & KEY_Y) - [_pressedButtons addObject: OFGameControllerButtonY]; - if (keys & KEY_ZL) - [_pressedButtons addObject: OFGameControllerButtonZL]; - if (keys & KEY_ZR) - [_pressedButtons addObject: OFGameControllerButtonZR]; - if (keys & KEY_CSTICK_RIGHT) - [_pressedButtons addObject: OFGameControllerButtonCPadRight]; - if (keys & KEY_CSTICK_LEFT) - [_pressedButtons addObject: OFGameControllerButtonCPadLeft]; - if (keys & KEY_CSTICK_UP) - [_pressedButtons addObject: OFGameControllerButtonCPadUp]; - if (keys & KEY_CSTICK_DOWN) - [_pressedButtons addObject: OFGameControllerButtonCPadDown]; - - _leftAnalogStickPosition = OFMakePoint( - (float)pos.dx / (pos.dx < 0 ? -INT16_MIN : INT16_MAX), - (float)pos.dy / (pos.dy < 0 ? -INT16_MIN : INT16_MAX)); -} - -- (OFString *)name -{ - return @"Nintendo 3DS"; -} - -- (OFNumber *)vendorID -{ - return nil; -} - -- (OFNumber *)productID -{ - return nil; -} - -- (OFSet OF_GENERIC(OFGameControllerButton) *)buttons -{ - return [OFSet setWithObjects: OFGameControllerButtonA, - OFGameControllerButtonB, OFGameControllerButtonSelect, - OFGameControllerButtonStart, OFGameControllerButtonDPadRight, - OFGameControllerButtonDPadLeft, OFGameControllerButtonDPadUp, - OFGameControllerButtonDPadDown, OFGameControllerButtonR, - OFGameControllerButtonL, OFGameControllerButtonX, - OFGameControllerButtonY, OFGameControllerButtonZL, - OFGameControllerButtonZR, OFGameControllerButtonCPadRight, - OFGameControllerButtonCPadLeft, OFGameControllerButtonCPadUp, - OFGameControllerButtonCPadDown, nil]; -} - -- (OFSet OF_GENERIC(OFGameControllerButton) *)pressedButtons -{ - return [[_pressedButtons copy] autorelease]; -} - -- (bool)hasLeftAnalogStick -{ - return true; -} - -- (bool)hasRightAnalogStick -{ - return false; -} - -- (float)pressureForButton: (OFGameControllerButton)button -{ - return ([self.pressedButtons containsObject: button] ? 1 : 0); -} - -- (OFGameControllerButton)northButton -{ - return OFGameControllerButtonX; -} - -- (OFGameControllerButton)southButton -{ - return OFGameControllerButtonB; -} - -- (OFGameControllerButton)westButton -{ - return OFGameControllerButtonY; -} - -- (OFGameControllerButton)eastButton -{ - return OFGameControllerButtonA; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; -} -@end DELETED src/platform/NintendoDS/OFGameController.m Index: src/platform/NintendoDS/OFGameController.m ================================================================== --- src/platform/NintendoDS/OFGameController.m +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3.0 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * version 3.0 for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * version 3.0 along with this program. If not, see - * . - */ - -#include "config.h" - -#import "OFGameController.h" -#import "OFArray.h" -#import "OFSet.h" - -#import "OFOutOfRangeException.h" - -#define asm __asm__ -#include -#undef asm - -@interface OFGameController () -- (instancetype)of_init OF_METHOD_FAMILY(init); -@end - -static OFArray OF_GENERIC(OFGameController *) *controllers; - -static void -initControllers(void) -{ - void *pool = objc_autoreleasePoolPush(); - - controllers = [[OFArray alloc] initWithObject: - [[[OFGameController alloc] of_init] autorelease]]; - - objc_autoreleasePoolPop(pool); -} - -@implementation OFGameController -@dynamic leftAnalogStickPosition, rightAnalogStickPosition; - -+ (OFArray OF_GENERIC(OFGameController *) *)controllers -{ - static OFOnceControl onceControl = OFOnceControlInitValue; - - OFOnce(&onceControl, initControllers); - - return [[controllers retain] autorelease]; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)of_init -{ - self = [super init]; - - @try { - _pressedButtons = [[OFMutableSet alloc] initWithCapacity: 12]; - - [self retrieveState]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_pressedButtons release]; - - [super dealloc]; -} - -- (void)retrieveState -{ - uint32 keys; - - scanKeys(); - keys = keysCurrent(); - - [_pressedButtons removeAllObjects]; - - if (keys & KEY_A) - [_pressedButtons addObject: OFGameControllerButtonA]; - if (keys & KEY_B) - [_pressedButtons addObject: OFGameControllerButtonB]; - if (keys & KEY_SELECT) - [_pressedButtons addObject: OFGameControllerButtonSelect]; - if (keys & KEY_START) - [_pressedButtons addObject: OFGameControllerButtonStart]; - if (keys & KEY_RIGHT) - [_pressedButtons addObject: OFGameControllerButtonDPadRight]; - if (keys & KEY_LEFT) - [_pressedButtons addObject: OFGameControllerButtonDPadLeft]; - if (keys & KEY_UP) - [_pressedButtons addObject: OFGameControllerButtonDPadUp]; - if (keys & KEY_DOWN) - [_pressedButtons addObject: OFGameControllerButtonDPadDown]; - if (keys & KEY_R) - [_pressedButtons addObject: OFGameControllerButtonR]; - if (keys & KEY_L) - [_pressedButtons addObject: OFGameControllerButtonL]; - if (keys & KEY_X) - [_pressedButtons addObject: OFGameControllerButtonX]; - if (keys & KEY_Y) - [_pressedButtons addObject: OFGameControllerButtonY]; -} - -- (OFString *)name -{ - return @"Nintendo DS"; -} - -- (OFNumber *)vendorID -{ - return nil; -} - -- (OFNumber *)productID -{ - return nil; -} - -- (OFSet OF_GENERIC(OFGameControllerButton) *)buttons -{ - return [OFSet setWithObjects: OFGameControllerButtonA, - OFGameControllerButtonB, OFGameControllerButtonSelect, - OFGameControllerButtonStart, OFGameControllerButtonDPadRight, - OFGameControllerButtonDPadLeft, OFGameControllerButtonDPadUp, - OFGameControllerButtonDPadDown, OFGameControllerButtonR, - OFGameControllerButtonL, OFGameControllerButtonX, - OFGameControllerButtonY, nil]; -} - -- (OFSet OF_GENERIC(OFGameControllerButton) *)pressedButtons -{ - return [[_pressedButtons copy] autorelease]; -} - -- (bool)hasLeftAnalogStick -{ - return false; -} - -- (bool)hasRightAnalogStick -{ - return false; -} - -- (float)pressureForButton: (OFGameControllerButton)button -{ - return ([self.pressedButtons containsObject: button] ? 1 : 0); -} - -- (OFGameControllerButton)northButton -{ - return OFGameControllerButtonX; -} - -- (OFGameControllerButton)southButton -{ - return OFGameControllerButtonB; -} - -- (OFGameControllerButton)westButton -{ - return OFGameControllerButtonY; -} - -- (OFGameControllerButton)eastButton -{ - return OFGameControllerButtonA; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; -} -@end DELETED src/platform/Windows/OFGameController.m Index: src/platform/Windows/OFGameController.m ================================================================== --- src/platform/Windows/OFGameController.m +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) 2008-2024 Jonathan Schleifer - * - * All rights reserved. - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version 3.0 only, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * version 3.0 for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * version 3.0 along with this program. If not, see - * . - */ - -#include "config.h" - -#import "OFGameController.h" -#import "OFArray.h" -#import "OFNumber.h" -#import "OFSet.h" - -#import "OFInitializationFailedException.h" -#import "OFReadFailedException.h" - -#include - -@interface OFGameController () -- (instancetype)of_initWithIndex: (DWORD)index OF_METHOD_FAMILY(init); -@end - -struct XInputCapabilitiesEx { - XINPUT_CAPABILITIES capabilities; - WORD vendorID; - WORD productID; - WORD versionNumber; - WORD unknown1; - DWORD unknown2; -}; - -static WINAPI DWORD (*XInputGetStateFuncPtr)(DWORD, XINPUT_STATE *); -static WINAPI DWORD (*XInputGetCapabilitiesExFuncPtr)(DWORD, DWORD, DWORD, - struct XInputCapabilitiesEx *); - -@implementation OFGameController -@synthesize vendorID = _vendorID, productID = _productID; -@synthesize leftAnalogStickPosition = _leftAnalogStickPosition; -@synthesize rightAnalogStickPosition = _rightAnalogStickPosition; - -+ (void)initialize -{ - HMODULE module; - - if (self != [OFGameController class]) - return; - - if ((module = LoadLibraryA("xinput1_4.dll")) != NULL) { - XInputGetStateFuncPtr = - (WINAPI DWORD (*)(DWORD, XINPUT_STATE *)) - GetProcAddress(module, "XInputGetState"); - XInputGetCapabilitiesExFuncPtr = (WINAPI DWORD (*)(DWORD, DWORD, - DWORD, struct XInputCapabilitiesEx *)) - GetProcAddress(module, "XInputGetCapabilitiesEx"); - } -} - -+ (OFArray OF_GENERIC(OFGameController *) *)controllers -{ - OFMutableArray *controllers = [OFMutableArray array]; - - if (XInputGetStateFuncPtr != NULL) { - void *pool = objc_autoreleasePoolPush(); - - for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) { - OFGameController *controller; - - @try { - controller = [[[OFGameController alloc] - of_initWithIndex: i] autorelease]; - } @catch (OFInitializationFailedException *e) { - /* Controller does not exist. */ - continue; - } - - [controllers addObject: controller]; - } - - objc_autoreleasePoolPop(pool); - } - - [controllers makeImmutable]; - - return controllers; -} - -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)of_initWithIndex: (DWORD)index -{ - self = [super init]; - - @try { - XINPUT_STATE state = { 0 }; - - if (XInputGetStateFuncPtr(index, &state) == - ERROR_DEVICE_NOT_CONNECTED) - @throw [OFInitializationFailedException exception]; - - _index = index; - - if (XInputGetCapabilitiesExFuncPtr != NULL) { - struct XInputCapabilitiesEx capabilities; - - if (XInputGetCapabilitiesExFuncPtr(1, _index, - XINPUT_FLAG_GAMEPAD, &capabilities) == - ERROR_SUCCESS) { - _vendorID = [[OFNumber alloc] - initWithUnsignedShort: - capabilities.vendorID]; - _productID = [[OFNumber alloc] - initWithUnsignedShort: - capabilities.productID]; - } - } - - _pressedButtons = [[OFMutableSet alloc] initWithCapacity: 16]; - - [self retrieveState]; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; -} - -- (void)dealloc -{ - [_vendorID release]; - [_productID release]; - [_pressedButtons release]; - - [super dealloc]; -} - -- (void)retrieveState -{ - XINPUT_STATE state = { 0 }; - - if (XInputGetStateFuncPtr(_index, &state) != ERROR_SUCCESS) - @throw [OFReadFailedException exceptionWithObject: self - requestedLength: sizeof(state) - errNo: 0]; - - [_pressedButtons removeAllObjects]; - - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP) - [_pressedButtons addObject: OFGameControllerButtonDPadUp]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN) - [_pressedButtons addObject: OFGameControllerButtonDPadDown]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT) - [_pressedButtons addObject: OFGameControllerButtonDPadLeft]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT) - [_pressedButtons addObject: OFGameControllerButtonDPadRight]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_START) - [_pressedButtons addObject: OFGameControllerButtonStart]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_BACK) - [_pressedButtons addObject: OFGameControllerButtonSelect]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB) - [_pressedButtons addObject: OFGameControllerButtonLeftStick]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB) - [_pressedButtons addObject: OFGameControllerButtonRightStick]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER) - [_pressedButtons addObject: OFGameControllerButtonL]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER) - [_pressedButtons addObject: OFGameControllerButtonR]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_A) - [_pressedButtons addObject: OFGameControllerButtonA]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_B) - [_pressedButtons addObject: OFGameControllerButtonB]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_X) - [_pressedButtons addObject: OFGameControllerButtonX]; - if (state.Gamepad.wButtons & XINPUT_GAMEPAD_Y) - [_pressedButtons addObject: OFGameControllerButtonY]; - - _ZLPressure = (float)state.Gamepad.bLeftTrigger / 255; - _ZRPressure = (float)state.Gamepad.bRightTrigger / 255; - - if (_ZLPressure > 0) - [_pressedButtons addObject: OFGameControllerButtonZL]; - if (_ZRPressure > 0) - [_pressedButtons addObject: OFGameControllerButtonZR]; - - _leftAnalogStickPosition = OFMakePoint( - (float)state.Gamepad.sThumbLX / - (state.Gamepad.sThumbLX < 0 ? -INT16_MIN : INT16_MAX), - -(float)state.Gamepad.sThumbLY / - (state.Gamepad.sThumbLY < 0 ? -INT16_MIN : INT16_MAX)); - _rightAnalogStickPosition = OFMakePoint( - (float)state.Gamepad.sThumbRX / - (state.Gamepad.sThumbRX < 0 ? -INT16_MIN : INT16_MAX), - -(float)state.Gamepad.sThumbRY / - (state.Gamepad.sThumbRY < 0 ? -INT16_MIN : INT16_MAX)); -} - -- (OFString *)name -{ - return @"XInput 1.3"; -} - -- (OFSet OF_GENERIC(OFGameControllerButton) *)buttons -{ - return [OFSet setWithObjects: - OFGameControllerButtonA, OFGameControllerButtonB, - OFGameControllerButtonX, OFGameControllerButtonY, - OFGameControllerButtonL, OFGameControllerButtonR, - OFGameControllerButtonZL, OFGameControllerButtonZR, - OFGameControllerButtonStart, OFGameControllerButtonSelect, - OFGameControllerButtonLeftStick, OFGameControllerButtonRightStick, - OFGameControllerButtonDPadLeft, OFGameControllerButtonDPadRight, - OFGameControllerButtonDPadUp, OFGameControllerButtonDPadDown, nil]; -} - -- (OFSet OF_GENERIC(OFGameControllerButton) *)pressedButtons -{ - return [[_pressedButtons copy] autorelease]; -} - -- (bool)hasLeftAnalogStick -{ - return true; -} - -- (bool)hasRightAnalogStick -{ - return true; -} - -- (float)pressureForButton: (OFGameControllerButton)button -{ - if (button == OFGameControllerButtonZL) - return _ZLPressure; - if (button == OFGameControllerButtonZR) - return _ZRPressure; - - return ([self.pressedButtons containsObject: button] ? 1 : 0); -} - -- (OFGameControllerButton)northButton -{ - return OFGameControllerButtonY; -} - -- (OFGameControllerButton)southButton -{ - return OFGameControllerButtonA; -} - -- (OFGameControllerButton)westButton -{ - return OFGameControllerButtonX; -} - -- (OFGameControllerButton)eastButton -{ - return OFGameControllerButtonB; -} - -- (OFString *)description -{ - return [OFString stringWithFormat: @"<%@: %@>", self.class, self.name]; -} -@end Index: src/test/Makefile ================================================================== --- src/test/Makefile +++ src/test/Makefile @@ -20,10 +20,11 @@ CPPFLAGS += -I. \ -I.. \ -I../.. \ -I../exceptions \ -I../runtime \ + -I../hid \ -DOBJFWTEST_LOCAL_INCLUDES LD = ${OBJC} FRAMEWORK_LIBS := -F.. \ -framework ObjFW \ -F../runtime \ Index: src/test/ObjFWTest.oc ================================================================== --- src/test/ObjFWTest.oc +++ src/test/ObjFWTest.oc @@ -1,4 +1,5 @@ package_format 1 +package_depends_on ObjFWHID LIBS="-lobjfwtest $LIBS" FRAMEWORK_LIBS="-lobjfwtest $FRAMEWORK_LIBS" STATIC_LIBS="${libdir}/libobjfwtest.a $STATIC_LIBS" Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -122,10 +122,14 @@ rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + rm -f libobjfwhid.so.${OBJFWHID_LIB_MAJOR} + rm -f libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR} + rm -f objfwhid${OBJFWHID_LIB_MAJOR}.dll + rm -f libobjfwhid.${OBJFWHID_LIB_MAJOR}.dylib if test -f ../src/libobjfw.so; then \ ${LN_S} ../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ @@ -132,11 +136,11 @@ ${LN_S} ../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ fi if test -f ../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ ${LN_S} ../src/objfw${OBJFW_LIB_MAJOR}.dll \ - objfw${OBJFW_LIB_MAJOR}.dll; \ + objfw${OBJFW_LIB_MAJOR}.dll; \ fi if test -f ../src/libobjfw.dylib; then \ ${LN_S} ../src/libobjfw.dylib \ libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ fi @@ -143,23 +147,44 @@ if test -f ../src/runtime/libobjfwrt.so; then \ ${LN_S} ../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ ${LN_S} ../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ - elif test -f ../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ - ${LN_S} ../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + elif test -f ../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + then \ + ${LN_S} \ + ../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} \ + libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ fi if test -f ../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ ${LN_S} ../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ - objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ + objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ fi if test -f ../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ fi + if test -f ../src/hid/libobjfwhid.so; then \ + ${LN_S} ../src/hid/libobjfwhid.so \ + libobjfwhid.so.${OBJFWHID_LIB_MAJOR}; \ + ${LN_S} ../src/hid/libobjfwhid.so \ + libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR}; \ + elif test -f ../src/hid/libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR}; \ + then \ + ${LN_S} ../src/hid/libobjfwhid.so.${OBJFWHIID_LIB_MAJOR_MINOR} \ + libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR}; \ + fi + if test -f ../src/hid/objfwhid${OBJFWHID_LIB_MAJOR}.dll; then \ + ${LN_S} ../src/hid/objfwhid${OBJFWHID_LIB_MAJOR}.dll \ + objfwhid${OBJFWHID_LIB_MAJOR}.dll; \ + fi + if test -f ../src/hid/libobjfwhid.dylib; then \ + ${LN_S} ../src/hid/libobjfwhid.dylib \ + libobjfwhid.${OBJFWHID_LIB_MAJOR}.dylib; \ + fi LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ - DYLD_FRAMEWORK_PATH=../src:../src/runtime$${DYLD_FRAMEWORK_PATH+:}$$DYLD_FRAMEWORK_PATH \ + DYLD_FRAMEWORK_PATH=../src:../src/runtime:../src/hid$${DYLD_FRAMEWORK_PATH+:}$$DYLD_FRAMEWORK_PATH \ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ ASAN_OPTIONS=allocator_may_return_null=1 \ ${WRAPPER} ./${PROG_NOINST} ${TESTCASES}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ @@ -168,10 +193,14 @@ rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ + rm -f libobjfwhid.so.${OBJFWHID_LIB_MAJOR}; \ + rm -f libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR}; \ + rm -f objfwhid${OBJFWHID_LIB_MAJOR}.dll; \ + rm -f libobjfwhid.${OBJFWHID_LIB_MAJOR}.dylib; \ exit $$EXIT run-on-android: all echo "Uploading files to Android device..." if test -f ../src/libobjfw.so; then \ @@ -180,10 +209,14 @@ fi if test -f ../src/runtime/libobjfwrt.so; then \ adb push ../src/runtime/libobjfwrt.so \ /data/local/tmp/objfw/libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ fi + if test -f ../src/hid/libobjfwhid.so; then \ + adb push ../src/hid/libobjfwhid.so \ + /data/local/tmp/objfw/libobjfwhid.so.${OBJFWHID_LIB_MAJOR}; \ + fi adb push tests /data/local/tmp/objfw/tests adb push testfile.txt /data/local/tmp/objfw/testfile.txt if test -f plugin/TestPlugin.so; then \ adb push plugin/TestPlugin.so \ /data/local/tmp/objfw/plugin/TestPlugin.so; \ @@ -198,11 +231,12 @@ pack-pbp $@ PARAM.SFO NULL NULL NULL NULL NULL ${PROG_NOINST} NULL boot.dol: ${PROG_NOINST} elf2dol ${PROG_NOINST} $@ -${PROG_NOINST}: ${LIBOBJFW_DEP} ${LIBOBJFWRT_DEP} ../src/test/libobjfwtest.a +${PROG_NOINST}: ${LIBOBJFW_DEP} ${LIBOBJFWRT_DEP} ../src/test/libobjfwtest.a \ + ${LIBOBJFWHID_DEP} ${PROG_NOINST}.3dsx: ${PROG_NOINST} 3dsxtool $< $@ ${PROG_NOINST}.arm9: ${PROG_NOINST} @@ -239,11 +273,12 @@ # main. Just moving -lobjfwtest later doesn't work either, as then the linker # cannot find ObjFW symbols. So the only solution is to list everything twice, # but hide it behind a variable because listing it twice causes a warning on # macOS. LIBS := -L../src/test \ + -L../src/hid \ -lobjfwtest \ ${TESTS_LIBS} \ ${LIBS} \ ${WII_U_TESTS_LIBS} LDFLAGS += ${MAP_LDFLAGS} LD = ${OBJC} Index: tests/gamecontroller/Makefile ================================================================== --- tests/gamecontroller/Makefile +++ tests/gamecontroller/Makefile @@ -12,10 +12,14 @@ rm -f objfw${OBJFW_LIB_MAJOR}.dll libobjfw.${OBJFW_LIB_MAJOR}.dylib rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR} rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib + rm -f libobjfwhid.so.${OBJFWHID_LIB_MAJOR} + rm -f libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR} + rm -f objfwhid${OBJFWHID_LIB_MAJOR}.dll + rm -f libobjfwhid.${OBJFWHID_LIB_MAJOR}.dylib if test -f ../../src/libobjfw.so; then \ ${LN_S} ../../src/libobjfw.so libobjfw.so.${OBJFW_LIB_MAJOR}; \ ${LN_S} ../../src/libobjfw.so \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ elif test -f ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; then \ @@ -22,11 +26,11 @@ ${LN_S} ../../src/libobjfw.so.${OBJFW_LIB_MAJOR_MINOR} \ libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ fi if test -f ../../src/objfw${OBJFW_LIB_MAJOR}.dll; then \ ${LN_S} ../../src/objfw${OBJFW_LIB_MAJOR}.dll \ - objfw${OBJFW_LIB_MAJOR}.dll; \ + objfw${OBJFW_LIB_MAJOR}.dll; \ fi if test -f ../../src/libobjfw.dylib; then \ ${LN_S} ../../src/libobjfw.dylib \ libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ fi @@ -33,33 +37,69 @@ if test -f ../../src/runtime/libobjfwrt.so; then \ ${LN_S} ../../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ ${LN_S} ../../src/runtime/libobjfwrt.so \ libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ - elif test -f ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ - ${LN_S} ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ + elif test -f ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; then \ + ${LN_S} \ + ../../src/runtime/libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR} \ + libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ fi if test -f ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll; then \ ${LN_S} ../../src/runtime/objfwrt${OBJFWRT_LIB_MAJOR}.dll \ - objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ + objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ fi if test -f ../../src/runtime/libobjfwrt.dylib; then \ ${LN_S} ../../src/runtime/libobjfwrt.dylib \ libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ + fi + if test -f ../../src/hid/libobjfwhid.so; then \ + ${LN_S} ../../src/hid/libobjfwhid.so \ + libobjfwhid.so.${OBJFWHID_LIB_MAJOR}; \ + ${LN_S} ../../src/hid/libobjfwhid.so \ + libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR}; \ + elif test -f ../../src/hid/libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR}; \ + then \ + ${LN_S} ../../src/hid/libobjfwhid.so.${OBJFWHIID_LIB_MAJOR_MINOR} \ + libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR}; \ + fi + if test -f ../../src/hid/objfwhid${OBJFWHID_LIB_MAJOR}.dll; then \ + ${LN_S} ../../src/hid/objfwhid${OBJFWHID_LIB_MAJOR}.dll \ + objfwhid${OBJFWHID_LIB_MAJOR}.dll; \ + fi + if test -f ../../src/hid/libobjfwhid.dylib; then \ + ${LN_S} ../../src/hid/libobjfwhid.dylib \ + libobjfwhid.${OBJFWHID_LIB_MAJOR}.dylib; \ fi LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH+:}$$LD_LIBRARY_PATH \ + DYLD_FRAMEWORK_PATH=../../src:../../src/runtime:../../src/hid$${DYLD_FRAMEWORK_PATH+:}$$DYLD_FRAMEWORK_PATH \ DYLD_LIBRARY_PATH=.$${DYLD_LIBRARY_PATH+:}$$DYLD_LIBRARY_PATH \ LIBRARY_PATH=.$${LIBRARY_PATH+:}$$LIBRARY_PATH \ - ${WRAPPER} ./${PROG_NOINST}; EXIT=$$?; \ + ASAN_OPTIONS=allocator_may_return_null=1 \ + ${WRAPPER} ./${PROG_NOINST} ${TESTCASES}; EXIT=$$?; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR}; \ rm -f libobjfw.so.${OBJFW_LIB_MAJOR_MINOR}; \ rm -f objfw${OBJFW_LIB_MAJOR}.dll; \ rm -f libobjfw.${OBJFW_LIB_MAJOR}.dylib; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR}; \ rm -f libobjfwrt.so.${OBJFWRT_LIB_MAJOR_MINOR}; \ rm -f objfwrt${OBJFWRT_LIB_MAJOR}.dll; \ rm -f libobjfwrt.${OBJFWRT_LIB_MAJOR}.dylib; \ + rm -f libobjfwhid.so.${OBJFWHID_LIB_MAJOR}; \ + rm -f libobjfwhid.so.${OBJFWHID_LIB_MAJOR_MINOR}; \ + rm -f objfwhid${OBJFWHID_LIB_MAJOR}.dll; \ + rm -f libobjfwhid.${OBJFWHID_LIB_MAJOR}.dylib; \ exit $$EXIT -CPPFLAGS += -I../../src -I../../src/exceptions -I../../src/runtime -I../.. -LIBS := -L../../src -lobjfw -L../../src/runtime ${RUNTIME_LIBS} ${LIBS} +${PROG_NOINST}: ${LIBOBJFW_DEP_LVL2} ${LIBOBJFWRT_DEP_LVL2} \ + ${LIBOBJFWHID_DEP_LVL2} + +CPPFLAGS += -I../../src \ + -I../../src/exceptions \ + -I../../src/hid \ + -I../../src/runtime \ + -I../.. +LIBS := -L../../src/hid -lobjfwhid \ + -L../../src -lobjfw \ + -L../../src/runtime ${RUNTIME_LIBS} \ + ${LIBS} LD = ${OBJC}