mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-05-12 12:00:13 +00:00
Reorg. game controller and update libstem_gamepad
This commit is contained in:
parent
059a41a86f
commit
79c531f2bb
13
Makefile
13
Makefile
|
@ -270,8 +270,17 @@ endif
|
|||
|
||||
ifneq ($(filter y,$(DEP_DEVICEINPUT)),)
|
||||
EXE_LIBS += $(QB_DEVICE_INPUT_LIB)
|
||||
|
||||
CXXFLAGS += -DDEPENDENCY_DEVICEINPUT
|
||||
ifeq ($(OS),win)
|
||||
CXXLIBS += -lwinmm -lxinput -ldinput8 -ldxguid -lwbemuuid -lole32 -loleaut32
|
||||
endif
|
||||
ifeq ($(OS),osx)
|
||||
CXXLIBS += -framework CoreFoundation -framework IOKit
|
||||
endif
|
||||
QBLIB_NAME := $(addsuffix 1,$(QBLIB_NAME))
|
||||
|
||||
LICENSE_IN_USE += libstem_gamepad
|
||||
else
|
||||
QBLIB_NAME := $(addsuffix 0,$(QBLIB_NAME))
|
||||
endif
|
||||
|
@ -345,10 +354,6 @@ ifeq ($(OS),win)
|
|||
CXXLIBS += -lwinspool
|
||||
endif
|
||||
|
||||
ifneq ($(filter y,$(DEP_DEVICEINPUT)),)
|
||||
CXXLIBS += -lwinmm
|
||||
endif
|
||||
|
||||
ifneq ($(filter y,$(DEP_ICON) $(DEP_ICON_RC) $(DEP_SCREENIMAGE) $(DEP_PRINTER)),)
|
||||
CXXLIBS += -lgdi32
|
||||
endif
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "datetime.h"
|
||||
#include "event.h"
|
||||
#include "font.h"
|
||||
#include "game_controller.h"
|
||||
#include "glut-thread.h"
|
||||
#include "gui.h"
|
||||
#include "http.h"
|
||||
|
@ -1236,31 +1237,9 @@ int32 key_display_state = 0;
|
|||
int32 key_display = 0;
|
||||
int32 key_display_redraw = 0;
|
||||
|
||||
extern int32 device_last;
|
||||
extern int32 device_max;
|
||||
extern device_struct *devices;
|
||||
|
||||
extern uint8 getDeviceEventButtonValue(device_struct *device, int32 eventIndex, int32 objectIndex);
|
||||
extern void setDeviceEventButtonValue(device_struct *device, int32 eventIndex, int32 objectIndex, uint8 value);
|
||||
extern float getDeviceEventAxisValue(device_struct *device, int32 eventIndex, int32 objectIndex);
|
||||
extern void setDeviceEventAxisValue(device_struct *device, int32 eventIndex, int32 objectIndex, float value);
|
||||
extern float getDeviceEventWheelValue(device_struct *device, int32 eventIndex, int32 objectIndex);
|
||||
extern void setDeviceEventWheelValue(device_struct *device, int32 eventIndex, int32 objectIndex, float value);
|
||||
extern void setupDevice(device_struct *device);
|
||||
extern int32 createDeviceEvent(device_struct *device);
|
||||
extern void commitDeviceEvent(device_struct *device);
|
||||
|
||||
extern ontimer_struct *ontimer;
|
||||
extern onkey_struct *onkey;
|
||||
extern int32 onkey_inprogress;
|
||||
extern onstrig_struct *onstrig;
|
||||
extern int32 onstrig_inprogress;
|
||||
|
||||
extern uint32 qbevent;
|
||||
|
||||
#ifdef DEPENDENCY_DEVICEINPUT
|
||||
# include "parts/input/game_controller/src.c"
|
||||
#endif
|
||||
|
||||
extern int32 console;
|
||||
extern int32 screen_hide_startup;
|
||||
|
|
|
@ -7,5 +7,6 @@ void error(int32_t error_number);
|
|||
void evnt(uint32_t linenumber, uint32_t inclinenumber = 0, const char *incfilename = NULL);
|
||||
|
||||
extern uint32_t new_error;
|
||||
extern uint32_t qbevent;
|
||||
|
||||
#endif
|
||||
|
|
29
internal/c/libqb/include/game_controller.h
Normal file
29
internal/c/libqb/include/game_controller.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// QB64-PE Game Controller Library
|
||||
// Powered by libstem Gamepad (https://github.com/ThemsAllTook/libstem_gamepad)
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct device_struct;
|
||||
struct onstrig_struct;
|
||||
|
||||
extern int32_t device_last;
|
||||
extern int32_t device_max;
|
||||
extern device_struct *devices;
|
||||
extern onstrig_struct *onstrig;
|
||||
extern int32_t onstrig_inprogress;
|
||||
|
||||
uint8_t getDeviceEventButtonValue(device_struct *device, int32_t eventIndex, int32_t objectIndex);
|
||||
void setDeviceEventButtonValue(device_struct *device, int32_t eventIndex, int32_t objectIndex, uint8_t value);
|
||||
float getDeviceEventAxisValue(device_struct *device, int32_t eventIndex, int32_t objectIndex);
|
||||
void setDeviceEventAxisValue(device_struct *device, int32_t eventIndex, int32_t objectIndex, float value);
|
||||
float getDeviceEventWheelValue(device_struct *device, int32_t eventIndex, int32_t objectIndex);
|
||||
void setDeviceEventWheelValue(device_struct *device, int32_t eventIndex, int32_t objectIndex, float value);
|
||||
void setupDevice(device_struct *device);
|
||||
int32_t createDeviceEvent(device_struct *device);
|
||||
void commitDeviceEvent(device_struct *device);
|
||||
|
||||
void QB64_GAMEPAD_INIT();
|
||||
void QB64_GAMEPAD_POLL();
|
||||
void QB64_GAMEPAD_SHUTDOWN();
|
|
@ -4,21 +4,27 @@ ifeq ($(OS),lnx)
|
|||
endif
|
||||
|
||||
ifeq ($(OS),win)
|
||||
GAMEPAD_SRCS := Gamepad_windows_mm.c Gamepad_private.c
|
||||
GAMEPAD_SRCS := Gamepad_windows_dinput.c Gamepad_private.c
|
||||
endif
|
||||
|
||||
ifeq ($(OS),osx)
|
||||
GAMEPAD_SRCS := Gamepad_macosx.c Gamepad_private.c
|
||||
endif
|
||||
|
||||
GAMEPAD_OBJS := $(GAMEPAD_SRCS:.c=.o)
|
||||
GAMEPAD_OBJS := $(patsubst %,$(PATH_INTERNAL_C)/parts/input/game_controller/src/%,$(GAMEPAD_OBJS))
|
||||
GAMECONTROLLER_SRCS := game_controller.cpp
|
||||
|
||||
$(PATH_INTERNAL_C)/parts/input/game_controller/src/%.o: $(PATH_INTERNAL_C)/parts/input/game_controller/src/%.c
|
||||
$(CC) -Wall $< -c -o $@
|
||||
GAMEPAD_OBJS := $(patsubst %.c,$(PATH_INTERNAL_C)/parts/input/game_controller/libstem_gamepad/%.o,$(GAMEPAD_SRCS))
|
||||
|
||||
QB_DEVICE_INPUT_LIB := $(PATH_INTERNAL_C)/parts/input/game_controller/src.a
|
||||
GAMECONTROLLER_OBJS := $(patsubst %.cpp,$(PATH_INTERNAL_C)/parts/input/game_controller/%.o,$(GAMECONTROLLER_SRCS))
|
||||
|
||||
$(QB_DEVICE_INPUT_LIB): $(GAMEPAD_OBJS)
|
||||
$(AR) rcs $@ $(GAMEPAD_OBJS)
|
||||
$(PATH_INTERNAL_C)/parts/input/game_controller/libstem_gamepad/%.o: $(PATH_INTERNAL_C)/parts/input/game_controller/libstem_gamepad/%.c
|
||||
$(CC) -O2 $(CFLAGS) -Wall $< -c -o $@
|
||||
|
||||
$(PATH_INTERNAL_C)/parts/input/game_controller/%.o: $(PATH_INTERNAL_C)/parts/input/game_controller/%.cpp
|
||||
$(CXX) -O2 $(CXXFLAGS) -Wall $< -c -o $@
|
||||
|
||||
QB_DEVICE_INPUT_LIB := $(PATH_INTERNAL_C)/parts/input/game_controller/game_controller.a
|
||||
|
||||
$(QB_DEVICE_INPUT_LIB): $(GAMEPAD_OBJS) $(GAMECONTROLLER_OBJS)
|
||||
$(AR) rcs $@ $(GAMEPAD_OBJS) $(GAMECONTROLLER_OBJS)
|
||||
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
1.4.0 (2014-04-06)
|
||||
* Windows implementation completely redone to use DirectInput and XInput instead of joyGetPosEx
|
||||
* Added MSVC support
|
||||
|
||||
1.3.1 (2014-02-01)
|
||||
* Gamepad_init() on Mac OS X now detects devices immediately rather than waiting until the next run loop cycle
|
||||
* Gamepad_detectDevices() and Gamepad_processEvents() now work on Mac OS X in applicactions that call them outside the main CF/NSRunLoop
|
||||
* Fixed a bug on Mac OS X that could cause a crash on Gamepad_shutdown()
|
||||
* Removed all remaining stem library dependencies (shell, glutshell, and glgraphics for testharness)
|
||||
|
||||
1.3.0 (2013-09-01)
|
||||
* Gamepad callbacks now include context pointers
|
||||
* Axis move callback now reports previous axis value in addition to current one
|
||||
* Fixed a major bug (introduced in 1.2.0) that caused button up events never to be reported on Windows
|
||||
|
||||
1.2.0 (2013-07-18)
|
||||
* Removed dependencies on utilities and stemobject. Library is now completely standalone, though test harness still requires shell and glutshell.
|
||||
* Gamepad API no longer uses EventDispatcher, instead providing GLUT-style callback registration for all previous event types
|
||||
|
||||
1.1.6 (2013-07-17)
|
||||
* Added 64-bit Windows and Linux support
|
||||
|
||||
1.1.5 (2011-11-16)
|
||||
* Gamepad_detectDevices() significantly sped up on Linux
|
||||
|
||||
1.1.4 (2011-11-08)
|
||||
* Gamepad_processEvents() will now do nothing if called from within itself
|
||||
|
||||
1.1.3 (2011-09-29)
|
||||
* Updated event dispatching to work with utilities 1.5.0
|
||||
|
||||
1.1.2 (2011-09-20)
|
||||
* Updated dependencies: utilities 1.4.0 -> 1.4.2
|
||||
|
||||
1.1.1 (2011-08-24)
|
||||
* Fixed crashes from retrieving gamepad description strings
|
||||
* Fixed a memory leak
|
||||
* Fixed a potential thread deadlock on Linux
|
||||
* Removed leftover joystick debug code
|
||||
|
||||
1.1.0 (2010-01-28)
|
||||
* Added vendor and product ID fields to Gamepad_device
|
||||
* Worked around a crash on the Mac with Sixaxis controllers
|
||||
* Fixed a problem that caused Saitek X52 hat switches to report incorrect values on Mac OS X
|
||||
|
||||
1.0.0 (2010-01-19)
|
||||
* Initial version
|
|
@ -1,787 +0,0 @@
|
|||
.PHONY: all
|
||||
all: library testharness include
|
||||
|
||||
UNAME = ${shell uname}
|
||||
ifeq (${UNAME},Linux)
|
||||
-include ~/.stem.defines
|
||||
STEM_SHARED_DIR ?= /usr/local/stem
|
||||
HOST_PLATFORM = linux
|
||||
else ifeq (${UNAME},Darwin)
|
||||
-include ~/.stem.defines
|
||||
STEM_SHARED_DIR ?= /usr/local/stem
|
||||
HOST_PLATFORM = macosx
|
||||
else
|
||||
STEM_SHARED_DIR ?= C:/stem
|
||||
-include ${STEM_SHARED_DIR}/stem.defines
|
||||
HOST_PLATFORM = windows
|
||||
endif
|
||||
|
||||
include version
|
||||
|
||||
define newline_and_tab
|
||||
|
||||
|
||||
endef
|
||||
|
||||
iphone_sdk_version_integer = ${subst .,0,$1}${word ${words ${wordlist 2, ${words ${subst ., ,$1}}, ${subst ., ,$1}}}, 00}
|
||||
|
||||
TARGET_PLATFORMS_macosx = macosx iphonesimulator iphoneos
|
||||
TARGET_PLATFORMS_linux = linux32 linux64
|
||||
TARGET_PLATFORMS_windows = win32 win64
|
||||
|
||||
PROJECT_NAME = gamepad
|
||||
IPHONE_BUILD_SDK_VERSION ?= 4.2
|
||||
IPHONE_DEPLOYMENT_TARGET_VERSION ?= 3.1
|
||||
CODESIGN_IDENTITY ?= "iPhone Developer"
|
||||
|
||||
LIBRARY_TARGETS = library
|
||||
EXECUTABLE_TARGETS =
|
||||
APPLICATION_TARGETS = testharness
|
||||
TARGETS = ${LIBRARY_TARGETS} ${EXECUTABLE_TARGETS} ${APPLICATION_TARGETS}
|
||||
PLATFORMS = ${filter ${TARGET_PLATFORMS_${HOST_PLATFORM}},macosx linux32 linux64 win32 win64}
|
||||
ANALYZERS = splint clang
|
||||
|
||||
TARGET_NAME_library = libstem_${PROJECT_NAME}
|
||||
TARGET_NAME_unittest = ${PROJECT_NAME}_unittest
|
||||
TARGET_NAME_testharness = ${PROJECT_NAME}_testharness
|
||||
HUMAN_READABLE_TARGET_NAME_testharness = GamepadTestHarness
|
||||
|
||||
#Per-target configurations
|
||||
CONFIGURATIONS_library = debug profile release
|
||||
CONFIGURATIONS_unittest = debug
|
||||
CONFIGURATIONS_testharness = debug profile release
|
||||
|
||||
#Per-target platforms
|
||||
PLATFORMS_library = ${filter ${PLATFORMS},macosx linux32 linux64 win32 win64}
|
||||
PLATFORMS_unittest = ${filter ${PLATFORMS},macosx linux32 linux64 win32 win64}
|
||||
PLATFORMS_testharness = ${filter ${PLATFORMS},macosx linux32 linux64 win32 win64}
|
||||
|
||||
#Per-target compile/link settings
|
||||
CCFLAGS_testharness = -DGLEW_STATIC
|
||||
|
||||
#Per-target analyzer settings
|
||||
CLANGFLAGS_unittest = ${CCFLAGS_unittest}
|
||||
SPLINTFLAGS_unittest = ${CCFLAGS_unittest}
|
||||
|
||||
#Per-configuration compile/link settings
|
||||
CCFLAGS_debug = -g -DDEBUG
|
||||
CCFLAGS_profile = -g -O3
|
||||
CCFLAGS_release = -O3
|
||||
|
||||
#Per-platform compile/link settings
|
||||
CC_macosx_i386 = /usr/bin/clang -arch i386
|
||||
CC_macosx_x86_64 = /usr/bin/clang -arch x86_64
|
||||
AR_macosx = /usr/bin/ar
|
||||
RANLIB_macosx = /usr/bin/ranlib
|
||||
SPLINT_macosx = /usr/local/bin/splint
|
||||
CLANG_macosx = /usr/bin/clang
|
||||
SDKROOT_macosx = /Developer/SDKs/MacOSX10.6.sdk
|
||||
ARCHS_macosx = i386 x86_64
|
||||
CCFLAGS_macosx = -isysroot ${SDKROOT_macosx} -mmacosx-version-min=10.6
|
||||
LINKFLAGS_macosx = -isysroot ${SDKROOT_macosx} -mmacosx-version-min=10.6 -framework IOKit -framework CoreFoundation -framework OpenGL -framework GLUT -framework ApplicationServices
|
||||
|
||||
CC_linux32_i386 = /usr/bin/gcc
|
||||
AR_linux32 = /usr/bin/ar
|
||||
RANLIB_linux32 = /usr/bin/ranlib
|
||||
SPLINT_linux32 = /usr/local/bin/splint
|
||||
CLANG_linux32 = /usr/local/bin/clang
|
||||
ARCHS_linux32 = i386
|
||||
CCFLAGS_linux32 = -m32
|
||||
LINKFLAGS_linux32 = -m32 -ldl -lglut -lGLU -lGL -lm -Wl,-E
|
||||
|
||||
CC_linux64_x86_64 = /usr/bin/gcc
|
||||
AR_linux64 = /usr/bin/ar
|
||||
RANLIB_linux64 = /usr/bin/ranlib
|
||||
SPLINT_linux64 = /usr/local/bin/splint
|
||||
CLANG_linux64 = /usr/local/bin/clang
|
||||
ARCHS_linux64 = x86_64
|
||||
CCFLAGS_linux64 = -m64
|
||||
LINKFLAGS_linux64 = -m64 -ldl -lglut -lGLU -lGL -lm -Wl,-E
|
||||
|
||||
MINGW_W32_PATH ?= C:/MinGW
|
||||
MINGW_W32_VERSION ?= 4.6.2
|
||||
SPLINT_WIN_PATH ?= C:/splint-3.1.1/bin/splint.exe
|
||||
CLANG_WIN_PATH ?= C:/llvm/bin/clang.exe
|
||||
DX9_INCLUDE_PATH ?= C:/MinGW/dx9/include
|
||||
DX9_LIB_PATH ?= C:/MinGW/dx9/lib
|
||||
DX9_LIB_PATH_i386 ?= ${DX9_LIB_PATH}/x86
|
||||
WMI_LIB_PATH_i386 ?= C:/MinGW/WinSDK/Lib
|
||||
CC_win32_i386 = ${MINGW_W32_PATH}/bin/gcc.exe
|
||||
AR_win32 = ${MINGW_W32_PATH}/bin/ar.exe
|
||||
RANLIB_win32 = ${MINGW_W32_PATH}/bin/ranlib.exe
|
||||
SPLINT_win32 = ${SPLINT_WIN_PATH}
|
||||
CLANG_win32 = ${CLANG_WIN_PATH}
|
||||
ARCHS_win32 = i386
|
||||
CCFLAGS_win32 = -DFREEGLUT_STATIC -I ${DX9_INCLUDE_PATH}
|
||||
LINKFLAGS_win32 = -lfreeglut32_static -lopengl32 -lglu32 -lpthread -lwinmm -lgdi32 ${DX9_LIB_PATH_i386}/Xinput.lib ${DX9_LIB_PATH_i386}/dinput8.lib ${DX9_LIB_PATH_i386}/dxguid.lib ${WMI_LIB_PATH_i386}/WbemUuid.Lib ${WMI_LIB_PATH_i386}/Ole32.Lib ${WMI_LIB_PATH_i386}/OleAut32.Lib
|
||||
EXECUTABLE_SUFFIX_win32 = .exe
|
||||
|
||||
MINGW_W64_PATH ?= C:/MinGW-w64
|
||||
MINGW_W64_VERSION ?= 4.7.0
|
||||
DX9_LIB_PATH_x86_64 ?= ${DX9_LIB_PATH}/x64
|
||||
WMI_LIB_PATH_x86_64 ?= C:/MinGW/WinSDK/Lib/x64
|
||||
CC_win64_x86_64 = ${MINGW_W64_PATH}/bin/x86_64-w64-mingw32-gcc.exe
|
||||
AR_win64 = ${MINGW_W64_PATH}/bin/x86_64-w64-mingw32-ar.exe
|
||||
RANLIB_win64 = ${MINGW_W64_PATH}/bin/x86_64-w64-mingw32-ranlib.exe
|
||||
SPLINT_win64 = ${SPLINT_WIN_PATH}
|
||||
CLANG_win64 = ${CLANG_WIN_PATH}
|
||||
ARCHS_win64 = x86_64
|
||||
CCFLAGS_win64 = -DFREEGLUT_STATIC -I ${DX9_INCLUDE_PATH}
|
||||
LINKFLAGS_win64 = -lfreeglut64_static -lopengl32 -lglu32 -lpthread -lwinmm -lgdi32 ${DX9_LIB_PATH_x86_64}/Xinput.lib ${DX9_LIB_PATH_x86_64}/dinput8.lib ${DX9_LIB_PATH_x86_64}/dxguid.lib ${WMI_LIB_PATH_x86_64}/WbemUuid.Lib ${WMI_LIB_PATH_x86_64}/Ole32.Lib ${WMI_LIB_PATH_x86_64}/OleAut32.Lib
|
||||
EXECUTABLE_SUFFIX_win64 = .exe
|
||||
|
||||
#General compile/link settings
|
||||
DEFINE_CCFLAGS = -DVERSION_MAJOR=${VERSION_MAJOR}u -DVERSION_MINOR=${VERSION_MINOR}u -DVERSION_TWEAK=${VERSION_TWEAK}u
|
||||
WARNING_CCFLAGS = -Wall -Wextra -Wno-unused-parameter -Werror
|
||||
OTHER_CCFLAGS = -std=gnu99
|
||||
CCFLAGS = ${DEFINE_CCFLAGS} ${WARNING_CCFLAGS} ${OTHER_CCFLAGS}
|
||||
|
||||
FRAMEWORK_LINKFLAGS =
|
||||
LIBRARY_LINKFLAGS =
|
||||
OTHER_LINKFLAGS =
|
||||
LINKFLAGS = ${FRAMEWORK_LINKFLAGS} ${LIBRARY_LINKFLAGS} ${OTHER_LINKFLAGS}
|
||||
|
||||
LINK_ORDER = \
|
||||
library
|
||||
|
||||
#Dependencies (can optionally be per-target or per-target-per-platform)
|
||||
|
||||
PROJECT_LIBRARY_DEPENDENCIES_unittest = library
|
||||
PROJECT_LIBRARY_DEPENDENCIES_testharness = library
|
||||
STEM_LIBRARY_DEPENDENCIES =
|
||||
STEM_LIBRARY_DEPENDENCIES_testharness =
|
||||
STEM_SOURCE_DEPENDENCIES =
|
||||
THIRDPARTY_LIBRARY_DEPENDENCIES =
|
||||
|
||||
#Per-target source file lists
|
||||
|
||||
SOURCES_library = \
|
||||
source/${PROJECT_NAME}/Gamepad_private.c
|
||||
|
||||
SOURCES_library_macosx = \
|
||||
source/${PROJECT_NAME}/Gamepad_macosx.c
|
||||
|
||||
SOURCES_library_win32 = \
|
||||
source/${PROJECT_NAME}/Gamepad_windows_dinput.c
|
||||
|
||||
SOURCES_library_win64 = \
|
||||
source/${PROJECT_NAME}/Gamepad_windows_dinput.c
|
||||
|
||||
SOURCES_library_linux32 = \
|
||||
source/${PROJECT_NAME}/Gamepad_linux.c
|
||||
|
||||
SOURCES_library_linux64 = \
|
||||
source/${PROJECT_NAME}/Gamepad_linux.c
|
||||
|
||||
SOURCES_unittest = \
|
||||
build/intermediate/TestList.c \
|
||||
${SOURCES_unittest_suites}
|
||||
|
||||
SOURCES_unittest_suites =
|
||||
|
||||
SOURCES_testharness = \
|
||||
source/testharness/TestHarness_main.c
|
||||
|
||||
#Include files to be distributed with library
|
||||
|
||||
INCLUDES = \
|
||||
source/${PROJECT_NAME}/Gamepad.h
|
||||
|
||||
#Target resources
|
||||
|
||||
RESOURCES_testharness =
|
||||
RESOURCES_unittest =
|
||||
RESOURCES_testharness_macosx =
|
||||
#...
|
||||
|
||||
#General analyzer settings
|
||||
CLANGFLAGS =
|
||||
CLANGFLAGS_win32 = -I ${MINGW_W32_PATH}/include -I ${MINGW_W32_PATH}/lib/gcc/mingw32/${MINGW_W32_VERSION}/include
|
||||
CLANGFLAGS_win64 = -I ${MINGW_W64_PATH}/include -I ${MINGW_W64_PATH}/lib/gcc/mingw32/${MINGW_W64_VERSION}/include
|
||||
SPLINTFLAGS = -exportlocal
|
||||
|
||||
#Source files excluded from static analysis
|
||||
|
||||
ANALYZER_EXCLUDE_SOURCES_clang =
|
||||
ANALYZER_EXCLUDE_SOURCES_splint = ${SOURCES_unittest}
|
||||
|
||||
#Additional target build prerequisites
|
||||
PREREQS_unittest =
|
||||
|
||||
#TestList.c is automatically generated from ${SOURCES_unittest_suites}. It is used by the unit test framework to determine which tests to run.
|
||||
build/intermediate/TestList.c: build/intermediate/TestSuites.txt | build/intermediate
|
||||
echo 'const char * UnitTest_suiteNameList[] = {${foreach file,${SOURCES_unittest_suites},"${basename ${notdir ${file}}}",} (void *) 0};' > $@
|
||||
|
||||
#TestSuites.txt tracks the state of ${SOURCES_unittest_suites} so that TestList.c can be updated if and only if ${SOURCES_unittest_suites} has changed. .PHONY is abused slightly to cause the target to be conditionally remade.
|
||||
ifneq (${shell echo "${SOURCES_unittest_suites}" | cmp - build/intermediate/TestSuites.txt 2>&1},)
|
||||
.PHONY: build/intermediate/TestSuites.txt
|
||||
endif
|
||||
build/intermediate/TestSuites.txt: | build/intermediate
|
||||
echo "${SOURCES_unittest_suites}" > $@
|
||||
|
||||
|
||||
|
||||
define configuration_object_list_template #(target, configuration)
|
||||
${foreach platform,${PLATFORMS_$1}, \
|
||||
${call platform_object_list_template,$1,$2,${platform}} \
|
||||
}
|
||||
endef
|
||||
|
||||
define platform_object_list_template #(target, configuration, platform)
|
||||
${foreach arch,${ARCHS_$3}, \
|
||||
${call arch_object_list_template,$1,$2,$3,${arch}} \
|
||||
}
|
||||
endef
|
||||
|
||||
define arch_object_list_template #(target, configuration, platform, arch)
|
||||
${foreach source,${SOURCES_$1} ${SOURCES_$1_$3}, \
|
||||
build/intermediate/$1-$2-$3-$4/${notdir ${basename ${source}}}.o \
|
||||
}
|
||||
endef
|
||||
|
||||
#Produces OBJECTS_${target}_${configuration} variables for each permutation of target and configuration in that target
|
||||
${foreach target,${TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${eval OBJECTS_${target}_${configuration} = ${call configuration_object_list_template,${target},${configuration}}} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define create_directory_target_template #(dir)
|
||||
.LOW_RESOLUTION_TIME: $1
|
||||
$1:
|
||||
mkdir -p $1
|
||||
endef
|
||||
|
||||
${foreach target,${TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval ${call create_directory_target_template,build/${target}/${configuration}-${platform}}} \
|
||||
${foreach arch,${ARCHS_${platform}}, \
|
||||
${eval ${call create_directory_target_template,build/intermediate/${target}-${configuration}-${platform}-${arch}}} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
${eval ${call create_directory_target_template,build/intermediate}}
|
||||
|
||||
|
||||
|
||||
define include_ccflags_template #(target, platform)
|
||||
-I source \
|
||||
${foreach stem_dependency,${STEM_LIBRARY_DEPENDENCIES} ${STEM_LIBRARY_DEPENDENCIES_$1} ${STEM_LIBRARY_DEPENDENCIES_$2} ${STEM_LIBRARY_DEPENDENCIES_$1_$2},-I ${STEM_SHARED_DIR}/${stem_dependency}/include} \
|
||||
${foreach thirdparty_dependency,${THIRDPARTY_LIBRARY_DEPENDENCIES} ${THIRDPARTY_LIBRARY_DEPENDENCIES_$1} ${THIRDPARTY_LIBRARY_DEPENDENCIES_$2} ${THIRDPARTY_LIBRARY_DEPENDENCIES_$1_$2},-I ${STEM_SHARED_DIR}/${dir ${thirdparty_dependency}}include} \
|
||||
${foreach source_dependency,${STEM_SOURCE_DEPENDENCIES} ${STEM_SOURCE_DEPENDENCIES_$1} ${STEM_SOURCE_DEPENDENCIES_$2} ${STEM_SOURCE_DEPENDENCIES_$1_$2},-I dep/${word 1,${subst /, ,${source_dependency}}}/source}
|
||||
endef
|
||||
|
||||
define define_ccflags_template #(target, configuration, platform, arch)
|
||||
-DSTEM_TARGET_$1 -DSTEM_CONFIGURATION_$2 -DSTEM_PLATFORM_$3 -DSTEM_ARCH_$4
|
||||
endef
|
||||
|
||||
define dependency_template #(target, configuration, platform, arch, source_file)
|
||||
build/intermediate/$1-$2-$3-$4/${notdir ${basename $5}}.d: $5 ${PREREQS_$1} | build/intermediate/$1-$2-$3-$4
|
||||
@${CC_$3_$4} ${CCFLAGS} ${CCFLAGS_$1} ${CCFLAGS_$2} ${CCFLAGS_$3} ${call include_ccflags_template,$1,$3} ${call define_ccflags_template,$1,$2,$3,$4} -MM -o $$@.temp $5
|
||||
@sed 's,\(${notdir ${basename $5}}\)\.o[ :]*,$${basename $$@}.o $${basename $$@}.d: ,g' < $$@.temp > $$@
|
||||
@rm $$@.temp
|
||||
endef
|
||||
|
||||
#Produces dependency build targets for all source files in each configuration/platform/arch
|
||||
ifeq ($(filter clean full_dist commit_dist analyze analyze_clang analyze_splint,${MAKECMDGOALS}),)
|
||||
${foreach target,${TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${foreach arch,${ARCHS_${platform}}, \
|
||||
${foreach source,${SOURCES_${target}} ${SOURCES_${target}_${platform}}, \
|
||||
${eval ${call dependency_template,${target},${configuration},${platform},${arch},${source}}} \
|
||||
${eval -include build/intermediate/${target}-${configuration}-${platform}-${arch}/${notdir ${basename ${source}}}.d} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
endif
|
||||
|
||||
|
||||
|
||||
define compile_template #(target, configuration, platform, arch, source_file)
|
||||
build/intermediate/$1-$2-$3-$4/${notdir ${basename $5}}.o: $5 ${PREREQS_$1} | build/intermediate/$1-$2-$3-$4
|
||||
${CC_$3_$4} ${CCFLAGS} ${CCFLAGS_$1} ${CCFLAGS_$2} ${CCFLAGS_$3} ${call include_ccflags_template,$1,$3} ${call define_ccflags_template,$1,$2,$3,$4} -c -o $$@ $5
|
||||
endef
|
||||
|
||||
#Produces object build targets for all source files in each configuration/platform/arch
|
||||
${foreach target,${TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${foreach arch,${ARCHS_${platform}}, \
|
||||
${foreach source,${SOURCES_${target}} ${SOURCES_${target}_${platform}}, \
|
||||
${eval ${call compile_template,${target},${configuration},${platform},${arch},${source}}} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define library_template #(target, configuration, platform, arch, output_file)
|
||||
build/intermediate/$1-$2-$3-$4/$5: ${call arch_object_list_template,$1,$2,$3,$4}
|
||||
${AR_$3} rc $$@ $$^
|
||||
${RANLIB_$3} $$@
|
||||
endef
|
||||
|
||||
#Produces static library build targets for each arch/platform/target for library targets
|
||||
${foreach target,${LIBRARY_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${foreach arch,${ARCHS_${platform}}, \
|
||||
${eval ${call library_template,${target},${configuration},${platform},${arch},${TARGET_NAME_${target}}.a}} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define executable_template #(target, configuration, platform, arch, output_file, dependent_libraries)
|
||||
build/intermediate/$1-$2-$3-$4/$5: ${call arch_object_list_template,$1,$2,$3,$4} $6
|
||||
${CC_$3_$4} -o $$@ $$^ ${LINKFLAGS} ${LINKFLAGS_$3}
|
||||
endef
|
||||
|
||||
define library_dependency_template #(target, configuration, platform)
|
||||
${foreach link_library,${LINK_ORDER}, \
|
||||
${foreach library,${filter ${link_library}%,${PROJECT_LIBRARY_DEPENDENCIES} ${PROJECT_LIBRARY_DEPENDENCIES_$1} ${PROJECT_LIBRARY_DEPENDENCIES_$3} ${PROJECT_LIBRARY_DEPENDENCIES_$1_$3}}, \
|
||||
build/${library}/$2-$3/${TARGET_NAME_${library}}.a \
|
||||
} \
|
||||
${foreach library,${filter ${link_library}%,${STEM_LIBRARY_DEPENDENCIES} ${STEM_LIBRARY_DEPENDENCIES_$1} ${STEM_LIBRARY_DEPENDENCIES_$3} ${STEM_LIBRARY_DEPENDENCIES_$1_$3}}, \
|
||||
${STEM_SHARED_DIR}/${library}/library/$2-$3/libstem_${word 1,${subst /, ,${library}}}.a \
|
||||
} \
|
||||
${foreach library,${filter ${link_library}%,${STEM_SOURCE_DEPENDENCIES} ${STEM_SOURCE_DEPENDENCIES_$1} ${STEM_SOURCE_DEPENDENCIES_$3} ${STEM_SOURCE_DEPENDENCIES_$1_$3}}, \
|
||||
dep/${word 1,${subst /, ,${library}}}/build/${word 2,${subst /, ,${library}}}/$2-$3/${word 3,${subst /, ,${library}}} \
|
||||
} \
|
||||
${foreach library,${filter ${link_library}%,${THIRDPARTY_LIBRARY_DEPENDENCIES} ${THIRDPARTY_LIBRARY_DEPENDENCIES_$1} ${THIRDPARTY_LIBRARY_DEPENDENCIES_$3} ${THIRDPARTY_LIBRARY_DEPENDENCIES_$1_$3}}, \
|
||||
${STEM_SHARED_DIR}/${dir ${library}}library/$3/${notdir ${library}} \
|
||||
} \
|
||||
}
|
||||
endef
|
||||
|
||||
#Produces executable build targets for each arch/platform/target for executable and application targets
|
||||
${foreach target,${EXECUTABLE_TARGETS} ${APPLICATION_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${foreach arch,${ARCHS_${platform}}, \
|
||||
${eval ${call executable_template,${target},${configuration},${platform},${arch},${TARGET_NAME_${target}}${EXECUTABLE_SUFFIX_${platform}},${call library_dependency_template,${target},${configuration},${platform}}}} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define dependency_submake_template #(dependency)
|
||||
.PHONY: $1
|
||||
$1:
|
||||
${MAKE} -C dep/${word 1,${subst /, ,$1}}
|
||||
endef
|
||||
|
||||
#Invokes make for each source dependency
|
||||
${foreach dependency,${sort ${foreach target,${TARGETS},${foreach platform,${PLATFORMS_${target}},${STEM_SOURCE_DEPENDENCIES} ${STEM_SOURCE_DEPENDENCIES_${target}} ${STEM_SOURCE_DEPENDENCIES_${platform}} ${STEM_SOURCE_DEPENDENCIES_${target}_${platform}}}}}, \
|
||||
${eval ${call dependency_submake_template,${dependency}}} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define thin_binary_list_template #(target, configuration, platform, target_name)
|
||||
${foreach arch,${ARCHS_$3}, \
|
||||
build/intermediate/$1-$2-$3-${arch}/$4 \
|
||||
}
|
||||
endef
|
||||
|
||||
#Produces THIN_BINARIES_${target}_${configuration}_${platform} variables for each target/configuration/platform for library targets
|
||||
${foreach target,${LIBRARY_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval THIN_BINARIES_${target}_${configuration}_${platform} = ${call thin_binary_list_template,${target},${configuration},${platform},${TARGET_NAME_${target}}.a}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#Produces THIN_BINARIES_${target}_${configuration}_${platform} variables for each target/configuration/platform for executable targets
|
||||
${foreach target,${EXECUTABLE_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval THIN_BINARIES_${target}_${configuration}_${platform} = ${call thin_binary_list_template,${target},${configuration},${platform},${TARGET_NAME_${target}}${EXECUTABLE_SUFFIX_${platform}}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#Produces THIN_BINARIES_${target}_${configuration}_${platform} variables for each target/configuration/platform for application targets
|
||||
${foreach target,${APPLICATION_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval THIN_BINARIES_${target}_${configuration}_${platform} = ${call thin_binary_list_template,${target},${configuration},${platform},${TARGET_NAME_${target}}${EXECUTABLE_SUFFIX_${platform}}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define assemble_library_macosx #(target, configuration, platform)
|
||||
build/$1/$2-$3/${TARGET_NAME_$1}.a: ${THIN_BINARIES_$1_$2_$3} | build/$1/$2-$3
|
||||
lipo -create -output $$@ ${THIN_BINARIES_$1_$2_$3}
|
||||
endef
|
||||
|
||||
define assemble_library_linux #(target, configuration, platform)
|
||||
build/$1/$2-$3/${TARGET_NAME_$1}.a: ${THIN_BINARIES_$1_$2_$3} | build/$1/$2-$3
|
||||
cp ${THIN_BINARIES_$1_$2_$3} $$@
|
||||
endef
|
||||
|
||||
define assemble_library_windows #(target, configuration, platform)
|
||||
build/$1/$2-$3/${TARGET_NAME_$1}.a: ${THIN_BINARIES_$1_$2_$3} | build/$1/$2-$3
|
||||
cp ${THIN_BINARIES_$1_$2_$3} $$@
|
||||
endef
|
||||
|
||||
#Produces final library build targets
|
||||
${foreach target,${LIBRARY_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval ${call assemble_library_${HOST_PLATFORM},${target},${configuration},${platform}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
define copy_target_resources #(target, platform, resources_dir)
|
||||
${if ${strip ${RESOURCES_$1} ${RESOURCES_$1_$2}},mkdir -p $3,}
|
||||
${foreach resource,${RESOURCES_$1} ${RESOURCES_$1_$2}, \
|
||||
cp -r ${resource} $3${newline_and_tab} \
|
||||
}
|
||||
${if ${strip ${RESOURCES_$1} ${RESOURCES_$1_$2}},find $3 -name .svn -print0 -or -name .DS_Store -print0 | xargs -0 rm -rf}
|
||||
endef
|
||||
|
||||
define assemble_executable_macosx #(target, configuration, platform)
|
||||
build/$1/$2-$3/${TARGET_NAME_$1}: ${THIN_BINARIES_$1_$2_$3} ${RESOURCES_$1} ${RESOURCES_$1_$3} | build/$1/$2-$3
|
||||
lipo -create -output $$@ ${THIN_BINARIES_$1_$2_$3}
|
||||
${call copy_target_resources,$1,$3,$${dir $$@}}
|
||||
endef
|
||||
|
||||
define assemble_executable_linux #(target, configuration, platform)
|
||||
build/$1/$2-$3/${TARGET_NAME_$1}: ${THIN_BINARIES_$1_$2_$3} ${RESOURCES_$1} ${RESOURCES_$1_$3} | build/$1/$2-$3
|
||||
cp ${THIN_BINARIES_$1_$2_$3} $$@
|
||||
${call copy_target_resources,$1,$3,$${dir $$@}}
|
||||
endef
|
||||
|
||||
define assemble_executable_windows #(target, configuration, platform)
|
||||
build/$1/$2-$3/${TARGET_NAME_$1}.exe: ${THIN_BINARIES_$1_$2_$3} ${RESOURCES_$1} ${RESOURCES_$1_$3} | build/$1/$2-$3
|
||||
cp ${THIN_BINARIES_$1_$2_$3} $$@
|
||||
${call copy_target_resources,$1,$3,$${dir $$@}}
|
||||
endef
|
||||
|
||||
#Produces final executable build targets
|
||||
${foreach target,${EXECUTABLE_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval ${call assemble_executable_${HOST_PLATFORM},${target},${configuration},${platform}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
PLIST_FILE_testharness_macosx = resources/Info_testharness_macosx.plist
|
||||
|
||||
PLIST_FILE_testharness_iphonesimulator = resources/Info_testharness_iphone.plist
|
||||
PLIST_PLATFORM_CASED_iphonesimulator = iPhoneSimulator
|
||||
PLIST_PLATFORM_LOWER_iphonesimulator = iphonesimulator
|
||||
PLIST_SDK_NAME_iphonesimulator = iphonesimulator${IPHONE_BUILD_SDK_VERSION}
|
||||
|
||||
PLIST_FILE_testharness_iphoneos = resources/Info_testharness_iphone.plist
|
||||
PLIST_PLATFORM_CASED_iphoneos = iPhoneOS
|
||||
PLIST_PLATFORM_LOWER_iphoneos = iphoneos
|
||||
PLIST_SDK_NAME_iphoneos = iphoneos${IPHONE_BUILD_SDK_VERSION}
|
||||
|
||||
define create_app_bundle #(target, platform, executable_dir, plist_dir, resources_dir)
|
||||
mkdir -p $3 $4 $5
|
||||
sed -e "s/\$$$${PRODUCT_NAME}/${TARGET_NAME_$1}/g" \
|
||||
-e "s/\$$$${HUMAN_READABLE_PRODUCT_NAME}/${HUMAN_READABLE_TARGET_NAME_$1}/g" \
|
||||
-e "s/\$$$${VERSION}/${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_TWEAK}/g" \
|
||||
-e "s/\$$$${COPYRIGHT_YEAR}/"`date +%Y`"/g" \
|
||||
-e "s/\$$$${BUILD_NUMBER}/0/g" \
|
||||
-e "s/\$$$${PLATFORM_CASED}/${PLIST_PLATFORM_CASED_$2}/g" \
|
||||
-e "s/\$$$${PLATFORM_LOWER}/${PLIST_PLATFORM_LOWER_$2}/g" \
|
||||
-e "s/\$$$${SDK}/${PLIST_SDK_NAME_$2}/g" \
|
||||
${PLIST_FILE_$1_$2} > $4/Info.plist
|
||||
echo "APPL????" > $4/PkgInfo
|
||||
${call copy_target_resources,$1,$2,$5}
|
||||
endef
|
||||
|
||||
define assemble_application_macosx #(target, configuration)
|
||||
build/$1/$2-macosx/$${HUMAN_READABLE_TARGET_NAME_$1}.app/Contents/MacOS/${TARGET_NAME_$1}: ${THIN_BINARIES_$1_$2_macosx} ${RESOURCES_$1} ${RESOURCES_$1_macosx} | build/$1/$2-macosx
|
||||
${call create_app_bundle,$1,macosx,build/$1/$2-macosx/$${HUMAN_READABLE_TARGET_NAME_$1}.app/Contents/MacOS,build/$1/$2-macosx/$${HUMAN_READABLE_TARGET_NAME_$1}.app/Contents,build/$1/$2-macosx/$${HUMAN_READABLE_TARGET_NAME_$1}.app/Contents/Resources}
|
||||
lipo -create -output "$$@" ${THIN_BINARIES_$1_$2_macosx}
|
||||
endef
|
||||
|
||||
define assemble_application_iphonesimulator #(target, configuration)
|
||||
build/$1/$2-iphonesimulator/${TARGET_NAME_$1}.app/${TARGET_NAME_$1}: ${THIN_BINARIES_$1_$2_iphonesimulator} ${RESOURCES_$1} ${RESOURCES_$1_iphonesimulator} | build/$1/$2-iphonesimulator
|
||||
${call create_app_bundle,$1,iphonesimulator,build/$1/$2-iphonesimulator/${TARGET_NAME_$1}.app,build/$1/$2-iphonesimulator/${TARGET_NAME_$1}.app,build/$1/$2-iphonesimulator/${TARGET_NAME_$1}.app}
|
||||
lipo -create -output "$$@" ${THIN_BINARIES_$1_$2_iphonesimulator}
|
||||
endef
|
||||
|
||||
define assemble_application_iphoneos #(target, configuration)
|
||||
build/$1/$2-iphoneos/${TARGET_NAME_$1}.app/${TARGET_NAME_$1}: ${THIN_BINARIES_$1_$2_iphoneos} ${RESOURCES_$1} ${RESOURCES_$1_iphoneos} | build/$1/$2-iphoneos
|
||||
${call create_app_bundle,$1,iphoneos,build/$1/$2-iphoneos/${TARGET_NAME_$1}.app,build/$1/$2-iphoneos/${TARGET_NAME_$1}.app,build/$1/$2-iphoneos/${TARGET_NAME_$1}.app}
|
||||
lipo -create -output "$$@" ${THIN_BINARIES_$1_$2_iphoneos}
|
||||
endef
|
||||
|
||||
define assemble_application_linux32 #(target, configuration)
|
||||
build/$1/$2-linux32/${TARGET_NAME_$1}: ${THIN_BINARIES_$1_$2_linux32} ${RESOURCES_$1} ${RESOURCES_$1_linux32} | build/$1/$2-linux32
|
||||
${call copy_target_resources,$1,linux32,build/$1/$2-linux32/Resources}
|
||||
cp ${THIN_BINARIES_$1_$2_linux32} "$$@"
|
||||
endef
|
||||
|
||||
define assemble_application_linux64 #(target, configuration)
|
||||
build/$1/$2-linux64/${TARGET_NAME_$1}: ${THIN_BINARIES_$1_$2_linux64} ${RESOURCES_$1} ${RESOURCES_$1_linux64} | build/$1/$2-linux64
|
||||
${call copy_target_resources,$1,linux64,build/$1/$2-linux64/Resources}
|
||||
cp ${THIN_BINARIES_$1_$2_linux64} "$$@"
|
||||
endef
|
||||
|
||||
define assemble_application_win32 #(target, configuration)
|
||||
build/$1/$2-win32/${TARGET_NAME_$1}.exe: ${THIN_BINARIES_$1_$2_win32} ${RESOURCES_$1} ${RESOURCES_$1_win32} | build/$1/$2-win32
|
||||
${call copy_target_resources,$1,win32,build/$1/$2-win32/Resources}
|
||||
cp ${THIN_BINARIES_$1_$2_win32} "$$@"
|
||||
endef
|
||||
|
||||
define assemble_application_win64 #(target, configuration)
|
||||
build/$1/$2-win64/${TARGET_NAME_$1}.exe: ${THIN_BINARIES_$1_$2_win64} ${RESOURCES_$1} ${RESOURCES_$1_win64} | build/$1/$2-win64
|
||||
${call copy_target_resources,$1,win64,build/$1/$2-win64/Resources}
|
||||
cp ${THIN_BINARIES_$1_$2_win64} "$$@"
|
||||
endef
|
||||
|
||||
#Produces final application build targets
|
||||
${foreach target,${APPLICATION_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval ${call assemble_application_${platform},${target},${configuration}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
define library_dependency_template #(target, configuration, platform)
|
||||
${STEM_SOURCE_DEPENDENCIES} ${STEM_SOURCE_DEPENDENCIES_$1} ${STEM_SOURCE_DEPENDENCIES_$1_$3} build/$1/$2-$3/${TARGET_NAME_$1}.a
|
||||
endef
|
||||
|
||||
define executable_dependency_template #(target, configuration, platform)
|
||||
${STEM_SOURCE_DEPENDENCIES} ${STEM_SOURCE_DEPENDENCIES_$1} ${STEM_SOURCE_DEPENDENCIES_$1_$3} build/$1/$2-$3/${TARGET_NAME_$1}${EXECUTABLE_SUFFIX_$3}
|
||||
endef
|
||||
|
||||
define application_dependency_template #(target, configuration, platform)
|
||||
${STEM_SOURCE_DEPENDENCIES} ${STEM_SOURCE_DEPENDENCIES_$1} ${STEM_SOURCE_DEPENDENCIES_$1_$3} build/$1/$2-$3/${call application_file_template_$3,$1}
|
||||
endef
|
||||
|
||||
define application_file_template_macosx #(target)
|
||||
$${HUMAN_READABLE_TARGET_NAME_$1}.app/Contents/MacOS/${TARGET_NAME_$1}
|
||||
endef
|
||||
|
||||
define application_file_template_iphonesimulator #(target)
|
||||
${TARGET_NAME_$1}.app/${TARGET_NAME_$1}
|
||||
endef
|
||||
|
||||
define application_file_template_iphoneos #(target)
|
||||
${TARGET_NAME_$1}.app/${TARGET_NAME_$1}
|
||||
endef
|
||||
|
||||
define application_file_template_linux32 #(target)
|
||||
${TARGET_NAME_$1}
|
||||
endef
|
||||
|
||||
define application_file_template_linux64 #(target)
|
||||
${TARGET_NAME_$1}
|
||||
endef
|
||||
|
||||
define application_file_template_win32 #(target)
|
||||
${TARGET_NAME_$1}.exe
|
||||
endef
|
||||
|
||||
define application_file_template_win64 #(target)
|
||||
${TARGET_NAME_$1}.exe
|
||||
endef
|
||||
|
||||
define target_template #(target, target_type)
|
||||
.PHONY: $1
|
||||
$1: ${foreach configuration,${CONFIGURATIONS_$1},${foreach platform,${PLATFORMS_$1},${call $2_dependency_template,$1,${configuration},${platform}}}}
|
||||
endef
|
||||
|
||||
${foreach target,${LIBRARY_TARGETS}, \
|
||||
${eval ${call target_template,${target},library}} \
|
||||
}
|
||||
|
||||
${foreach target,${EXECUTABLE_TARGETS}, \
|
||||
${eval ${call target_template,${target},executable}} \
|
||||
}
|
||||
|
||||
${foreach target,${APPLICATION_TARGETS}, \
|
||||
${eval ${call target_template,${target},application}} \
|
||||
}
|
||||
|
||||
.PHONY: test
|
||||
test: ${foreach platform,${PLATFORMS_unittest},run_unittests_${platform}}
|
||||
|
||||
.PHONY: run_unittests_macosx
|
||||
run_unittests_macosx: unittest
|
||||
./build/unittest/debug-macosx/${TARGET_NAME_unittest} "${CURDIR}/build/unittest/debug-macosx"
|
||||
|
||||
.PHONY: run_unittests_iphonesimulator
|
||||
run_unittests_iphonesimulator: unittest
|
||||
DYLD_ROOT_PATH=${SDKROOT_iphonesimulator} \
|
||||
./build/unittest/debug-iphonesimulator/${TARGET_NAME_unittest} "${CURDIR}/build/unittest/debug-iphonesimulator"
|
||||
|
||||
.PHONY: run_unittests_linux32
|
||||
run_unittests_linux32: unittest
|
||||
./build/unittest/debug-linux32/${TARGET_NAME_unittest} "${CURDIR}/build/unittest/debug-linux32"
|
||||
|
||||
.PHONY: run_unittests_linux64
|
||||
run_unittests_linux64: unittest
|
||||
./build/unittest/debug-linux64/${TARGET_NAME_unittest} "${CURDIR}/build/unittest/debug-linux64"
|
||||
|
||||
.PHONY: run_unittests_win32
|
||||
run_unittests_win32: unittest
|
||||
./build/unittest/debug-win32/${TARGET_NAME_unittest}.exe "${CURDIR}/build/unittest/debug-win32"
|
||||
|
||||
.PHONY: run_unittests_win64
|
||||
run_unittests_win64: unittest
|
||||
./build/unittest/debug-win64/${TARGET_NAME_unittest}.exe "${CURDIR}/build/unittest/debug-win64"
|
||||
|
||||
define analyze_file_template_clang #(target, platform, file)
|
||||
build/analyzer-results/clang-$1-$2/${basename ${notdir $3}}.txt: $3 ${PREREQS_$1} | build/analyzer-results/clang-$1-$2
|
||||
${CLANG_$2} --analyze ${call include_ccflags_template,$1,$2} ${call define_ccflags_template,$1,analyze,$2,none} ${CLANGFLAGS} ${CLANGFLAGS_$1} ${CLANGFLAGS_$2} -o $${basename $$@}.plist $3 > $$@ 2>&1; true
|
||||
@cat $$@
|
||||
endef
|
||||
|
||||
define analyze_file_template_splint #(target, platform, file)
|
||||
build/analyzer-results/splint-$1-$2/${basename ${notdir $3}}.txt: $3 ${PREREQS_$1} | build/analyzer-results/splint-$1-$2
|
||||
${SPLINT_$2} ${call include_ccflags_template,$1,$2} ${call define_ccflags_template,$1,analyze,$2,none} ${SPLINTFLAGS} ${SPLINTFLAGS_$1} ${SPLINTFLAGS_$2} $3 > $$@ 2>&1; true
|
||||
@cat $$@
|
||||
endef
|
||||
|
||||
define analyzed_sources_template #(analyzer, target, platform)
|
||||
${sort ${filter-out ${ANALYZER_EXCLUDE_SOURCES_$1},${SOURCES_$2} ${SOURCES_$2_$3}}}
|
||||
endef
|
||||
|
||||
define analyzer_output_template #(analyzer, target, platform)
|
||||
${foreach file,${call analyzed_sources_template,$1,$2,$3}, \
|
||||
build/analyzer-results/$1-$2-$3/${basename ${notdir ${file}}}.txt \
|
||||
}
|
||||
endef
|
||||
|
||||
define analyze_target_template #(analyzer, target, platform)
|
||||
.PHONY: analyze_$1_$2_$3
|
||||
analyze_$1_$2_$3: ${call analyzer_output_template,$1,$2,$3}
|
||||
endef
|
||||
|
||||
define analyze_template #(analyzer)
|
||||
.PHONY: analyze_$1
|
||||
analyze_$1: ${foreach target,${TARGETS},${foreach platform,${PLATFORMS_${target}},analyze_$1_${target}_${platform}}}
|
||||
endef
|
||||
|
||||
${foreach analyzer,${ANALYZERS}, \
|
||||
${eval ${call analyze_template,${analyzer}}} \
|
||||
${foreach target,${TARGETS}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval ${call analyze_target_template,${analyzer},${target},${platform}}} \
|
||||
${foreach file,${call analyzed_sources_template,${analyzer},${target},${platform}}, \
|
||||
${eval ${call analyze_file_template_${analyzer},${target},${platform},${file}}} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
${foreach analyzer,${ANALYZERS}, \
|
||||
${foreach target,${TARGETS}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval ${call create_directory_target_template,build/analyzer-results/${analyzer}-${target}-${platform}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
.PHONY: analyze
|
||||
analyze: ${foreach analyzer,${ANALYZERS},analyze_${analyzer}}
|
||||
|
||||
${foreach dir,${sort ${foreach include_file,${INCLUDES},build/include/${notdir ${patsubst %/,%,${dir ${include_file}}}}}}, \
|
||||
${eval ${call create_directory_target_template,${dir}}} \
|
||||
}
|
||||
|
||||
.PHONY: include
|
||||
include: ${INCLUDES} | ${foreach include_file,${INCLUDES},build/include/${notdir ${patsubst %/,%,${dir ${include_file}}}}}
|
||||
${foreach include_file,${INCLUDES}, \
|
||||
cp ${include_file} build/include/${notdir ${patsubst %/,%,${dir ${include_file}}}}${newline_and_tab} \
|
||||
}
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf build
|
||||
${foreach dependency,${sort ${foreach target,${TARGETS},${foreach platform,${PLATFORMS_${target}},${STEM_SOURCE_DEPENDENCIES} ${STEM_SOURCE_DEPENDENCIES_${target}} ${STEM_SOURCE_DEPENDENCIES_${platform}} ${STEM_SOURCE_DEPENDENCIES_${target}_${platform}}}}}, \
|
||||
${MAKE} -C dep/${word 1,${subst /, ,${dependency}}} clean${newline_and_tab} \
|
||||
}
|
||||
|
||||
TARGET_SUFFIX_ipad = _ipad
|
||||
TARGET_SUFFIX_iphone4 = _iphone4
|
||||
IPHONE_SDK_VERSION_iphone ?= 4.2
|
||||
IPHONE_SDK_VERSION_ipad ?= 3.2
|
||||
IPHONE_SDK_VERSION_iphone4 ?= 4.2
|
||||
IPHONESIMULATOR_APPLICATIONS_DIR_iphone ?= ${HOME}/Library/Application Support/iPhone Simulator/${IPHONE_SDK_VERSION_iphone}/Applications
|
||||
IPHONESIMULATOR_APPLICATIONS_DIR_ipad ?= ${HOME}/Library/Application Support/iPhone Simulator/${IPHONE_SDK_VERSION_ipad}/Applications
|
||||
IPHONESIMULATOR_APPLICATIONS_DIR_iphone4 ?= ${HOME}/Library/Application Support/iPhone Simulator/${IPHONE_SDK_VERSION_iphone4}/Applications
|
||||
SIMULATE_DEVICE_iphone = iPhone
|
||||
SIMULATE_DEVICE_ipad = iPad
|
||||
SIMULATE_DEVICE_iphone4 = iPhone 4
|
||||
SIMULATE_SDKROOT_iphone = /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${IPHONE_SDK_VERSION_iphone}.sdk
|
||||
SIMULATE_SDKROOT_ipad = /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${IPHONE_SDK_VERSION_ipad}.sdk
|
||||
SIMULATE_SDKROOT_iphone4 = /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${IPHONE_SDK_VERSION_iphone4}.sdk
|
||||
IPHONE_SIMULATOR_PATH ?= /Developer/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone Simulator.app
|
||||
|
||||
define install_target_iphonesimulator_template #(target, simulate_device)
|
||||
.PHONY: install_$1_iphonesimulator${TARGET_SUFFIX_$2}
|
||||
install_$1_iphonesimulator${TARGET_SUFFIX_$2}: $1
|
||||
killall "iPhone Simulator"; true
|
||||
rm -rf "${IPHONESIMULATOR_APPLICATIONS_DIR_$2}/${TARGET_NAME_$1}"
|
||||
mkdir -p "${IPHONESIMULATOR_APPLICATIONS_DIR_$2}/${TARGET_NAME_$1}/Documents"
|
||||
mkdir -p "${IPHONESIMULATOR_APPLICATIONS_DIR_$2}/${TARGET_NAME_$1}/Library/Preferences"
|
||||
mkdir -p "${IPHONESIMULATOR_APPLICATIONS_DIR_$2}/${TARGET_NAME_$1}/tmp"
|
||||
cp -r "build/$1/debug-iphonesimulator/${TARGET_NAME_$1}.app" "${IPHONESIMULATOR_APPLICATIONS_DIR_$2}/${TARGET_NAME_$1}"
|
||||
defaults write com.apple.iphonesimulator SimulateDevice -string "${SIMULATE_DEVICE_$2}"
|
||||
defaults write com.apple.iphonesimulator SimulateSDKRoot -string "${SIMULATE_SDKROOT_$2}"
|
||||
defaults write com.apple.iphonesimulator currentSDKRoot -string "${SIMULATE_SDKROOT_$2}"
|
||||
open "${IPHONE_SIMULATOR_PATH}"
|
||||
endef
|
||||
|
||||
define add_blob_header #(source_file, target_file)
|
||||
ruby -e "contents = \"\"; File.open(\"$1\", \"r\") {|file| contents = file.read}; File.open(\"$2\", \"w\") {|file| file.write(\"\xFA\xDE\x71\x71\"); file.write([contents.length + 8].pack(\"N\")); file.write(contents)}"
|
||||
endef
|
||||
|
||||
RESOURCE_RULES_PLIST = /Developer/Platforms/MacOSX.platform/ResourceRules.plist
|
||||
|
||||
define codesign_target_iphoneos_template #(target)
|
||||
.PHONY: codesign_$1_iphoneos
|
||||
codesign_$1_iphoneos: $1
|
||||
sed -e "s/\$$$${PRODUCT_NAME}/${TARGET_NAME_$1}/g" resources/Entitlements.plist > build/intermediate/Entitlements.plist
|
||||
${call add_blob_header,build/intermediate/Entitlements.plist,build/intermediate/Entitlements.xcent}
|
||||
export CODESIGN_ALLOCATE=/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate
|
||||
${foreach configuration,${CONFIGURATIONS_$1},\
|
||||
cp "${RESOURCE_RULES_PLIST}" "build/$1/${configuration}-iphoneos/${TARGET_NAME_$1}.app"${newline_and_tab} \
|
||||
/usr/bin/codesign -f -s ${CODESIGN_IDENTITY} --resource-rules=${RESOURCE_RULES_PLIST} --entitlements=build/intermediate/Entitlements.xcent "build/$1/${configuration}-iphoneos/${TARGET_NAME_$1}.app"${newline_and_tab} \
|
||||
}
|
||||
endef
|
||||
|
||||
${foreach target,${APPLICATION_TARGETS}, \
|
||||
${eval ${call install_target_iphonesimulator_template,${target},iphone}} \
|
||||
${eval ${call install_target_iphonesimulator_template,${target},ipad}} \
|
||||
${eval ${call install_target_iphonesimulator_template,${target},iphone4}} \
|
||||
${eval ${call codesign_target_iphoneos_template,${target}}} \
|
||||
}
|
||||
|
||||
INSTALL_DIR = ${STEM_SHARED_DIR}/${PROJECT_NAME}/${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_TWEAK}
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
mkdir -p "${INSTALL_DIR}/include" "${INSTALL_DIR}/library" "${INSTALL_DIR}/testharness"
|
||||
cp Changes.txt License.txt ReadMe.txt version ${INSTALL_DIR}
|
||||
cp -r build/include/* ${INSTALL_DIR}/include
|
||||
cp -r build/library/* ${INSTALL_DIR}/library
|
||||
cp -r build/testharness/* ${INSTALL_DIR}/testharness
|
|
@ -1,5 +0,0 @@
|
|||
Gamepad provides a low-level interface for USB game controller input. Each element on an attached game controller is mapped to zero or more buttons and zero or more axes. Buttons are binary controls; axes are continuous values ranging from -1.0f to 1.0f. The presence and ordering of elements depends on the platform and driver.
|
||||
|
||||
Typical usage: Register a callback to notify you when a new device is attached with Gamepad_deviceAttachFunc(), then call Gamepad_init() and Gamepad_detectDevices(). Your callback will be called once per connected game controller. Also register callbacks for button and axis events with Gamepad_buttonDownFunc(), Gamepad_buttonUpFunc(), and Gamepad_axisMoveFunc(). Call Gamepad_processEvents() every frame, and Gamepad_detectDevices() occasionally to be notified of new devices that were plugged in after your Gamepad_init() call. If you're interested in knowing when a device was disconnected, you can call Gamepad_deviceRemoveFunc() get be notified of it.
|
||||
|
||||
See Gamepad.h for more details.
|
|
@ -1,162 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>testharness</RootNamespace>
|
||||
<ProjectName>testharness</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\source;C:\Program Files\Common Files\MSVC\freeglut\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>C:\Projects\StemLibProjects\gamepad_trunk\msvc\Debug;C:\Program Files\Common Files\MSVC\freeglut\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
|
||||
<AdditionalDependencies>libstem_gamepad.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\..\source;C:\Program Files\Common Files\MSVC\freeglut\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalLibraryDirectories>C:\Projects\StemLibProjects\gamepad_trunk\msvc\x64\Debug;C:\Program Files\Common Files\MSVC\freeglut\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
|
||||
<AdditionalDependencies>libstem_gamepad.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Common Files\MSVC\freeglut\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Common Files\MSVC\freeglut\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>C:\Program Files\Common Files\MSVC\freeglut\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>C:\Program Files\Common Files\MSVC\freeglut\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\source\testharness\TestHarness_main.c" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\source\testharness\TestHarness_main.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,49 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Express 2013 for Windows Desktop
|
||||
VisualStudioVersion = 12.0.21005.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libstem_gamepad", "libstem_gamepad\libstem_gamepad.vcxproj", "{4579D2EA-39EB-4766-9EB6-497500F379D6}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testharness", "Win32Project1\Win32Project1.vcxproj", "{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6} = {4579D2EA-39EB-4766-9EB6-497500F379D6}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Mixed Platforms = Debug|Mixed Platforms
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Mixed Platforms = Release|Mixed Platforms
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Debug|Mixed Platforms.Build.0 = Debug|x64
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Debug|x64.Build.0 = Debug|x64
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Release|Win32.Build.0 = Release|Win32
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Release|x64.ActiveCfg = Release|x64
|
||||
{4579D2EA-39EB-4766-9EB6-497500F379D6}.Release|x64.Build.0 = Release|x64
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Debug|Mixed Platforms.ActiveCfg = Debug|x64
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Debug|Mixed Platforms.Build.0 = Debug|x64
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Release|Mixed Platforms.ActiveCfg = Release|Win32
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Release|Mixed Platforms.Build.0 = Release|Win32
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Release|Win32.Build.0 = Release|Win32
|
||||
{EAF0DEE7-ADEF-4778-B4CD-8DF22FD0F724}.Release|x64.ActiveCfg = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,142 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{4579D2EA-39EB-4766-9EB6-497500F379D6}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libstem_gamepad</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../source</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../../source</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\source\gamepad\Gamepad_private.c" />
|
||||
<ClCompile Include="..\..\source\gamepad\Gamepad_windows_dinput.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\source\gamepad\Gamepad.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\source\gamepad\Gamepad_windows_dinput.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\source\gamepad\Gamepad_private.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\source\gamepad\Gamepad.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,30 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string>${PRODUCT_NAME} ${VERSION} Copyright © ${COPYRIGHT_YEAR} Alex Diener
|
||||
http://sacredsoftware.net/</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.sacredsoftware.${PRODUCT_NAME}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${PRODUCT_NAME} ${VERSION}</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © ${COPYRIGHT_YEAR} Alex Diener
|
||||
http://sacredsoftware.net/</string>
|
||||
</dict>
|
||||
</plist>
|
File diff suppressed because it is too large
Load diff
|
@ -1,400 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Alex Diener
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <regstr.h>
|
||||
|
||||
struct Gamepad_devicePrivate {
|
||||
UINT joystickID;
|
||||
JOYINFOEX lastState;
|
||||
int xAxisIndex;
|
||||
int yAxisIndex;
|
||||
int zAxisIndex;
|
||||
int rAxisIndex;
|
||||
int uAxisIndex;
|
||||
int vAxisIndex;
|
||||
int povXAxisIndex;
|
||||
int povYAxisIndex;
|
||||
UINT (* axisRanges)[2];
|
||||
};
|
||||
|
||||
static struct Gamepad_device ** devices = NULL;
|
||||
static unsigned int numDevices = 0;
|
||||
static unsigned int nextDeviceID = 0;
|
||||
|
||||
static bool inited = false;
|
||||
|
||||
void Gamepad_init() {
|
||||
if (!inited) {
|
||||
inited = true;
|
||||
Gamepad_detectDevices();
|
||||
}
|
||||
}
|
||||
|
||||
static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
||||
free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->axisRanges);
|
||||
free(deviceRecord->privateData);
|
||||
|
||||
free((void *) deviceRecord->description);
|
||||
free(deviceRecord->axisStates);
|
||||
free(deviceRecord->buttonStates);
|
||||
|
||||
free(deviceRecord);
|
||||
}
|
||||
|
||||
void Gamepad_shutdown() {
|
||||
unsigned int deviceIndex;
|
||||
|
||||
if (inited) {
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
disposeDevice(devices[deviceIndex]);
|
||||
}
|
||||
free(devices);
|
||||
devices = NULL;
|
||||
numDevices = 0;
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Gamepad_numDevices() {
|
||||
return numDevices;
|
||||
}
|
||||
|
||||
struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex) {
|
||||
if (deviceIndex >= numDevices) {
|
||||
return NULL;
|
||||
}
|
||||
return devices[deviceIndex];
|
||||
}
|
||||
|
||||
#define REG_STRING_MAX 256
|
||||
|
||||
static char * getDeviceDescription(UINT joystickID, JOYCAPS caps) {
|
||||
char * description = NULL;
|
||||
char subkey[REG_STRING_MAX];
|
||||
HKEY topKey, key;
|
||||
LONG result;
|
||||
|
||||
snprintf(subkey, REG_STRING_MAX, "%s\\%s\\%s", REGSTR_PATH_JOYCONFIG, caps.szRegKey, REGSTR_KEY_JOYCURR);
|
||||
result = RegOpenKeyEx(topKey = HKEY_LOCAL_MACHINE, subkey, 0, KEY_READ, &key);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
result = RegOpenKeyEx(topKey = HKEY_CURRENT_USER, subkey, 0, KEY_READ, &key);
|
||||
}
|
||||
if (result == ERROR_SUCCESS) {
|
||||
char value[REG_STRING_MAX];
|
||||
char name[REG_STRING_MAX];
|
||||
DWORD nameSize;
|
||||
|
||||
snprintf(value, REG_STRING_MAX, "Joystick%d%s", joystickID + 1, REGSTR_VAL_JOYOEMNAME);
|
||||
nameSize = sizeof(name);
|
||||
result = RegQueryValueEx(key, value, NULL, NULL, (LPBYTE) name, &nameSize);
|
||||
RegCloseKey(key);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
snprintf(subkey, REG_STRING_MAX, "%s\\%s", REGSTR_PATH_JOYOEM, name);
|
||||
result = RegOpenKeyEx(topKey, subkey, 0, KEY_READ, &key);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
nameSize = sizeof(name);
|
||||
result = RegQueryValueEx(key, REGSTR_VAL_JOYOEMNAME, NULL, NULL, NULL, &nameSize);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
description = malloc(nameSize);
|
||||
result = RegQueryValueEx(key, REGSTR_VAL_JOYOEMNAME, NULL, NULL, (LPBYTE) description, &nameSize);
|
||||
}
|
||||
RegCloseKey(key);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
return description;
|
||||
}
|
||||
free(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
description = malloc(strlen(caps.szPname) + 1);
|
||||
strcpy(description, caps.szPname);
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
void Gamepad_detectDevices() {
|
||||
unsigned int numPadsSupported;
|
||||
unsigned int deviceIndex, deviceIndex2;
|
||||
JOYINFOEX info;
|
||||
JOYCAPS caps;
|
||||
bool duplicate;
|
||||
struct Gamepad_device * deviceRecord;
|
||||
struct Gamepad_devicePrivate * deviceRecordPrivate;
|
||||
UINT joystickID;
|
||||
int axisIndex;
|
||||
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
numPadsSupported = joyGetNumDevs();
|
||||
for (deviceIndex = 0; deviceIndex < numPadsSupported; deviceIndex++) {
|
||||
info.dwSize = sizeof(info);
|
||||
info.dwFlags = JOY_RETURNALL;
|
||||
joystickID = JOYSTICKID1 + deviceIndex;
|
||||
if (joyGetPosEx(joystickID, &info) == JOYERR_NOERROR &&
|
||||
joyGetDevCaps(joystickID, &caps, sizeof(JOYCAPS)) == JOYERR_NOERROR) {
|
||||
|
||||
duplicate = false;
|
||||
for (deviceIndex2 = 0; deviceIndex2 < numDevices; deviceIndex2++) {
|
||||
if (((struct Gamepad_devicePrivate *) devices[deviceIndex2]->privateData)->joystickID == joystickID) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceRecord = malloc(sizeof(struct Gamepad_device));
|
||||
deviceRecord->deviceID = nextDeviceID++;
|
||||
deviceRecord->description = getDeviceDescription(joystickID, caps);
|
||||
deviceRecord->vendorID = caps.wMid;
|
||||
deviceRecord->productID = caps.wPid;
|
||||
deviceRecord->numAxes = caps.wNumAxes + ((caps.wCaps & JOYCAPS_HASPOV) ? 2 : 0);
|
||||
deviceRecord->numButtons = caps.wNumButtons;
|
||||
deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes);
|
||||
deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons);
|
||||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
deviceRecordPrivate = malloc(sizeof(struct Gamepad_devicePrivate));
|
||||
deviceRecordPrivate->joystickID = joystickID;
|
||||
deviceRecordPrivate->lastState = info;
|
||||
|
||||
deviceRecordPrivate->xAxisIndex = 0;
|
||||
deviceRecordPrivate->yAxisIndex = 1;
|
||||
axisIndex = 2;
|
||||
deviceRecordPrivate->zAxisIndex = (caps.wCaps & JOYCAPS_HASZ) ? axisIndex++ : -1;
|
||||
deviceRecordPrivate->rAxisIndex = (caps.wCaps & JOYCAPS_HASR) ? axisIndex++ : -1;
|
||||
deviceRecordPrivate->uAxisIndex = (caps.wCaps & JOYCAPS_HASU) ? axisIndex++ : -1;
|
||||
deviceRecordPrivate->vAxisIndex = (caps.wCaps & JOYCAPS_HASV) ? axisIndex++ : -1;
|
||||
|
||||
deviceRecordPrivate->axisRanges = malloc(sizeof(UINT[2]) * axisIndex);
|
||||
deviceRecordPrivate->axisRanges[0][0] = caps.wXmin;
|
||||
deviceRecordPrivate->axisRanges[0][1] = caps.wXmax;
|
||||
deviceRecordPrivate->axisRanges[1][0] = caps.wYmin;
|
||||
deviceRecordPrivate->axisRanges[1][1] = caps.wYmax;
|
||||
if (deviceRecordPrivate->zAxisIndex != -1) {
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->zAxisIndex][0] = caps.wZmin;
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->zAxisIndex][1] = caps.wZmax;
|
||||
}
|
||||
if (deviceRecordPrivate->rAxisIndex != -1) {
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->rAxisIndex][0] = caps.wRmin;
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->rAxisIndex][1] = caps.wRmax;
|
||||
}
|
||||
if (deviceRecordPrivate->uAxisIndex != -1) {
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->uAxisIndex][0] = caps.wUmin;
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->uAxisIndex][1] = caps.wUmax;
|
||||
}
|
||||
if (deviceRecordPrivate->vAxisIndex != -1) {
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->vAxisIndex][0] = caps.wVmin;
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->vAxisIndex][1] = caps.wVmax;
|
||||
}
|
||||
|
||||
deviceRecordPrivate->povXAxisIndex = (caps.wCaps & JOYCAPS_HASPOV) ? axisIndex++ : -1;
|
||||
deviceRecordPrivate->povYAxisIndex = (caps.wCaps & JOYCAPS_HASPOV) ? axisIndex++ : -1;
|
||||
|
||||
deviceRecord->privateData = deviceRecordPrivate;
|
||||
|
||||
if (Gamepad_deviceAttachCallback != NULL) {
|
||||
Gamepad_deviceAttachCallback(deviceRecord, Gamepad_deviceAttachContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static double currentTime() {
|
||||
// HACK: No timestamp data from joyGetInfoEx, so we make it up
|
||||
static LARGE_INTEGER frequency;
|
||||
LARGE_INTEGER currentTime;
|
||||
|
||||
if (frequency.QuadPart == 0) {
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
}
|
||||
QueryPerformanceCounter(¤tTime);
|
||||
|
||||
return (double) currentTime.QuadPart / frequency.QuadPart;
|
||||
}
|
||||
|
||||
static void handleAxisChange(struct Gamepad_device * device, int axisIndex, DWORD ivalue) {
|
||||
float value, lastValue;
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
|
||||
if (axisIndex < 0 || axisIndex >= (int) device->numAxes) {
|
||||
return;
|
||||
}
|
||||
|
||||
devicePrivate = device->privateData;
|
||||
value = (ivalue - devicePrivate->axisRanges[axisIndex][0]) / (float) (devicePrivate->axisRanges[axisIndex][1] - devicePrivate->axisRanges[axisIndex][0]) * 2.0f - 1.0f;
|
||||
|
||||
lastValue = device->axisStates[axisIndex];
|
||||
device->axisStates[axisIndex] = value;
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
Gamepad_axisMoveCallback(device, axisIndex, value, lastValue, currentTime(), Gamepad_axisMoveContext);
|
||||
}
|
||||
}
|
||||
|
||||
static void handleButtonChange(struct Gamepad_device * device, DWORD lastValue, DWORD value) {
|
||||
bool down;
|
||||
unsigned int buttonIndex;
|
||||
|
||||
for (buttonIndex = 0; buttonIndex < device->numButtons; buttonIndex++) {
|
||||
if ((lastValue ^ value) & (1 << buttonIndex)) {
|
||||
down = !!(value & (1 << buttonIndex));
|
||||
|
||||
device->buttonStates[buttonIndex] = down;
|
||||
if (down && Gamepad_buttonDownCallback != NULL) {
|
||||
Gamepad_buttonDownCallback(device, buttonIndex, currentTime(), Gamepad_buttonDownContext);
|
||||
} else if (!down && Gamepad_buttonUpCallback != NULL) {
|
||||
Gamepad_buttonUpCallback(device, buttonIndex, currentTime(), Gamepad_buttonUpContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void povToXY(DWORD pov, int * outX, int * outY) {
|
||||
if (pov == JOY_POVCENTERED) {
|
||||
*outX = *outY = 0;
|
||||
|
||||
} else {
|
||||
if (pov > JOY_POVFORWARD && pov < JOY_POVBACKWARD) {
|
||||
*outX = 1;
|
||||
|
||||
} else if (pov > JOY_POVBACKWARD) {
|
||||
*outX = -1;
|
||||
|
||||
} else {
|
||||
*outX = 0;
|
||||
}
|
||||
|
||||
if (pov > JOY_POVLEFT || pov < JOY_POVRIGHT) {
|
||||
*outY = -1;
|
||||
|
||||
} else if (pov > JOY_POVRIGHT && pov < JOY_POVLEFT) {
|
||||
*outY = 1;
|
||||
|
||||
} else {
|
||||
*outY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handlePOVChange(struct Gamepad_device * device, DWORD lastValue, DWORD value) {
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
int lastX, lastY, newX, newY;
|
||||
|
||||
devicePrivate = device->privateData;
|
||||
|
||||
if (devicePrivate->povXAxisIndex == -1 || devicePrivate->povYAxisIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
povToXY(lastValue, &lastX, &lastY);
|
||||
povToXY(value, &newX, &newY);
|
||||
|
||||
if (newX != lastX) {
|
||||
device->axisStates[devicePrivate->povXAxisIndex] = newX;
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
Gamepad_axisMoveCallback(device, devicePrivate->povXAxisIndex, newX, lastX, currentTime(), Gamepad_axisMoveContext);
|
||||
}
|
||||
}
|
||||
if (newY != lastY) {
|
||||
device->axisStates[devicePrivate->povYAxisIndex] = newY;
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
Gamepad_axisMoveCallback(device, devicePrivate->povYAxisIndex, newY, lastY, currentTime(), Gamepad_axisMoveContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Gamepad_processEvents() {
|
||||
unsigned int deviceIndex;
|
||||
static bool inProcessEvents;
|
||||
JOYINFOEX info;
|
||||
MMRESULT result;
|
||||
struct Gamepad_device * device;
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
|
||||
if (!inited || inProcessEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
inProcessEvents = true;
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
device = devices[deviceIndex];
|
||||
devicePrivate = device->privateData;
|
||||
|
||||
info.dwSize = sizeof(info);
|
||||
info.dwFlags = JOY_RETURNALL;
|
||||
result = joyGetPosEx(devicePrivate->joystickID, &info);
|
||||
if (result == JOYERR_UNPLUGGED) {
|
||||
if (Gamepad_deviceRemoveCallback != NULL) {
|
||||
Gamepad_deviceRemoveCallback(device, Gamepad_deviceRemoveContext);
|
||||
}
|
||||
|
||||
disposeDevice(device);
|
||||
numDevices--;
|
||||
for (; deviceIndex < numDevices; deviceIndex++) {
|
||||
devices[deviceIndex] = devices[deviceIndex + 1];
|
||||
}
|
||||
|
||||
} else if (result == JOYERR_NOERROR) {
|
||||
if (info.dwXpos != devicePrivate->lastState.dwXpos) {
|
||||
handleAxisChange(device, devicePrivate->xAxisIndex, info.dwXpos);
|
||||
}
|
||||
if (info.dwYpos != devicePrivate->lastState.dwYpos) {
|
||||
handleAxisChange(device, devicePrivate->yAxisIndex, info.dwYpos);
|
||||
}
|
||||
if (info.dwZpos != devicePrivate->lastState.dwZpos) {
|
||||
handleAxisChange(device, devicePrivate->zAxisIndex, info.dwZpos);
|
||||
}
|
||||
if (info.dwRpos != devicePrivate->lastState.dwRpos) {
|
||||
handleAxisChange(device, devicePrivate->rAxisIndex, info.dwRpos);
|
||||
}
|
||||
if (info.dwUpos != devicePrivate->lastState.dwUpos) {
|
||||
handleAxisChange(device, devicePrivate->uAxisIndex, info.dwUpos);
|
||||
}
|
||||
if (info.dwVpos != devicePrivate->lastState.dwVpos) {
|
||||
handleAxisChange(device, devicePrivate->vAxisIndex, info.dwVpos);
|
||||
}
|
||||
if (info.dwPOV != devicePrivate->lastState.dwPOV) {
|
||||
handlePOVChange(device, devicePrivate->lastState.dwPOV, info.dwPOV);
|
||||
}
|
||||
if (info.dwButtons != devicePrivate->lastState.dwButtons) {
|
||||
handleButtonChange(device, devicePrivate->lastState.dwButtons, info.dwButtons);
|
||||
}
|
||||
devicePrivate->lastState = info;
|
||||
}
|
||||
}
|
||||
inProcessEvents = false;
|
||||
}
|
||||
|
|
@ -1,214 +0,0 @@
|
|||
#include "gamepad/Gamepad.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <GLUT/glut.h>
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
static bool verbose = false;
|
||||
|
||||
void onButtonDown(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context) {
|
||||
if (verbose) {
|
||||
printf("Button %u down on device %u at %f with context %p\n", buttonID, device->deviceID, timestamp, context);
|
||||
}
|
||||
}
|
||||
|
||||
void onButtonUp(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context) {
|
||||
if (verbose) {
|
||||
printf("Button %u up on device %u at %f with context %p\n", buttonID, device->deviceID, timestamp, context);
|
||||
}
|
||||
}
|
||||
|
||||
void onAxisMoved(struct Gamepad_device * device, unsigned int axisID, float value, float lastValue, double timestamp, void * context) {
|
||||
if (verbose) {
|
||||
printf("Axis %u moved from %f to %f on device %u at %f with context %p\n", axisID, lastValue, value, device->deviceID, timestamp, context);
|
||||
}
|
||||
}
|
||||
|
||||
void onDeviceAttached(struct Gamepad_device * device, void * context) {
|
||||
if (verbose) {
|
||||
printf("Device ID %u attached (vendor = 0x%X; product = 0x%X) with context %p\n", device->deviceID, device->vendorID, device->productID, context);
|
||||
}
|
||||
}
|
||||
|
||||
void onDeviceRemoved(struct Gamepad_device * device, void * context) {
|
||||
if (verbose) {
|
||||
printf("Device ID %u removed with context %p\n", device->deviceID, context);
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int windowWidth = 800, windowHeight = 600;
|
||||
|
||||
static void initGamepad() {
|
||||
Gamepad_deviceAttachFunc(onDeviceAttached, (void *) 0x1);
|
||||
Gamepad_deviceRemoveFunc(onDeviceRemoved, (void *) 0x2);
|
||||
Gamepad_buttonDownFunc(onButtonDown, (void *) 0x3);
|
||||
Gamepad_buttonUpFunc(onButtonUp, (void *) 0x4);
|
||||
Gamepad_axisMoveFunc(onAxisMoved, (void *) 0x5);
|
||||
Gamepad_init();
|
||||
}
|
||||
|
||||
static void drawGlutString(int rasterPosX, int rasterPosY, const char * string) {
|
||||
size_t length, charIndex;
|
||||
|
||||
glRasterPos2i(rasterPosX, rasterPosY);
|
||||
length = strlen(string);
|
||||
for (charIndex = 0; charIndex < length; charIndex++) {
|
||||
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, string[charIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
#define POLL_ITERATION_INTERVAL 30
|
||||
|
||||
static void displayFunc(void) {
|
||||
unsigned int gamepadIndex;
|
||||
struct Gamepad_device * device;
|
||||
unsigned int axesPerRow, buttonsPerRow;
|
||||
unsigned int axisRowIndex, axisIndex;
|
||||
unsigned int buttonRowIndex, buttonIndex;
|
||||
float axisState;
|
||||
char indexString[16];
|
||||
static unsigned int iterationsToNextPoll = POLL_ITERATION_INTERVAL;
|
||||
char descriptionString[256];
|
||||
|
||||
iterationsToNextPoll--;
|
||||
if (iterationsToNextPoll == 0) {
|
||||
Gamepad_detectDevices();
|
||||
iterationsToNextPoll = POLL_ITERATION_INTERVAL;
|
||||
}
|
||||
Gamepad_processEvents();
|
||||
|
||||
axesPerRow = (windowWidth - 10) / 60;
|
||||
buttonsPerRow = (windowWidth - 10) / 30;
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glLoadIdentity();
|
||||
glTranslatef(5.0f, 20.0f, 0.0f);
|
||||
for (gamepadIndex = 0; gamepadIndex < Gamepad_numDevices(); gamepadIndex++) {
|
||||
device = Gamepad_deviceAtIndex(gamepadIndex);
|
||||
|
||||
glColor3f(0.0f, 0.0f, 0.0f);
|
||||
snprintf(descriptionString, 256, "%s (0x%X 0x%X %u)", device->description, device->vendorID, device->productID, device->deviceID);
|
||||
drawGlutString(0, 0, descriptionString);
|
||||
|
||||
for (axisRowIndex = 0; axisRowIndex <= device->numAxes / axesPerRow; axisRowIndex++) {
|
||||
glPushMatrix();
|
||||
for (axisIndex = axisRowIndex * axesPerRow; axisIndex < (axisRowIndex + 1) * axesPerRow && axisIndex < device->numAxes; axisIndex++) {
|
||||
axisState = device->axisStates[axisIndex];
|
||||
|
||||
sprintf(indexString, "a%d", axisIndex);
|
||||
glColor3f(0.0f, 0.0f, 0.0f);
|
||||
drawGlutString(2, 28, indexString);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(2.0f, 5.0f);
|
||||
glVertex2f(58.0f, 5.0f);
|
||||
glVertex2f(58.0f, 15.0f);
|
||||
glVertex2f(2.0f, 15.0f);
|
||||
glColor3f(0.5f, 1.0f, 0.5f);
|
||||
glVertex2f(29.0f + axisState * 26, 6.0f);
|
||||
glVertex2f(31.0f + axisState * 26, 6.0f);
|
||||
glVertex2f(31.0f + axisState * 26, 14.0f);
|
||||
glVertex2f(29.0f + axisState * 26, 14.0f);
|
||||
glEnd();
|
||||
glTranslatef(60.0f, 0.0f, 0.0f);
|
||||
}
|
||||
glPopMatrix();
|
||||
glTranslatef(0.0f, 32.0f, 0.0f);
|
||||
}
|
||||
|
||||
for (buttonRowIndex = 0; buttonRowIndex <= device->numButtons / buttonsPerRow; buttonRowIndex++) {
|
||||
glPushMatrix();
|
||||
for (buttonIndex = buttonRowIndex * buttonsPerRow; buttonIndex < (buttonRowIndex + 1) * buttonsPerRow && buttonIndex < device->numButtons; buttonIndex++) {
|
||||
sprintf(indexString, "b%d", buttonIndex);
|
||||
glColor3f(0.0f, 0.0f, 0.0f);
|
||||
drawGlutString(2, 32, indexString);
|
||||
|
||||
glBegin(GL_QUADS);
|
||||
glColor3f(0.0f, 0.0f, 0.0f);
|
||||
glVertex2f(2.0f, 2.0f);
|
||||
glVertex2f(28.0f, 2.0f);
|
||||
glVertex2f(28.0f, 18.0f);
|
||||
glVertex2f(2.0f, 18.0f);
|
||||
if (device->buttonStates[buttonIndex]) {
|
||||
glColor3f(0.5f, 1.0f, 0.5f);
|
||||
glVertex2f(3.0f, 3.0f);
|
||||
glVertex2f(27.0f, 3.0f);
|
||||
glVertex2f(27.0f, 17.0f);
|
||||
glVertex2f(3.0f, 17.0f);
|
||||
}
|
||||
glEnd();
|
||||
glTranslatef(30.0f, 0.0f, 0.0f);
|
||||
}
|
||||
glPopMatrix();
|
||||
glTranslatef(0.0f, 38.0f, 0.0f);
|
||||
}
|
||||
glTranslatef(0.0f, 40.0f, 0.0f);
|
||||
}
|
||||
|
||||
if (gamepadIndex == 0) {
|
||||
glLoadIdentity();
|
||||
glTranslatef(5.0f, 20.0f, 0.0f);
|
||||
glColor3f(0.0f, 0.0f, 0.0f);
|
||||
drawGlutString(0, 0, "No devices found; plug in a USB gamepad and it will be detected automatically");
|
||||
}
|
||||
|
||||
glutSwapBuffers();
|
||||
glutPostRedisplay();
|
||||
}
|
||||
|
||||
static void keyDownFunc(unsigned char charCode, int x, int y) {
|
||||
if (charCode == 'r') {
|
||||
Gamepad_shutdown();
|
||||
initGamepad();
|
||||
}
|
||||
}
|
||||
|
||||
static void reshapeFunc(int newWidth, int newHeight) {
|
||||
windowWidth = newWidth;
|
||||
windowHeight = newHeight;
|
||||
glViewport(0, 0, newWidth, newHeight);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int argIndex;
|
||||
|
||||
for (argIndex = 1; argIndex < argc; argIndex++) {
|
||||
if (!strcmp(argv[argIndex], "-v")) {
|
||||
verbose = true;
|
||||
}
|
||||
}
|
||||
|
||||
glutInit(&argc, argv);
|
||||
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
|
||||
glutInitWindowPosition(30, 30);
|
||||
glutInitWindowSize(800, 600);
|
||||
glutCreateWindow("Gamepad Test Harness");
|
||||
glutReshapeFunc(reshapeFunc);
|
||||
glutDisplayFunc(displayFunc);
|
||||
glutKeyboardFunc(keyDownFunc);
|
||||
|
||||
initGamepad();
|
||||
|
||||
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glutMainLoop();
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
VERSION_MAJOR=1
|
||||
VERSION_MINOR=4
|
||||
VERSION_TWEAK=0
|
|
@ -1,276 +1,252 @@
|
|||
#include "src/gamepad/Gamepad.h"
|
||||
|
||||
/*
|
||||
struct Gamepad_device {
|
||||
// Unique device identifier for application session, starting at 0 for the first device attached and
|
||||
// incrementing by 1 for each additional device. If a device is removed and subsequently reattached
|
||||
// during the same application session, it will have a new deviceID.
|
||||
unsigned int deviceID;
|
||||
|
||||
// Human-readable device name
|
||||
const char * description;
|
||||
|
||||
// USB vendor/product IDs as returned by the driver. Can be used to determine the particular model of device represented.
|
||||
int vendorID;
|
||||
int productID;
|
||||
|
||||
// Number of axis elements belonging to the device
|
||||
unsigned int numAxes;
|
||||
|
||||
// Number of button elements belonging to the device
|
||||
unsigned int numButtons;
|
||||
|
||||
// Array[numAxes] of values representing the current state of each axis, in the range [-1..1]
|
||||
float * axisStates;
|
||||
|
||||
// Array[numButtons] of values representing the current state of each button
|
||||
bool * buttonStates;
|
||||
|
||||
// Platform-specific device data storage. Don't touch unless you know what you're doing and don't
|
||||
// mind your code breaking in future versions of this library.
|
||||
void * privateData;
|
||||
};
|
||||
*/
|
||||
|
||||
bool verbose = false;
|
||||
|
||||
char *verboseMessage = (char *)malloc(1000);
|
||||
|
||||
void onButtonDown(struct Gamepad_device *device, unsigned int buttonID, double timestamp, void *context) {
|
||||
// buttonId is base 0
|
||||
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Button %u down on device %u at %f with context %p\n", buttonID, device->deviceID, timestamp, context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int button = buttonID;
|
||||
|
||||
int32 di, controller;
|
||||
controller = 0;
|
||||
for (di = 1; di <= device_last; di++) {
|
||||
static device_struct *d;
|
||||
d = &devices[di];
|
||||
if (d->used == 1) {
|
||||
if (d->type == 1) {
|
||||
controller++;
|
||||
if (d->handle_int == device->deviceID) {
|
||||
|
||||
// ON STRIG event
|
||||
static int32 i;
|
||||
if (controller <= 256 && button <= 255) { // within supported range
|
||||
i = (controller - 1) * 256 + button;
|
||||
if (onstrig[i].active) {
|
||||
if (onstrig[i].id) {
|
||||
if (onstrig[i].active == 1) { //(1)ON
|
||||
onstrig[i].state++;
|
||||
} else { //(2)STOP
|
||||
onstrig[i].state = 1;
|
||||
}
|
||||
qbevent = 1;
|
||||
}
|
||||
}
|
||||
} // within supported range
|
||||
|
||||
int32 eventIndex = createDeviceEvent(d);
|
||||
setDeviceEventButtonValue(d, eventIndex, button, 1);
|
||||
commitDeviceEvent(d);
|
||||
|
||||
// set STRIG_button_pressed for button
|
||||
if (button >= 0 && button <= 255) {
|
||||
d->STRIG_button_pressed[button] = 1;
|
||||
}
|
||||
} // js index
|
||||
} // type==1
|
||||
} // used
|
||||
} // di
|
||||
}
|
||||
|
||||
void onButtonUp(struct Gamepad_device *device, unsigned int buttonID, double timestamp, void *context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Button %u up on device %u at %f with context %p\n", buttonID, device->deviceID, timestamp, context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int button = buttonID;
|
||||
|
||||
int32 di;
|
||||
for (di = 1; di <= device_last; di++) {
|
||||
static device_struct *d;
|
||||
d = &devices[di];
|
||||
if (d->used == 1) {
|
||||
if (d->type == 1) {
|
||||
if (d->handle_int == device->deviceID) {
|
||||
|
||||
int32 eventIndex = createDeviceEvent(d);
|
||||
setDeviceEventButtonValue(d, eventIndex, button, 0);
|
||||
commitDeviceEvent(d);
|
||||
|
||||
} // js index
|
||||
} // type==1
|
||||
} // used
|
||||
} // di
|
||||
}
|
||||
|
||||
void onAxisMoved(struct Gamepad_device *device, unsigned int axisID, float value, float lastValue, double timestamp, void *context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Axis %u moved from %f to %f on device %u at %f with context %p\n", axisID, lastValue, value, device->deviceID, timestamp,
|
||||
context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int axis = axisID;
|
||||
|
||||
int32 di;
|
||||
|
||||
for (di = 1; di <= device_last; di++) {
|
||||
static device_struct *d;
|
||||
d = &devices[di];
|
||||
if (d->used == 1) {
|
||||
if (d->type == 1) {
|
||||
if (d->handle_int == device->deviceID) {
|
||||
|
||||
float f;
|
||||
f = value;
|
||||
/*
|
||||
if (f==-32768) f=-32767;
|
||||
f/=32767.0;
|
||||
*/
|
||||
if (f > 1.0)
|
||||
f = 1.0;
|
||||
if (f < -1.0)
|
||||
f = -1.0;
|
||||
|
||||
int32 eventIndex = createDeviceEvent(d);
|
||||
setDeviceEventAxisValue(d, eventIndex, axis, f);
|
||||
commitDeviceEvent(d);
|
||||
|
||||
} // js index
|
||||
} // type==1
|
||||
} // used
|
||||
} // di
|
||||
}
|
||||
|
||||
void onDeviceAttached(struct Gamepad_device *device, void *context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Device ID %u attached (vendor = 0x%X; product = 0x%X) with context %p\n", device->deviceID, device->vendorID,
|
||||
device->productID, context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int i, x, x2;
|
||||
|
||||
// re-aquire a potentially dropped device in its original index
|
||||
for (i = 1; i <= device_last; i++) {
|
||||
if (devices[i].used) {
|
||||
if (devices[i].type == 1) { // it's a joystick/gamepad
|
||||
if (!devices[i].connected) {
|
||||
|
||||
if (device->productID == devices[i].product_id) {
|
||||
if (device->vendorID == devices[i].vendor_id) {
|
||||
if (device->numAxes == devices[i].axes) {
|
||||
if (device->numButtons == devices[i].buttons) {
|
||||
//(sometimes when gamepads are re-plugged they receieve a generic name)
|
||||
// if (strlen(device->description)==strlen(devices[i].description)){//same name length
|
||||
// if (strcmp(device->description,devices[i].description)==0){//same name content
|
||||
// re-acquire device
|
||||
devices[i].handle_int = device->deviceID;
|
||||
if (!devices[i].connected) {
|
||||
devices[i].connected = 1;
|
||||
devices[i].name[strlen(devices[i].name) - 14] = 0; // Remove "[DISCONNECTED]"
|
||||
}
|
||||
devices[i].used = 1;
|
||||
return;
|
||||
//}
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // i
|
||||
|
||||
// add new device
|
||||
i = device_last + 1;
|
||||
if (i > device_max) {
|
||||
device_struct *devices = (device_struct *)realloc(devices, (device_max * 2 + 1) * sizeof(device_struct));
|
||||
device_max *= 2;
|
||||
}
|
||||
memset(&devices[i], 0, sizeof(device_struct));
|
||||
devices[i].type = DEVICETYPE_CONTROLLER;
|
||||
devices[i].description = strdup(device->description);
|
||||
devices[i].handle_int = device->deviceID;
|
||||
devices[i].buttons = device->numButtons;
|
||||
devices[i].lastbutton = devices[i].buttons;
|
||||
devices[i].axes = device->numAxes;
|
||||
devices[i].lastaxis = devices[i].axes;
|
||||
devices[i].product_id = device->productID;
|
||||
devices[i].vendor_id = device->vendorID;
|
||||
char name[1000];
|
||||
strcpy(name, "[CONTROLLER][[NAME][");
|
||||
strcat(name, devices[i].description);
|
||||
strcat(name, "]]");
|
||||
if (devices[i].lastbutton)
|
||||
strcat(name, "[BUTTON]");
|
||||
if (devices[i].lastaxis)
|
||||
strcat(name, "[AXIS]");
|
||||
if (devices[i].lastwheel)
|
||||
strcat(name, "[WHEEL]");
|
||||
devices[i].name = strdup(name);
|
||||
|
||||
setupDevice(&devices[i]);
|
||||
|
||||
device_last = i;
|
||||
}
|
||||
|
||||
void onDeviceRemoved(struct Gamepad_device *device, void *context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Device ID %u removed with context %p\n", device->deviceID, context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 1; i <= device_last; i++) {
|
||||
if (devices[i].used) {
|
||||
if (devices[i].type == 1) { // it's a joystick/gamepad
|
||||
if (devices[i].handle_int == device->deviceID) {
|
||||
|
||||
char name[1000];
|
||||
strcpy(name, devices[i].name);
|
||||
strcat(name, "[DISCONNECTED]");
|
||||
char *oldname = devices[i].name;
|
||||
devices[i].name = strdup(name);
|
||||
free(oldname);
|
||||
devices[i].connected = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // i
|
||||
}
|
||||
|
||||
static void initGamepad() {
|
||||
Gamepad_deviceAttachFunc(onDeviceAttached, (void *)0x1);
|
||||
Gamepad_deviceRemoveFunc(onDeviceRemoved, (void *)0x2);
|
||||
Gamepad_buttonDownFunc(onButtonDown, (void *)0x3);
|
||||
Gamepad_buttonUpFunc(onButtonUp, (void *)0x4);
|
||||
Gamepad_axisMoveFunc(onAxisMoved, (void *)0x5);
|
||||
Gamepad_init();
|
||||
}
|
||||
|
||||
void QB64_GAMEPAD_INIT() { initGamepad(); }
|
||||
|
||||
void QB64_GAMEPAD_POLL() {
|
||||
Gamepad_detectDevices();
|
||||
Gamepad_processEvents();
|
||||
}
|
||||
|
||||
void QB64_GAMEPAD_SHUTDOWN() {
|
||||
Gamepad_deviceAttachFunc(NULL, (void *)0x1);
|
||||
Gamepad_deviceRemoveFunc(NULL, (void *)0x2);
|
||||
Gamepad_buttonDownFunc(NULL, (void *)0x3);
|
||||
Gamepad_buttonUpFunc(NULL, (void *)0x4);
|
||||
Gamepad_axisMoveFunc(NULL, (void *)0x5);
|
||||
Gamepad_shutdown();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// QB64-PE Game Controller Library
|
||||
// Powered by libstem Gamepad (https://github.com/ThemsAllTook/libstem_gamepad)
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "game_controller.h"
|
||||
#include "../../../common.h"
|
||||
#include "event.h"
|
||||
#include "libstem_gamepad/Gamepad.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
static bool verbose = false;
|
||||
static char verboseMessage[1024];
|
||||
|
||||
static void onButtonDown(struct Gamepad_device *device, unsigned int buttonID, double timestamp, void *context) {
|
||||
// buttonId is base 0
|
||||
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Button %u down on device %u at %f with context %p\n", buttonID, device->deviceID, timestamp, context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int button = buttonID;
|
||||
|
||||
int32_t di, controller;
|
||||
controller = 0;
|
||||
for (di = 1; di <= device_last; di++) {
|
||||
static device_struct *d;
|
||||
d = &devices[di];
|
||||
if (d->used == 1) {
|
||||
if (d->type == 1) {
|
||||
controller++;
|
||||
if (d->handle_int == device->deviceID) {
|
||||
|
||||
// ON STRIG event
|
||||
static int32_t i;
|
||||
if (controller <= 256 && button <= 255) { // within supported range
|
||||
i = (controller - 1) * 256 + button;
|
||||
if (onstrig[i].active) {
|
||||
if (onstrig[i].id) {
|
||||
if (onstrig[i].active == 1) { //(1)ON
|
||||
onstrig[i].state++;
|
||||
} else { //(2)STOP
|
||||
onstrig[i].state = 1;
|
||||
}
|
||||
qbevent = 1;
|
||||
}
|
||||
}
|
||||
} // within supported range
|
||||
|
||||
int32_t eventIndex = createDeviceEvent(d);
|
||||
setDeviceEventButtonValue(d, eventIndex, button, 1);
|
||||
commitDeviceEvent(d);
|
||||
|
||||
// set STRIG_button_pressed for button
|
||||
if (button >= 0 && button <= 255) {
|
||||
d->STRIG_button_pressed[button] = 1;
|
||||
}
|
||||
} // js index
|
||||
} // type==1
|
||||
} // used
|
||||
} // di
|
||||
}
|
||||
|
||||
static void onButtonUp(struct Gamepad_device *device, unsigned int buttonID, double timestamp, void *context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Button %u up on device %u at %f with context %p\n", buttonID, device->deviceID, timestamp, context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int button = buttonID;
|
||||
|
||||
int32_t di;
|
||||
for (di = 1; di <= device_last; di++) {
|
||||
static device_struct *d;
|
||||
d = &devices[di];
|
||||
if (d->used == 1) {
|
||||
if (d->type == 1) {
|
||||
if (d->handle_int == device->deviceID) {
|
||||
|
||||
int32_t eventIndex = createDeviceEvent(d);
|
||||
setDeviceEventButtonValue(d, eventIndex, button, 0);
|
||||
commitDeviceEvent(d);
|
||||
|
||||
} // js index
|
||||
} // type==1
|
||||
} // used
|
||||
} // di
|
||||
}
|
||||
|
||||
static void onAxisMoved(struct Gamepad_device *device, unsigned int axisID, float value, float lastValue, double timestamp, void *context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Axis %u moved from %f to %f on device %u at %f with context %p\n", axisID, lastValue, value, device->deviceID, timestamp,
|
||||
context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int axis = axisID;
|
||||
|
||||
int32_t di;
|
||||
|
||||
for (di = 1; di <= device_last; di++) {
|
||||
static device_struct *d;
|
||||
d = &devices[di];
|
||||
if (d->used == 1) {
|
||||
if (d->type == 1) {
|
||||
if (d->handle_int == device->deviceID) {
|
||||
|
||||
float f;
|
||||
f = value;
|
||||
/*
|
||||
if (f==-32768) f=-32767;
|
||||
f/=32767.0;
|
||||
*/
|
||||
if (f > 1.0)
|
||||
f = 1.0;
|
||||
if (f < -1.0)
|
||||
f = -1.0;
|
||||
|
||||
int32_t eventIndex = createDeviceEvent(d);
|
||||
setDeviceEventAxisValue(d, eventIndex, axis, f);
|
||||
commitDeviceEvent(d);
|
||||
|
||||
} // js index
|
||||
} // type==1
|
||||
} // used
|
||||
} // di
|
||||
}
|
||||
|
||||
static void onDeviceAttached(struct Gamepad_device *device, void *context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Device ID %u attached (vendor = 0x%X; product = 0x%X) with context %p\n", device->deviceID, device->vendorID,
|
||||
device->productID, context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int i, x, x2;
|
||||
|
||||
// re-aquire a potentially dropped device in its original index
|
||||
for (i = 1; i <= device_last; i++) {
|
||||
if (devices[i].used) {
|
||||
if (devices[i].type == 1) { // it's a joystick/gamepad
|
||||
if (!devices[i].connected) {
|
||||
|
||||
if (device->productID == devices[i].product_id) {
|
||||
if (device->vendorID == devices[i].vendor_id) {
|
||||
if (device->numAxes == devices[i].axes) {
|
||||
if (device->numButtons == devices[i].buttons) {
|
||||
//(sometimes when gamepads are re-plugged they receieve a generic name)
|
||||
// if (strlen(device->description)==strlen(devices[i].description)){//same name length
|
||||
// if (strcmp(device->description,devices[i].description)==0){//same name content
|
||||
// re-acquire device
|
||||
devices[i].handle_int = device->deviceID;
|
||||
if (!devices[i].connected) {
|
||||
devices[i].connected = 1;
|
||||
devices[i].name[strlen(devices[i].name) - 14] = 0; // Remove "[DISCONNECTED]"
|
||||
}
|
||||
devices[i].used = 1;
|
||||
return;
|
||||
//}
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // i
|
||||
|
||||
// add new device
|
||||
i = device_last + 1;
|
||||
if (i > device_max) {
|
||||
device_struct *devices = (device_struct *)realloc(devices, (device_max * 2 + 1) * sizeof(device_struct));
|
||||
device_max *= 2;
|
||||
}
|
||||
memset(&devices[i], 0, sizeof(device_struct));
|
||||
devices[i].type = DEVICETYPE_CONTROLLER;
|
||||
devices[i].description = strdup(device->description);
|
||||
devices[i].handle_int = device->deviceID;
|
||||
devices[i].buttons = device->numButtons;
|
||||
devices[i].lastbutton = devices[i].buttons;
|
||||
devices[i].axes = device->numAxes;
|
||||
devices[i].lastaxis = devices[i].axes;
|
||||
devices[i].product_id = device->productID;
|
||||
devices[i].vendor_id = device->vendorID;
|
||||
char name[1000];
|
||||
strcpy(name, "[CONTROLLER][[NAME][");
|
||||
strcat(name, devices[i].description);
|
||||
strcat(name, "]]");
|
||||
if (devices[i].lastbutton)
|
||||
strcat(name, "[BUTTON]");
|
||||
if (devices[i].lastaxis)
|
||||
strcat(name, "[AXIS]");
|
||||
if (devices[i].lastwheel)
|
||||
strcat(name, "[WHEEL]");
|
||||
devices[i].name = strdup(name);
|
||||
|
||||
setupDevice(&devices[i]);
|
||||
|
||||
device_last = i;
|
||||
}
|
||||
|
||||
static void onDeviceRemoved(struct Gamepad_device *device, void *context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage, "Device ID %u removed with context %p\n", device->deviceID, context);
|
||||
std::cout << verboseMessage;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 1; i <= device_last; i++) {
|
||||
if (devices[i].used) {
|
||||
if (devices[i].type == 1) { // it's a joystick/gamepad
|
||||
if (devices[i].handle_int == device->deviceID) {
|
||||
|
||||
char name[1000];
|
||||
strcpy(name, devices[i].name);
|
||||
strcat(name, "[DISCONNECTED]");
|
||||
char *oldname = devices[i].name;
|
||||
devices[i].name = strdup(name);
|
||||
free(oldname);
|
||||
devices[i].connected = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // i
|
||||
}
|
||||
|
||||
void QB64_GAMEPAD_INIT() {
|
||||
Gamepad_deviceAttachFunc(onDeviceAttached, (void *)0x1);
|
||||
Gamepad_deviceRemoveFunc(onDeviceRemoved, (void *)0x2);
|
||||
Gamepad_buttonDownFunc(onButtonDown, (void *)0x3);
|
||||
Gamepad_buttonUpFunc(onButtonUp, (void *)0x4);
|
||||
Gamepad_axisMoveFunc(onAxisMoved, (void *)0x5);
|
||||
Gamepad_init();
|
||||
}
|
||||
|
||||
void QB64_GAMEPAD_POLL() {
|
||||
Gamepad_detectDevices();
|
||||
Gamepad_processEvents();
|
||||
}
|
||||
|
||||
void QB64_GAMEPAD_SHUTDOWN() {
|
||||
Gamepad_deviceAttachFunc(NULL, (void *)0x1);
|
||||
Gamepad_deviceRemoveFunc(NULL, (void *)0x2);
|
||||
Gamepad_buttonDownFunc(NULL, (void *)0x3);
|
||||
Gamepad_buttonUpFunc(NULL, (void *)0x4);
|
||||
Gamepad_axisMoveFunc(NULL, (void *)0x5);
|
||||
Gamepad_shutdown();
|
||||
}
|
|
@ -26,7 +26,13 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= 1600)
|
||||
#define bool int
|
||||
#define true 1
|
||||
#define false 0
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
struct Gamepad_device {
|
||||
// Unique device identifier for application session, starting at 0 for the first device attached and
|
|
@ -20,12 +20,12 @@
|
|||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include "Gamepad.h"
|
||||
#include "Gamepad_private.h"
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/input.h>
|
||||
#define __USE_UNIX98
|
||||
#include <pthread.h>
|
||||
|
@ -54,6 +54,7 @@ struct Gamepad_queuedEvent {
|
|||
static struct Gamepad_device ** devices = NULL;
|
||||
static unsigned int numDevices = 0;
|
||||
static unsigned int nextDeviceID = 0;
|
||||
static time_t lastInputStatTime = 0;
|
||||
static pthread_mutex_t devicesMutex;
|
||||
|
||||
static struct Gamepad_queuedEvent * eventQueue = NULL;
|
||||
|
@ -105,6 +106,7 @@ void Gamepad_shutdown() {
|
|||
thread = ((struct Gamepad_devicePrivate *) devices[0]->privateData)->thread;
|
||||
pthread_cancel(thread);
|
||||
pthread_join(thread, NULL);
|
||||
disposeDevice(devices[0]);
|
||||
|
||||
numDevices--;
|
||||
for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) {
|
||||
|
@ -118,10 +120,15 @@ void Gamepad_shutdown() {
|
|||
pthread_mutex_destroy(&eventQueueMutex);
|
||||
free(devices);
|
||||
devices = NULL;
|
||||
lastInputStatTime = 0;
|
||||
|
||||
for (eventIndex = 0; eventIndex < eventCount; eventIndex++) {
|
||||
if (eventQueue[eventIndex].eventType == GAMEPAD_EVENT_DEVICE_REMOVED) {
|
||||
disposeDevice(eventQueue[eventIndex].eventData);
|
||||
} else if (eventQueue[eventIndex].eventType == GAMEPAD_EVENT_BUTTON_DOWN ||
|
||||
eventQueue[eventIndex].eventType == GAMEPAD_EVENT_BUTTON_UP ||
|
||||
eventQueue[eventIndex].eventType == GAMEPAD_EVENT_AXIS_MOVED) {
|
||||
free(eventQueue[eventIndex].eventData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,7 +284,6 @@ void Gamepad_detectDevices() {
|
|||
char * description;
|
||||
int bit;
|
||||
time_t currentTime;
|
||||
static time_t lastInputStatTime;
|
||||
|
||||
if (!inited) {
|
||||
return;
|
||||
|
@ -445,6 +451,11 @@ void Gamepad_processEvents() {
|
|||
processQueuedEvent(eventQueue[eventIndex]);
|
||||
if (eventQueue[eventIndex].eventType == GAMEPAD_EVENT_DEVICE_REMOVED) {
|
||||
disposeDevice(eventQueue[eventIndex].eventData);
|
||||
|
||||
} else if (eventQueue[eventIndex].eventType == GAMEPAD_EVENT_BUTTON_DOWN ||
|
||||
eventQueue[eventIndex].eventType == GAMEPAD_EVENT_BUTTON_UP ||
|
||||
eventQueue[eventIndex].eventType == GAMEPAD_EVENT_AXIS_MOVED) {
|
||||
free(eventQueue[eventIndex].eventData);
|
||||
}
|
||||
}
|
||||
eventCount = 0;
|
|
@ -20,8 +20,8 @@
|
|||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include "Gamepad.h"
|
||||
#include "Gamepad_private.h"
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#include <limits.h>
|
||||
#include <mach/mach.h>
|
||||
|
@ -285,7 +285,7 @@ static void onDeviceMatched(void * context, IOReturn result, void * sender, IOHI
|
|||
|
||||
cfProductName = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
||||
if (cfProductName == NULL || CFGetTypeID(cfProductName) != CFStringGetTypeID()) {
|
||||
description = malloc(strlen("[Unknown]" + 1));
|
||||
description = malloc(strlen("[Unknown]") + 1);
|
||||
strcpy(description, "[Unknown]");
|
||||
|
||||
} else {
|
|
@ -20,8 +20,8 @@
|
|||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include "Gamepad.h"
|
||||
#include "Gamepad_private.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void (* Gamepad_deviceAttachCallback)(struct Gamepad_device * device, void * context) = NULL;
|
|
@ -34,8 +34,8 @@
|
|||
#define __reserved
|
||||
#endif
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include "Gamepad.h"
|
||||
#include "Gamepad_private.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -43,6 +43,118 @@
|
|||
#include <regstr.h>
|
||||
#include <dinput.h>
|
||||
#include <XInput.h>
|
||||
#include <Dbt.h>
|
||||
|
||||
// The following code is from SDL2
|
||||
// detects gamepad device remove/attach events without having to poll multiple times per second
|
||||
static bool s_bWindowsDeviceChanged = false;
|
||||
|
||||
static LRESULT CALLBACK PrivateJoystickDetectProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case WM_DEVICECHANGE:
|
||||
switch (wParam) {
|
||||
case DBT_DEVICEARRIVAL:
|
||||
if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
|
||||
s_bWindowsDeviceChanged = true;
|
||||
}
|
||||
break;
|
||||
case DBT_DEVICEREMOVECOMPLETE:
|
||||
if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
|
||||
s_bWindowsDeviceChanged = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
HRESULT coinitialized;
|
||||
WNDCLASSEX wincl;
|
||||
HWND messageWindow;
|
||||
HDEVNOTIFY hNotify;
|
||||
} DeviceNotificationData;
|
||||
|
||||
static void CleanupDeviceNotification(DeviceNotificationData *data)
|
||||
{
|
||||
if (data->hNotify)
|
||||
UnregisterDeviceNotification(data->hNotify);
|
||||
|
||||
if (data->messageWindow)
|
||||
DestroyWindow(data->messageWindow);
|
||||
|
||||
UnregisterClass(data->wincl.lpszClassName, data->wincl.hInstance);
|
||||
|
||||
if (data->coinitialized == S_OK) {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
static int CreateDeviceNotification(DeviceNotificationData *data)
|
||||
{
|
||||
DEV_BROADCAST_DEVICEINTERFACE dbh;
|
||||
GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2L, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
|
||||
|
||||
memset(data, 0, sizeof(*data));
|
||||
|
||||
data->coinitialized = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
if (data->coinitialized == RPC_E_CHANGED_MODE) {
|
||||
data->coinitialized = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
}
|
||||
|
||||
data->wincl.hInstance = GetModuleHandle(NULL);
|
||||
data->wincl.lpszClassName = "Message";
|
||||
data->wincl.lpfnWndProc = PrivateJoystickDetectProc; /* This function is called by windows */
|
||||
data->wincl.cbSize = sizeof (WNDCLASSEX);
|
||||
|
||||
if (!RegisterClassEx(&data->wincl)) {
|
||||
fprintf(stderr, "Failed to create register class for joystick autodetect");
|
||||
CleanupDeviceNotification(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
data->messageWindow = (HWND)CreateWindowEx(0, "Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
|
||||
if (!data->messageWindow) {
|
||||
fprintf(stderr, "Failed to create message window for joystick autodetect");
|
||||
CleanupDeviceNotification(data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&dbh, 0, sizeof(dbh));
|
||||
dbh.dbcc_size = sizeof(dbh);
|
||||
dbh.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
|
||||
dbh.dbcc_classguid = GUID_DEVINTERFACE_HID;
|
||||
|
||||
data->hNotify = RegisterDeviceNotification(data->messageWindow, &dbh, DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
if (!data->hNotify) {
|
||||
fprintf(stderr, "Failed to create notify device for joystick autodetect");
|
||||
CleanupDeviceNotification(data);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void CheckDeviceNotification(DeviceNotificationData *data)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
if (!data->messageWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (PeekMessage(&msg, data->messageWindow, 0, 0, PM_NOREMOVE)) {
|
||||
if (GetMessage(&msg, data->messageWindow, 0, 0) != 0) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Copy from MinGW-w64 to MinGW, along with wbemcli.h, wbemprov.h, wbemdisp.h, and wbemtran.h
|
||||
#ifndef __MINGW_EXTENSION
|
||||
|
@ -94,6 +206,7 @@ struct Gamepad_devicePrivate {
|
|||
unsigned int playerIndex;
|
||||
};
|
||||
|
||||
static DeviceNotificationData notificationData;
|
||||
static struct Gamepad_device ** devices = NULL;
|
||||
static unsigned int numDevices = 0;
|
||||
static unsigned int nextDeviceID = 0;
|
||||
|
@ -143,10 +256,7 @@ void Gamepad_init() {
|
|||
fprintf(stderr, "Gamepad_init fatal error: Couldn't load DINPUT8.dll\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
DirectInput8Create_proc = (HRESULT (WINAPI *)(HINSTANCE, DWORD, REFIID, LPVOID *, LPUNKNOWN)) GetProcAddress(module, "DirectInput8Create");
|
||||
|
||||
result = DirectInput8Create_proc(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8, (void **) &directInputInterface, NULL);
|
||||
|
||||
if (result != DI_OK) {
|
||||
|
@ -154,7 +264,9 @@ void Gamepad_init() {
|
|||
}
|
||||
|
||||
inited = true;
|
||||
s_bWindowsDeviceChanged = true;
|
||||
Gamepad_detectDevices();
|
||||
CreateDeviceNotification(¬ificationData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,6 +298,7 @@ void Gamepad_shutdown() {
|
|||
devices = NULL;
|
||||
numDevices = 0;
|
||||
inited = false;
|
||||
CleanupDeviceNotification(¬ificationData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -745,6 +858,10 @@ static BOOL CALLBACK enumDevicesCallback(const DIDEVICEINSTANCE * instance, LPVO
|
|||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
if (Gamepad_deviceAttachCallback != NULL) {
|
||||
Gamepad_deviceAttachCallback(deviceRecord, Gamepad_deviceAttachContext);
|
||||
}
|
||||
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -770,9 +887,13 @@ void Gamepad_detectDevices() {
|
|||
return;
|
||||
}
|
||||
|
||||
result = IDirectInput_EnumDevices(directInputInterface, DI8DEVCLASS_GAMECTRL, enumDevicesCallback, NULL, DIEDFL_ALLDEVICES);
|
||||
if (result != DI_OK) {
|
||||
fprintf(stderr, "Warning: IDirectInput_EnumDevices returned 0x%X\n", (unsigned int) result);
|
||||
CheckDeviceNotification(¬ificationData);
|
||||
if (s_bWindowsDeviceChanged) {
|
||||
result = IDirectInput_EnumDevices(directInputInterface, DI8DEVCLASS_GAMECTRL, enumDevicesCallback, NULL, DIEDFL_ALLDEVICES);
|
||||
if (result != DI_OK) {
|
||||
fprintf(stderr, "Warning: IDirectInput_EnumDevices returned 0x%X\n", (unsigned int) result);
|
||||
}
|
||||
s_bWindowsDeviceChanged = false;
|
||||
}
|
||||
|
||||
if (xInputAvailable) {
|
||||
|
@ -800,6 +921,9 @@ void Gamepad_detectDevices() {
|
|||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
registeredXInputDevices[playerIndex] = deviceRecord;
|
||||
if (Gamepad_deviceAttachCallback != NULL) {
|
||||
Gamepad_deviceAttachCallback(deviceRecord, Gamepad_deviceAttachContext);
|
||||
}
|
||||
|
||||
} else if (xResult != ERROR_SUCCESS && registeredXInputDevices[playerIndex] != NULL) {
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
|
@ -960,7 +1084,7 @@ void Gamepad_processEvents() {
|
|||
IDirectInputDevice8_Acquire(devicePrivate->deviceInterface);
|
||||
result = IDirectInputDevice8_GetDeviceData(devicePrivate->deviceInterface, sizeof(DIDEVICEOBJECTDATA), events, &eventCount, 0);
|
||||
}
|
||||
if (result != DI_OK) {
|
||||
if (!SUCCEEDED(result)) {
|
||||
removeDevice(deviceIndex);
|
||||
deviceIndex--;
|
||||
continue;
|
|
@ -1 +0,0 @@
|
|||
http://forums.tigsource.com/index.php?topic=10675.80
|
|
@ -1,454 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Alex Diener
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <linux/input.h>
|
||||
#define __USE_UNIX98
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct Gamepad_devicePrivate {
|
||||
pthread_t thread;
|
||||
int fd;
|
||||
char * path;
|
||||
int buttonMap[KEY_CNT - BTN_MISC];
|
||||
int axisMap[ABS_CNT];
|
||||
struct input_absinfo axisInfo[ABS_CNT];
|
||||
};
|
||||
|
||||
struct Gamepad_queuedEvent {
|
||||
unsigned int deviceID;
|
||||
enum Gamepad_eventType eventType;
|
||||
void * eventData;
|
||||
};
|
||||
|
||||
static struct Gamepad_device ** devices = NULL;
|
||||
static unsigned int numDevices = 0;
|
||||
static unsigned int nextDeviceID = 0;
|
||||
static pthread_mutex_t devicesMutex;
|
||||
|
||||
static struct Gamepad_queuedEvent * eventQueue = NULL;
|
||||
static size_t eventQueueSize = 0;
|
||||
static size_t eventCount = 0;
|
||||
static pthread_mutex_t eventQueueMutex;
|
||||
|
||||
static bool inited = false;
|
||||
|
||||
#define test_bit(bitIndex, array) \
|
||||
((array[(bitIndex) / (sizeof(int) * 8)] >> ((bitIndex) % (sizeof(int) * 8))) & 0x1)
|
||||
|
||||
void Gamepad_init() {
|
||||
if (!inited) {
|
||||
pthread_mutexattr_t recursiveLock;
|
||||
pthread_mutexattr_init(&recursiveLock);
|
||||
pthread_mutexattr_settype(&recursiveLock, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&devicesMutex, &recursiveLock);
|
||||
pthread_mutex_init(&eventQueueMutex, &recursiveLock);
|
||||
inited = true;
|
||||
Gamepad_detectDevices();
|
||||
}
|
||||
}
|
||||
|
||||
static void disposeDevice(struct Gamepad_device * device) {
|
||||
close(((struct Gamepad_devicePrivate *) device->privateData)->fd);
|
||||
free(((struct Gamepad_devicePrivate *) device->privateData)->path);
|
||||
free(device->privateData);
|
||||
|
||||
free((void *) device->description);
|
||||
free(device->axisStates);
|
||||
free(device->buttonStates);
|
||||
|
||||
free(device);
|
||||
}
|
||||
|
||||
void Gamepad_shutdown() {
|
||||
if (inited) {
|
||||
unsigned int eventIndex;
|
||||
unsigned int devicesLeft;
|
||||
unsigned int gamepadIndex;
|
||||
|
||||
do {
|
||||
pthread_mutex_lock(&devicesMutex);
|
||||
devicesLeft = numDevices;
|
||||
if (devicesLeft > 0) {
|
||||
pthread_t thread;
|
||||
|
||||
thread = ((struct Gamepad_devicePrivate *) devices[0]->privateData)->thread;
|
||||
pthread_cancel(thread);
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
numDevices--;
|
||||
for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) {
|
||||
devices[gamepadIndex] = devices[gamepadIndex + 1];
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&devicesMutex);
|
||||
} while (devicesLeft > 0);
|
||||
|
||||
pthread_mutex_destroy(&devicesMutex);
|
||||
pthread_mutex_destroy(&eventQueueMutex);
|
||||
free(devices);
|
||||
devices = NULL;
|
||||
|
||||
for (eventIndex = 0; eventIndex < eventCount; eventIndex++) {
|
||||
if (eventQueue[eventIndex].eventType == GAMEPAD_EVENT_DEVICE_REMOVED) {
|
||||
disposeDevice(eventQueue[eventIndex].eventData);
|
||||
}
|
||||
}
|
||||
|
||||
eventQueueSize = 0;
|
||||
eventCount = 0;
|
||||
free(eventQueue);
|
||||
eventQueue = NULL;
|
||||
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Gamepad_numDevices() {
|
||||
unsigned int result;
|
||||
|
||||
pthread_mutex_lock(&devicesMutex);
|
||||
result = numDevices;
|
||||
pthread_mutex_unlock(&devicesMutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex) {
|
||||
struct Gamepad_device * result;
|
||||
|
||||
pthread_mutex_lock(&devicesMutex);
|
||||
if (deviceIndex >= numDevices) {
|
||||
result = NULL;
|
||||
} else {
|
||||
result = devices[deviceIndex];
|
||||
}
|
||||
pthread_mutex_unlock(&devicesMutex);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void queueEvent(unsigned int deviceID, enum Gamepad_eventType eventType, void * eventData) {
|
||||
struct Gamepad_queuedEvent queuedEvent;
|
||||
|
||||
queuedEvent.deviceID = deviceID;
|
||||
queuedEvent.eventType = eventType;
|
||||
queuedEvent.eventData = eventData;
|
||||
|
||||
pthread_mutex_lock(&eventQueueMutex);
|
||||
if (eventCount >= eventQueueSize) {
|
||||
eventQueueSize = eventQueueSize == 0 ? 1 : eventQueueSize * 2;
|
||||
eventQueue = realloc(eventQueue, sizeof(struct Gamepad_queuedEvent) * eventQueueSize);
|
||||
}
|
||||
eventQueue[eventCount++] = queuedEvent;
|
||||
pthread_mutex_unlock(&eventQueueMutex);
|
||||
}
|
||||
|
||||
static void queueAxisEvent(struct Gamepad_device * device, double timestamp, unsigned int axisID, float value, float lastValue) {
|
||||
struct Gamepad_axisEvent * axisEvent;
|
||||
|
||||
axisEvent = malloc(sizeof(struct Gamepad_axisEvent));
|
||||
axisEvent->device = device;
|
||||
axisEvent->timestamp = timestamp;
|
||||
axisEvent->axisID = axisID;
|
||||
axisEvent->value = value;
|
||||
axisEvent->lastValue = lastValue;
|
||||
|
||||
queueEvent(device->deviceID, GAMEPAD_EVENT_AXIS_MOVED, axisEvent);
|
||||
}
|
||||
|
||||
static void queueButtonEvent(struct Gamepad_device * device, double timestamp, unsigned int buttonID, bool down) {
|
||||
struct Gamepad_buttonEvent * buttonEvent;
|
||||
|
||||
buttonEvent = malloc(sizeof(struct Gamepad_buttonEvent));
|
||||
buttonEvent->device = device;
|
||||
buttonEvent->timestamp = timestamp;
|
||||
buttonEvent->buttonID = buttonID;
|
||||
buttonEvent->down = down;
|
||||
|
||||
queueEvent(device->deviceID, down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, buttonEvent);
|
||||
}
|
||||
|
||||
static void * deviceThread(void * context) {
|
||||
unsigned int gamepadIndex;
|
||||
struct Gamepad_device * device;
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
struct input_event event;
|
||||
|
||||
device = context;
|
||||
devicePrivate = device->privateData;
|
||||
|
||||
while (read(devicePrivate->fd, &event, sizeof(struct input_event)) > 0) {
|
||||
if (event.type == EV_ABS) {
|
||||
float value;
|
||||
|
||||
if (event.code > ABS_MAX || devicePrivate->axisMap[event.code] == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
value = (event.value - devicePrivate->axisInfo[event.code].minimum) / (float) (devicePrivate->axisInfo[event.code].maximum - devicePrivate->axisInfo[event.code].minimum) * 2.0f - 1.0f;
|
||||
queueAxisEvent(device,
|
||||
event.time.tv_sec + event.time.tv_usec * 0.000001,
|
||||
devicePrivate->axisMap[event.code],
|
||||
value,
|
||||
device->axisStates[devicePrivate->axisMap[event.code]]);
|
||||
|
||||
device->axisStates[devicePrivate->axisMap[event.code]] = value;
|
||||
|
||||
} else if (event.type == EV_KEY) {
|
||||
if (event.code < BTN_MISC || event.code > KEY_MAX || devicePrivate->buttonMap[event.code - BTN_MISC] == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
queueButtonEvent(device,
|
||||
event.time.tv_sec + event.time.tv_usec * 0.000001,
|
||||
devicePrivate->buttonMap[event.code - BTN_MISC],
|
||||
!!event.value);
|
||||
|
||||
device->buttonStates[devicePrivate->buttonMap[event.code - BTN_MISC]] = !!event.value;
|
||||
}
|
||||
}
|
||||
|
||||
queueEvent(device->deviceID, GAMEPAD_EVENT_DEVICE_REMOVED, device);
|
||||
|
||||
pthread_mutex_lock(&devicesMutex);
|
||||
for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) {
|
||||
if (devices[gamepadIndex] == device) {
|
||||
unsigned int gamepadIndex2;
|
||||
|
||||
numDevices--;
|
||||
for (gamepadIndex2 = gamepadIndex; gamepadIndex2 < numDevices; gamepadIndex2++) {
|
||||
devices[gamepadIndex2] = devices[gamepadIndex2 + 1];
|
||||
}
|
||||
gamepadIndex--;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&devicesMutex);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Gamepad_detectDevices() {
|
||||
struct input_id id;
|
||||
DIR * dev_input;
|
||||
struct dirent * entity;
|
||||
unsigned int charsConsumed;
|
||||
int num;
|
||||
int fd;
|
||||
int evCapBits[(EV_CNT - 1) / sizeof(int) * 8 + 1];
|
||||
int evKeyBits[(KEY_CNT - 1) / sizeof(int) * 8 + 1];
|
||||
int evAbsBits[(ABS_CNT - 1) / sizeof(int) * 8 + 1];
|
||||
char fileName[PATH_MAX];
|
||||
bool duplicate;
|
||||
unsigned int gamepadIndex;
|
||||
struct stat statBuf;
|
||||
struct Gamepad_device * deviceRecord;
|
||||
struct Gamepad_devicePrivate * deviceRecordPrivate;
|
||||
char name[128];
|
||||
char * description;
|
||||
int bit;
|
||||
time_t currentTime;
|
||||
static time_t lastInputStatTime;
|
||||
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&devicesMutex);
|
||||
|
||||
dev_input = opendir("/dev/input");
|
||||
currentTime = time(NULL);
|
||||
if (dev_input != NULL) {
|
||||
while ((entity = readdir(dev_input)) != NULL) {
|
||||
charsConsumed = 0;
|
||||
if (sscanf(entity->d_name, "event%d%n", &num, &charsConsumed) && charsConsumed == strlen(entity->d_name)) {
|
||||
snprintf(fileName, PATH_MAX, "/dev/input/%s", entity->d_name);
|
||||
if (stat(fileName, &statBuf) || statBuf.st_mtime < lastInputStatTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
duplicate = false;
|
||||
for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) {
|
||||
if (!strcmp(((struct Gamepad_devicePrivate *) devices[gamepadIndex]->privateData)->path, fileName)) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = open(fileName, O_RDONLY, 0);
|
||||
memset(evCapBits, 0, sizeof(evCapBits));
|
||||
memset(evKeyBits, 0, sizeof(evKeyBits));
|
||||
memset(evAbsBits, 0, sizeof(evAbsBits));
|
||||
if (ioctl(fd, EVIOCGBIT(0, sizeof(evCapBits)), evCapBits) < 0 ||
|
||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(evKeyBits)), evKeyBits) < 0 ||
|
||||
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(evAbsBits)), evAbsBits) < 0) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
if (!test_bit(EV_KEY, evCapBits) || !test_bit(EV_ABS, evCapBits) ||
|
||||
!test_bit(ABS_X, evAbsBits) || !test_bit(ABS_Y, evAbsBits) ||
|
||||
(!test_bit(BTN_TRIGGER, evKeyBits) && !test_bit(BTN_A, evKeyBits) && !test_bit(BTN_1, evKeyBits))) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceRecord = malloc(sizeof(struct Gamepad_device));
|
||||
deviceRecord->deviceID = nextDeviceID++;
|
||||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
deviceRecordPrivate = malloc(sizeof(struct Gamepad_devicePrivate));
|
||||
deviceRecordPrivate->fd = fd;
|
||||
deviceRecordPrivate->path = malloc(strlen(fileName) + 1);
|
||||
strcpy(deviceRecordPrivate->path, fileName);
|
||||
memset(deviceRecordPrivate->buttonMap, 0xFF, sizeof(deviceRecordPrivate->buttonMap));
|
||||
memset(deviceRecordPrivate->axisMap, 0xFF, sizeof(deviceRecordPrivate->axisMap));
|
||||
deviceRecord->privateData = deviceRecordPrivate;
|
||||
|
||||
if (ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0) {
|
||||
description = malloc(strlen(name) + 1);
|
||||
strcpy(description, name);
|
||||
} else {
|
||||
description = malloc(strlen(fileName) + 1);
|
||||
strcpy(description, fileName);
|
||||
}
|
||||
deviceRecord->description = description;
|
||||
|
||||
if (!ioctl(fd, EVIOCGID, &id)) {
|
||||
deviceRecord->vendorID = id.vendor;
|
||||
deviceRecord->productID = id.product;
|
||||
} else {
|
||||
deviceRecord->vendorID = deviceRecord->productID = 0;
|
||||
}
|
||||
|
||||
memset(evKeyBits, 0, sizeof(evKeyBits));
|
||||
memset(evAbsBits, 0, sizeof(evAbsBits));
|
||||
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(evKeyBits)), evKeyBits);
|
||||
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(evAbsBits)), evAbsBits);
|
||||
|
||||
deviceRecord->numAxes = 0;
|
||||
for (bit = 0; bit < ABS_CNT; bit++) {
|
||||
if (test_bit(bit, evAbsBits)) {
|
||||
if (ioctl(fd, EVIOCGABS(bit), &deviceRecordPrivate->axisInfo[bit]) < 0 ||
|
||||
deviceRecordPrivate->axisInfo[bit].minimum == deviceRecordPrivate->axisInfo[bit].maximum) {
|
||||
continue;
|
||||
}
|
||||
deviceRecordPrivate->axisMap[bit] = deviceRecord->numAxes;
|
||||
deviceRecord->numAxes++;
|
||||
}
|
||||
}
|
||||
deviceRecord->numButtons = 0;
|
||||
for (bit = BTN_MISC; bit < KEY_CNT; bit++) {
|
||||
if (test_bit(bit, evKeyBits)) {
|
||||
deviceRecordPrivate->buttonMap[bit - BTN_MISC] = deviceRecord->numButtons;
|
||||
deviceRecord->numButtons++;
|
||||
}
|
||||
}
|
||||
|
||||
deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes);
|
||||
deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons);
|
||||
|
||||
if (Gamepad_deviceAttachCallback != NULL) {
|
||||
Gamepad_deviceAttachCallback(deviceRecord, Gamepad_deviceAttachContext);
|
||||
}
|
||||
|
||||
pthread_create(&deviceRecordPrivate->thread, NULL, deviceThread, deviceRecord);
|
||||
}
|
||||
}
|
||||
closedir(dev_input);
|
||||
}
|
||||
|
||||
lastInputStatTime = currentTime;
|
||||
pthread_mutex_unlock(&devicesMutex);
|
||||
}
|
||||
|
||||
static void processQueuedEvent(struct Gamepad_queuedEvent event) {
|
||||
switch (event.eventType) {
|
||||
case GAMEPAD_EVENT_DEVICE_ATTACHED:
|
||||
if (Gamepad_deviceAttachCallback != NULL) {
|
||||
Gamepad_deviceAttachCallback(event.eventData, Gamepad_deviceAttachContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAMEPAD_EVENT_DEVICE_REMOVED:
|
||||
if (Gamepad_deviceRemoveCallback != NULL) {
|
||||
Gamepad_deviceRemoveCallback(event.eventData, Gamepad_deviceRemoveContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAMEPAD_EVENT_BUTTON_DOWN:
|
||||
if (Gamepad_buttonDownCallback != NULL) {
|
||||
struct Gamepad_buttonEvent * buttonEvent = event.eventData;
|
||||
Gamepad_buttonDownCallback(buttonEvent->device, buttonEvent->buttonID, buttonEvent->timestamp, Gamepad_buttonDownContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAMEPAD_EVENT_BUTTON_UP:
|
||||
if (Gamepad_buttonUpCallback != NULL) {
|
||||
struct Gamepad_buttonEvent * buttonEvent = event.eventData;
|
||||
Gamepad_buttonUpCallback(buttonEvent->device, buttonEvent->buttonID, buttonEvent->timestamp, Gamepad_buttonUpContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAMEPAD_EVENT_AXIS_MOVED:
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
struct Gamepad_axisEvent * axisEvent = event.eventData;
|
||||
Gamepad_axisMoveCallback(axisEvent->device, axisEvent->axisID, axisEvent->value, axisEvent->lastValue, axisEvent->timestamp, Gamepad_axisMoveContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Gamepad_processEvents() {
|
||||
unsigned int eventIndex;
|
||||
static bool inProcessEvents;
|
||||
|
||||
if (!inited || inProcessEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
inProcessEvents = true;
|
||||
pthread_mutex_lock(&eventQueueMutex);
|
||||
for (eventIndex = 0; eventIndex < eventCount; eventIndex++) {
|
||||
processQueuedEvent(eventQueue[eventIndex]);
|
||||
if (eventQueue[eventIndex].eventType == GAMEPAD_EVENT_DEVICE_REMOVED) {
|
||||
disposeDevice(eventQueue[eventIndex].eventData);
|
||||
}
|
||||
}
|
||||
eventCount = 0;
|
||||
pthread_mutex_unlock(&eventQueueMutex);
|
||||
inProcessEvents = false;
|
||||
}
|
||||
|
|
@ -1,562 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Alex Diener
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#include <limits.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#define GAMEPAD_RUN_LOOP_MODE CFSTR("GamepadRunLoopMode")
|
||||
|
||||
struct HIDGamepadAxis {
|
||||
IOHIDElementCookie cookie;
|
||||
CFIndex logicalMin;
|
||||
CFIndex logicalMax;
|
||||
bool hasNullState;
|
||||
bool isHatSwitch;
|
||||
bool isHatSwitchSecondAxis;
|
||||
};
|
||||
|
||||
struct HIDGamepadButton {
|
||||
IOHIDElementCookie cookie;
|
||||
};
|
||||
|
||||
struct Gamepad_devicePrivate {
|
||||
IOHIDDeviceRef deviceRef;
|
||||
struct HIDGamepadAxis * axisElements;
|
||||
struct HIDGamepadButton * buttonElements;
|
||||
};
|
||||
|
||||
struct Gamepad_queuedEvent {
|
||||
unsigned int deviceID;
|
||||
enum Gamepad_eventType eventType;
|
||||
void * eventData;
|
||||
};
|
||||
|
||||
static IOHIDManagerRef hidManager = NULL;
|
||||
static struct Gamepad_device ** devices = NULL;
|
||||
static unsigned int numDevices = 0;
|
||||
static unsigned int nextDeviceID = 0;
|
||||
|
||||
static struct Gamepad_queuedEvent * inputEventQueue = NULL;
|
||||
static size_t inputEventQueueSize = 0;
|
||||
static size_t inputEventCount = 0;
|
||||
|
||||
static struct Gamepad_queuedEvent * deviceEventQueue = NULL;
|
||||
static size_t deviceEventQueueSize = 0;
|
||||
static size_t deviceEventCount = 0;
|
||||
|
||||
static void hatValueToXY(CFIndex value, CFIndex range, int * outX, int * outY) {
|
||||
if (value == range) {
|
||||
*outX = *outY = 0;
|
||||
|
||||
} else {
|
||||
if (value > 0 && value < range / 2) {
|
||||
*outX = 1;
|
||||
|
||||
} else if (value > range / 2) {
|
||||
*outX = -1;
|
||||
|
||||
} else {
|
||||
*outX = 0;
|
||||
}
|
||||
|
||||
if (value > range / 4 * 3 || value < range / 4) {
|
||||
*outY = -1;
|
||||
|
||||
} else if (value > range / 4 && value < range / 4 * 3) {
|
||||
*outY = 1;
|
||||
|
||||
} else {
|
||||
*outY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void queueInputEvent(unsigned int deviceID, enum Gamepad_eventType eventType, void * eventData) {
|
||||
struct Gamepad_queuedEvent queuedEvent;
|
||||
|
||||
queuedEvent.deviceID = deviceID;
|
||||
queuedEvent.eventType = eventType;
|
||||
queuedEvent.eventData = eventData;
|
||||
|
||||
if (inputEventCount >= inputEventQueueSize) {
|
||||
inputEventQueueSize = inputEventQueueSize == 0 ? 1 : inputEventQueueSize * 2;
|
||||
inputEventQueue = realloc(inputEventQueue, sizeof(struct Gamepad_queuedEvent) * inputEventQueueSize);
|
||||
}
|
||||
inputEventQueue[inputEventCount++] = queuedEvent;
|
||||
}
|
||||
|
||||
static void queueAxisEvent(struct Gamepad_device * device, double timestamp, unsigned int axisID, float value, float lastValue) {
|
||||
struct Gamepad_axisEvent * axisEvent;
|
||||
|
||||
axisEvent = malloc(sizeof(struct Gamepad_axisEvent));
|
||||
axisEvent->device = device;
|
||||
axisEvent->timestamp = timestamp;
|
||||
axisEvent->axisID = axisID;
|
||||
axisEvent->value = value;
|
||||
axisEvent->lastValue = lastValue;
|
||||
|
||||
queueInputEvent(device->deviceID, GAMEPAD_EVENT_AXIS_MOVED, axisEvent);
|
||||
}
|
||||
|
||||
static void queueButtonEvent(struct Gamepad_device * device, double timestamp, unsigned int buttonID, bool down) {
|
||||
struct Gamepad_buttonEvent * buttonEvent;
|
||||
|
||||
buttonEvent = malloc(sizeof(struct Gamepad_buttonEvent));
|
||||
buttonEvent->device = device;
|
||||
buttonEvent->timestamp = timestamp;
|
||||
buttonEvent->buttonID = buttonID;
|
||||
buttonEvent->down = down;
|
||||
|
||||
queueInputEvent(device->deviceID, down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, buttonEvent);
|
||||
}
|
||||
|
||||
static void onDeviceValueChanged(void * context, IOReturn result, void * sender, IOHIDValueRef value) {
|
||||
struct Gamepad_device * deviceRecord;
|
||||
struct Gamepad_devicePrivate * hidDeviceRecord;
|
||||
IOHIDElementRef element;
|
||||
IOHIDElementCookie cookie;
|
||||
unsigned int axisIndex, buttonIndex;
|
||||
static mach_timebase_info_data_t timebaseInfo;
|
||||
|
||||
if (timebaseInfo.denom == 0) {
|
||||
mach_timebase_info(&timebaseInfo);
|
||||
}
|
||||
|
||||
deviceRecord = context;
|
||||
hidDeviceRecord = deviceRecord->privateData;
|
||||
element = IOHIDValueGetElement(value);
|
||||
cookie = IOHIDElementGetCookie(element);
|
||||
|
||||
for (axisIndex = 0; axisIndex < deviceRecord->numAxes; axisIndex++) {
|
||||
if (!hidDeviceRecord->axisElements[axisIndex].isHatSwitchSecondAxis &&
|
||||
hidDeviceRecord->axisElements[axisIndex].cookie == cookie) {
|
||||
CFIndex integerValue;
|
||||
|
||||
if (IOHIDValueGetLength(value) > 4) {
|
||||
// Workaround for a strange crash that occurs with PS3 controller; was getting lengths of 39 (!)
|
||||
continue;
|
||||
}
|
||||
integerValue = IOHIDValueGetIntegerValue(value);
|
||||
|
||||
if (hidDeviceRecord->axisElements[axisIndex].isHatSwitch) {
|
||||
int x, y;
|
||||
|
||||
// Fix for Saitek X52
|
||||
if (!hidDeviceRecord->axisElements[axisIndex].hasNullState) {
|
||||
if (integerValue < hidDeviceRecord->axisElements[axisIndex].logicalMin) {
|
||||
integerValue = hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin + 1;
|
||||
} else {
|
||||
integerValue--;
|
||||
}
|
||||
}
|
||||
|
||||
hatValueToXY(integerValue, hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin + 1, &x, &y);
|
||||
|
||||
if (x != deviceRecord->axisStates[axisIndex]) {
|
||||
queueAxisEvent(deviceRecord,
|
||||
IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
||||
axisIndex,
|
||||
x,
|
||||
deviceRecord->axisStates[axisIndex]);
|
||||
|
||||
deviceRecord->axisStates[axisIndex] = x;
|
||||
}
|
||||
|
||||
if (y != deviceRecord->axisStates[axisIndex + 1]) {
|
||||
queueAxisEvent(deviceRecord,
|
||||
IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
||||
axisIndex + 1,
|
||||
y,
|
||||
deviceRecord->axisStates[axisIndex + 1]);
|
||||
|
||||
deviceRecord->axisStates[axisIndex + 1] = y;
|
||||
}
|
||||
|
||||
} else {
|
||||
float floatValue;
|
||||
|
||||
if (integerValue < hidDeviceRecord->axisElements[axisIndex].logicalMin) {
|
||||
hidDeviceRecord->axisElements[axisIndex].logicalMin = integerValue;
|
||||
}
|
||||
if (integerValue > hidDeviceRecord->axisElements[axisIndex].logicalMax) {
|
||||
hidDeviceRecord->axisElements[axisIndex].logicalMax = integerValue;
|
||||
}
|
||||
floatValue = (integerValue - hidDeviceRecord->axisElements[axisIndex].logicalMin) / (float) (hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin) * 2.0f - 1.0f;
|
||||
|
||||
queueAxisEvent(deviceRecord,
|
||||
IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
||||
axisIndex,
|
||||
floatValue,
|
||||
deviceRecord->axisStates[axisIndex]);
|
||||
|
||||
deviceRecord->axisStates[axisIndex] = floatValue;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (buttonIndex = 0; buttonIndex < deviceRecord->numButtons; buttonIndex++) {
|
||||
if (hidDeviceRecord->buttonElements[buttonIndex].cookie == cookie) {
|
||||
bool down;
|
||||
|
||||
down = IOHIDValueGetIntegerValue(value);
|
||||
queueButtonEvent(deviceRecord,
|
||||
IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
||||
buttonIndex,
|
||||
down);
|
||||
|
||||
deviceRecord->buttonStates[buttonIndex] = down;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key) {
|
||||
CFTypeRef typeRef;
|
||||
int value;
|
||||
|
||||
typeRef = IOHIDDeviceGetProperty(deviceRef, key);
|
||||
if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFNumberGetValue((CFNumberRef) typeRef, kCFNumberSInt32Type, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static int IOHIDDeviceGetVendorID(IOHIDDeviceRef deviceRef) {
|
||||
return IOHIDDeviceGetIntProperty(deviceRef, CFSTR(kIOHIDVendorIDKey));
|
||||
}
|
||||
|
||||
static int IOHIDDeviceGetProductID(IOHIDDeviceRef deviceRef) {
|
||||
return IOHIDDeviceGetIntProperty(deviceRef, CFSTR(kIOHIDProductIDKey));
|
||||
}
|
||||
|
||||
static void onDeviceMatched(void * context, IOReturn result, void * sender, IOHIDDeviceRef device) {
|
||||
CFArrayRef elements;
|
||||
CFIndex elementIndex;
|
||||
IOHIDElementRef element;
|
||||
CFStringRef cfProductName;
|
||||
struct Gamepad_device * deviceRecord;
|
||||
struct Gamepad_devicePrivate * hidDeviceRecord;
|
||||
IOHIDElementType type;
|
||||
char * description;
|
||||
struct Gamepad_queuedEvent queuedEvent;
|
||||
|
||||
deviceRecord = malloc(sizeof(struct Gamepad_device));
|
||||
deviceRecord->deviceID = nextDeviceID++;
|
||||
deviceRecord->vendorID = IOHIDDeviceGetVendorID(device);
|
||||
deviceRecord->productID = IOHIDDeviceGetProductID(device);
|
||||
deviceRecord->numAxes = 0;
|
||||
deviceRecord->numButtons = 0;
|
||||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
hidDeviceRecord = malloc(sizeof(struct Gamepad_devicePrivate));
|
||||
hidDeviceRecord->deviceRef = device;
|
||||
hidDeviceRecord->axisElements = NULL;
|
||||
hidDeviceRecord->buttonElements = NULL;
|
||||
deviceRecord->privateData = hidDeviceRecord;
|
||||
|
||||
cfProductName = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
||||
if (cfProductName == NULL || CFGetTypeID(cfProductName) != CFStringGetTypeID()) {
|
||||
description = malloc(strlen("[Unknown]" + 1));
|
||||
strcpy(description, "[Unknown]");
|
||||
|
||||
} else {
|
||||
CFIndex length;
|
||||
|
||||
CFStringGetBytes(cfProductName, CFRangeMake(0, CFStringGetLength(cfProductName)), kCFStringEncodingUTF8, '?', false, NULL, 100, &length);
|
||||
description = malloc(length + 1);
|
||||
CFStringGetBytes(cfProductName, CFRangeMake(0, CFStringGetLength(cfProductName)), kCFStringEncodingUTF8, '?', false, (UInt8 *) description, length + 1, NULL);
|
||||
description[length] = '\x00';
|
||||
}
|
||||
deviceRecord->description = description;
|
||||
|
||||
elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone);
|
||||
for (elementIndex = 0; elementIndex < CFArrayGetCount(elements); elementIndex++) {
|
||||
element = (IOHIDElementRef) CFArrayGetValueAtIndex(elements, elementIndex);
|
||||
type = IOHIDElementGetType(element);
|
||||
|
||||
// All of the axis elements I've ever detected have been kIOHIDElementTypeInput_Misc. kIOHIDElementTypeInput_Axis is only included for good faith...
|
||||
if (type == kIOHIDElementTypeInput_Misc ||
|
||||
type == kIOHIDElementTypeInput_Axis) {
|
||||
|
||||
hidDeviceRecord->axisElements = realloc(hidDeviceRecord->axisElements, sizeof(struct HIDGamepadAxis) * (deviceRecord->numAxes + 1));
|
||||
hidDeviceRecord->axisElements[deviceRecord->numAxes].cookie = IOHIDElementGetCookie(element);
|
||||
hidDeviceRecord->axisElements[deviceRecord->numAxes].logicalMin = IOHIDElementGetLogicalMin(element);
|
||||
hidDeviceRecord->axisElements[deviceRecord->numAxes].logicalMax = IOHIDElementGetLogicalMax(element);
|
||||
hidDeviceRecord->axisElements[deviceRecord->numAxes].hasNullState = !!IOHIDElementHasNullState(element);
|
||||
hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitch = IOHIDElementGetUsage(element) == kHIDUsage_GD_Hatswitch;
|
||||
hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitchSecondAxis = false;
|
||||
deviceRecord->numAxes++;
|
||||
|
||||
if (hidDeviceRecord->axisElements[deviceRecord->numAxes - 1].isHatSwitch) {
|
||||
hidDeviceRecord->axisElements = realloc(hidDeviceRecord->axisElements, sizeof(struct HIDGamepadAxis) * (deviceRecord->numAxes + 1));
|
||||
hidDeviceRecord->axisElements[deviceRecord->numAxes].isHatSwitchSecondAxis = true;
|
||||
deviceRecord->numAxes++;
|
||||
}
|
||||
|
||||
} else if (type == kIOHIDElementTypeInput_Button) {
|
||||
hidDeviceRecord->buttonElements = realloc(hidDeviceRecord->buttonElements, sizeof(struct HIDGamepadButton) * (deviceRecord->numButtons + 1));
|
||||
hidDeviceRecord->buttonElements[deviceRecord->numButtons].cookie = IOHIDElementGetCookie(element);
|
||||
deviceRecord->numButtons++;
|
||||
}
|
||||
}
|
||||
CFRelease(elements);
|
||||
|
||||
deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes);
|
||||
deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons);
|
||||
|
||||
IOHIDDeviceRegisterInputValueCallback(device, onDeviceValueChanged, deviceRecord);
|
||||
|
||||
queuedEvent.deviceID = deviceRecord->deviceID;
|
||||
queuedEvent.eventType = GAMEPAD_EVENT_DEVICE_ATTACHED;
|
||||
queuedEvent.eventData = deviceRecord;
|
||||
|
||||
if (deviceEventCount >= deviceEventQueueSize) {
|
||||
deviceEventQueueSize = deviceEventQueueSize == 0 ? 1 : deviceEventQueueSize * 2;
|
||||
deviceEventQueue = realloc(deviceEventQueue, sizeof(struct Gamepad_queuedEvent) * deviceEventQueueSize);
|
||||
}
|
||||
deviceEventQueue[deviceEventCount++] = queuedEvent;
|
||||
}
|
||||
|
||||
static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
||||
unsigned int inputEventIndex, deviceEventIndex;
|
||||
|
||||
IOHIDDeviceRegisterInputValueCallback(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->deviceRef, NULL, NULL);
|
||||
|
||||
for (inputEventIndex = 0; inputEventIndex < inputEventCount; inputEventIndex++) {
|
||||
if (inputEventQueue[inputEventIndex].deviceID == deviceRecord->deviceID) {
|
||||
unsigned int inputEventIndex2;
|
||||
|
||||
free(inputEventQueue[inputEventIndex].eventData);
|
||||
inputEventCount--;
|
||||
for (inputEventIndex2 = inputEventIndex; inputEventIndex2 < inputEventCount; inputEventIndex2++) {
|
||||
inputEventQueue[inputEventIndex2] = inputEventQueue[inputEventIndex2 + 1];
|
||||
}
|
||||
inputEventIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
for (deviceEventIndex = 0; deviceEventIndex < deviceEventCount; deviceEventIndex++) {
|
||||
if (deviceEventQueue[deviceEventIndex].deviceID == deviceRecord->deviceID) {
|
||||
unsigned int deviceEventIndex2;
|
||||
|
||||
deviceEventCount--;
|
||||
for (deviceEventIndex2 = deviceEventIndex; deviceEventIndex2 < deviceEventCount; deviceEventIndex2++) {
|
||||
deviceEventQueue[deviceEventIndex2] = deviceEventQueue[deviceEventIndex2 + 1];
|
||||
}
|
||||
deviceEventIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->axisElements);
|
||||
free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->buttonElements);
|
||||
free(deviceRecord->privateData);
|
||||
|
||||
free((void *) deviceRecord->description);
|
||||
free(deviceRecord->axisStates);
|
||||
free(deviceRecord->buttonStates);
|
||||
|
||||
free(deviceRecord);
|
||||
}
|
||||
|
||||
static void onDeviceRemoved(void * context, IOReturn result, void * sender, IOHIDDeviceRef device) {
|
||||
unsigned int deviceIndex;
|
||||
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
if (((struct Gamepad_devicePrivate *) devices[deviceIndex]->privateData)->deviceRef == device) {
|
||||
if (Gamepad_deviceRemoveCallback != NULL) {
|
||||
Gamepad_deviceRemoveCallback(devices[deviceIndex], Gamepad_deviceRemoveContext);
|
||||
}
|
||||
|
||||
disposeDevice(devices[deviceIndex]);
|
||||
numDevices--;
|
||||
for (; deviceIndex < numDevices; deviceIndex++) {
|
||||
devices[deviceIndex] = devices[deviceIndex + 1];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Gamepad_init() {
|
||||
if (hidManager == NULL) {
|
||||
CFStringRef keys[2];
|
||||
int value;
|
||||
CFNumberRef values[2];
|
||||
CFDictionaryRef dictionaries[3];
|
||||
CFArrayRef array;
|
||||
|
||||
hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
||||
|
||||
keys[0] = CFSTR(kIOHIDDeviceUsagePageKey);
|
||||
keys[1] = CFSTR(kIOHIDDeviceUsageKey);
|
||||
|
||||
value = kHIDPage_GenericDesktop;
|
||||
values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
||||
value = kHIDUsage_GD_Joystick;
|
||||
values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
||||
dictionaries[0] = CFDictionaryCreate(kCFAllocatorDefault, (const void **) keys, (const void **) values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease(values[0]);
|
||||
CFRelease(values[1]);
|
||||
|
||||
value = kHIDPage_GenericDesktop;
|
||||
values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
||||
value = kHIDUsage_GD_GamePad;
|
||||
values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
||||
dictionaries[1] = CFDictionaryCreate(kCFAllocatorDefault, (const void **) keys, (const void **) values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease(values[0]);
|
||||
CFRelease(values[1]);
|
||||
|
||||
value = kHIDPage_GenericDesktop;
|
||||
values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
||||
value = kHIDUsage_GD_MultiAxisController;
|
||||
values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &value);
|
||||
dictionaries[2] = CFDictionaryCreate(kCFAllocatorDefault, (const void **) keys, (const void **) values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease(values[0]);
|
||||
CFRelease(values[1]);
|
||||
|
||||
array = CFArrayCreate(kCFAllocatorDefault, (const void **) dictionaries, 3, &kCFTypeArrayCallBacks);
|
||||
CFRelease(dictionaries[0]);
|
||||
CFRelease(dictionaries[1]);
|
||||
CFRelease(dictionaries[2]);
|
||||
IOHIDManagerSetDeviceMatchingMultiple(hidManager, array);
|
||||
CFRelease(array);
|
||||
|
||||
IOHIDManagerRegisterDeviceMatchingCallback(hidManager, onDeviceMatched, NULL);
|
||||
IOHIDManagerRegisterDeviceRemovalCallback(hidManager, onDeviceRemoved, NULL);
|
||||
|
||||
IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
|
||||
|
||||
// Force gamepads to be recognized immediately. The normal run loop mode takes a few frames,
|
||||
// but we can run one iteration with a custom mode to do it without a delay.
|
||||
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), GAMEPAD_RUN_LOOP_MODE);
|
||||
CFRunLoopRunInMode(GAMEPAD_RUN_LOOP_MODE, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Gamepad_shutdown() {
|
||||
if (hidManager != NULL) {
|
||||
unsigned int deviceIndex;
|
||||
|
||||
IOHIDManagerUnscheduleFromRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
disposeDevice(devices[deviceIndex]);
|
||||
}
|
||||
free(devices);
|
||||
devices = NULL;
|
||||
numDevices = 0;
|
||||
|
||||
IOHIDManagerClose(hidManager, 0);
|
||||
CFRelease(hidManager);
|
||||
hidManager = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Gamepad_numDevices() {
|
||||
return numDevices;
|
||||
}
|
||||
|
||||
struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex) {
|
||||
if (deviceIndex >= numDevices) {
|
||||
return NULL;
|
||||
}
|
||||
return devices[deviceIndex];
|
||||
}
|
||||
|
||||
static void processQueuedEvent(struct Gamepad_queuedEvent event) {
|
||||
switch (event.eventType) {
|
||||
case GAMEPAD_EVENT_DEVICE_ATTACHED:
|
||||
if (Gamepad_deviceAttachCallback != NULL) {
|
||||
Gamepad_deviceAttachCallback(event.eventData, Gamepad_deviceAttachContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAMEPAD_EVENT_DEVICE_REMOVED:
|
||||
if (Gamepad_deviceRemoveCallback != NULL) {
|
||||
Gamepad_deviceRemoveCallback(event.eventData, Gamepad_deviceRemoveContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAMEPAD_EVENT_BUTTON_DOWN:
|
||||
if (Gamepad_buttonDownCallback != NULL) {
|
||||
struct Gamepad_buttonEvent * buttonEvent = event.eventData;
|
||||
Gamepad_buttonDownCallback(buttonEvent->device, buttonEvent->buttonID, buttonEvent->timestamp, Gamepad_buttonDownContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAMEPAD_EVENT_BUTTON_UP:
|
||||
if (Gamepad_buttonUpCallback != NULL) {
|
||||
struct Gamepad_buttonEvent * buttonEvent = event.eventData;
|
||||
Gamepad_buttonUpCallback(buttonEvent->device, buttonEvent->buttonID, buttonEvent->timestamp, Gamepad_buttonUpContext);
|
||||
}
|
||||
break;
|
||||
|
||||
case GAMEPAD_EVENT_AXIS_MOVED:
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
struct Gamepad_axisEvent * axisEvent = event.eventData;
|
||||
Gamepad_axisMoveCallback(axisEvent->device, axisEvent->axisID, axisEvent->value, axisEvent->lastValue, axisEvent->timestamp, Gamepad_axisMoveContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Gamepad_detectDevices() {
|
||||
unsigned int eventIndex;
|
||||
|
||||
if (hidManager == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
CFRunLoopRunInMode(GAMEPAD_RUN_LOOP_MODE, 0, true);
|
||||
for (eventIndex = 0; eventIndex < deviceEventCount; eventIndex++) {
|
||||
processQueuedEvent(deviceEventQueue[eventIndex]);
|
||||
}
|
||||
deviceEventCount = 0;
|
||||
}
|
||||
|
||||
void Gamepad_processEvents() {
|
||||
unsigned int eventIndex;
|
||||
static bool inProcessEvents;
|
||||
|
||||
if (hidManager == NULL || inProcessEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
inProcessEvents = true;
|
||||
CFRunLoopRunInMode(GAMEPAD_RUN_LOOP_MODE, 0, true);
|
||||
for (eventIndex = 0; eventIndex < inputEventCount; eventIndex++) {
|
||||
processQueuedEvent(inputEventQueue[eventIndex]);
|
||||
free(inputEventQueue[eventIndex].eventData);
|
||||
}
|
||||
inputEventCount = 0;
|
||||
inProcessEvents = false;
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Alex Diener
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
void (* Gamepad_deviceAttachCallback)(struct Gamepad_device * device, void * context) = NULL;
|
||||
void (* Gamepad_deviceRemoveCallback)(struct Gamepad_device * device, void * context) = NULL;
|
||||
void (* Gamepad_buttonDownCallback)(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context) = NULL;
|
||||
void (* Gamepad_buttonUpCallback)(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context) = NULL;
|
||||
void (* Gamepad_axisMoveCallback)(struct Gamepad_device * device, unsigned int buttonID, float value, float lastValue, double timestamp, void * context) = NULL;
|
||||
void * Gamepad_deviceAttachContext = NULL;
|
||||
void * Gamepad_deviceRemoveContext = NULL;
|
||||
void * Gamepad_buttonDownContext = NULL;
|
||||
void * Gamepad_buttonUpContext = NULL;
|
||||
void * Gamepad_axisMoveContext = NULL;
|
||||
|
||||
void Gamepad_deviceAttachFunc(void (* callback)(struct Gamepad_device * device, void * context), void * context) {
|
||||
Gamepad_deviceAttachCallback = callback;
|
||||
Gamepad_deviceAttachContext = context;
|
||||
}
|
||||
|
||||
void Gamepad_deviceRemoveFunc(void (* callback)(struct Gamepad_device * device, void * context), void * context) {
|
||||
Gamepad_deviceRemoveCallback = callback;
|
||||
Gamepad_deviceRemoveContext = context;
|
||||
}
|
||||
|
||||
void Gamepad_buttonDownFunc(void (* callback)(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context), void * context) {
|
||||
Gamepad_buttonDownCallback = callback;
|
||||
Gamepad_buttonDownContext = context;
|
||||
}
|
||||
|
||||
void Gamepad_buttonUpFunc(void (* callback)(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context), void * context) {
|
||||
Gamepad_buttonUpCallback = callback;
|
||||
Gamepad_buttonUpContext = context;
|
||||
}
|
||||
|
||||
void Gamepad_axisMoveFunc(void (* callback)(struct Gamepad_device * device, unsigned int axisID, float value, float lastValue, double timestamp, void * context), void * context) {
|
||||
Gamepad_axisMoveCallback = callback;
|
||||
Gamepad_axisMoveContext = context;
|
||||
}
|
|
@ -1,400 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Alex Diener
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <regstr.h>
|
||||
|
||||
struct Gamepad_devicePrivate {
|
||||
UINT joystickID;
|
||||
JOYINFOEX lastState;
|
||||
int xAxisIndex;
|
||||
int yAxisIndex;
|
||||
int zAxisIndex;
|
||||
int rAxisIndex;
|
||||
int uAxisIndex;
|
||||
int vAxisIndex;
|
||||
int povXAxisIndex;
|
||||
int povYAxisIndex;
|
||||
UINT (* axisRanges)[2];
|
||||
};
|
||||
|
||||
static struct Gamepad_device ** devices = NULL;
|
||||
static unsigned int numDevices = 0;
|
||||
static unsigned int nextDeviceID = 0;
|
||||
|
||||
static bool inited = false;
|
||||
|
||||
void Gamepad_init() {
|
||||
if (!inited) {
|
||||
inited = true;
|
||||
Gamepad_detectDevices();
|
||||
}
|
||||
}
|
||||
|
||||
static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
||||
free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->axisRanges);
|
||||
free(deviceRecord->privateData);
|
||||
|
||||
free((void *) deviceRecord->description);
|
||||
free(deviceRecord->axisStates);
|
||||
free(deviceRecord->buttonStates);
|
||||
|
||||
free(deviceRecord);
|
||||
}
|
||||
|
||||
void Gamepad_shutdown() {
|
||||
unsigned int deviceIndex;
|
||||
|
||||
if (inited) {
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
disposeDevice(devices[deviceIndex]);
|
||||
}
|
||||
free(devices);
|
||||
devices = NULL;
|
||||
numDevices = 0;
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int Gamepad_numDevices() {
|
||||
return numDevices;
|
||||
}
|
||||
|
||||
struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex) {
|
||||
if (deviceIndex >= numDevices) {
|
||||
return NULL;
|
||||
}
|
||||
return devices[deviceIndex];
|
||||
}
|
||||
|
||||
#define REG_STRING_MAX 256
|
||||
|
||||
static char * getDeviceDescription(UINT joystickID, JOYCAPS caps) {
|
||||
char * description = NULL;
|
||||
char subkey[REG_STRING_MAX];
|
||||
HKEY topKey, key;
|
||||
LONG result;
|
||||
|
||||
snprintf(subkey, REG_STRING_MAX, "%s\\%s\\%s", REGSTR_PATH_JOYCONFIG, caps.szRegKey, REGSTR_KEY_JOYCURR);
|
||||
result = RegOpenKeyEx(topKey = HKEY_LOCAL_MACHINE, subkey, 0, KEY_READ, &key);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
result = RegOpenKeyEx(topKey = HKEY_CURRENT_USER, subkey, 0, KEY_READ, &key);
|
||||
}
|
||||
if (result == ERROR_SUCCESS) {
|
||||
char value[REG_STRING_MAX];
|
||||
char name[REG_STRING_MAX];
|
||||
DWORD nameSize;
|
||||
|
||||
snprintf(value, REG_STRING_MAX, "Joystick%d%s", joystickID + 1, REGSTR_VAL_JOYOEMNAME);
|
||||
nameSize = sizeof(name);
|
||||
result = RegQueryValueEx(key, value, NULL, NULL, (LPBYTE) name, &nameSize);
|
||||
RegCloseKey(key);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
snprintf(subkey, REG_STRING_MAX, "%s\\%s", REGSTR_PATH_JOYOEM, name);
|
||||
result = RegOpenKeyEx(topKey, subkey, 0, KEY_READ, &key);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
nameSize = sizeof(name);
|
||||
result = RegQueryValueEx(key, REGSTR_VAL_JOYOEMNAME, NULL, NULL, NULL, &nameSize);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
description = malloc(nameSize);
|
||||
result = RegQueryValueEx(key, REGSTR_VAL_JOYOEMNAME, NULL, NULL, (LPBYTE) description, &nameSize);
|
||||
}
|
||||
RegCloseKey(key);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
return description;
|
||||
}
|
||||
free(description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
description = malloc(strlen(caps.szPname) + 1);
|
||||
strcpy(description, caps.szPname);
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
void Gamepad_detectDevices() {
|
||||
unsigned int numPadsSupported;
|
||||
unsigned int deviceIndex, deviceIndex2;
|
||||
JOYINFOEX info;
|
||||
JOYCAPS caps;
|
||||
bool duplicate;
|
||||
struct Gamepad_device * deviceRecord;
|
||||
struct Gamepad_devicePrivate * deviceRecordPrivate;
|
||||
UINT joystickID;
|
||||
int axisIndex;
|
||||
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
numPadsSupported = joyGetNumDevs();
|
||||
for (deviceIndex = 0; deviceIndex < numPadsSupported; deviceIndex++) {
|
||||
info.dwSize = sizeof(info);
|
||||
info.dwFlags = JOY_RETURNALL;
|
||||
joystickID = JOYSTICKID1 + deviceIndex;
|
||||
if (joyGetPosEx(joystickID, &info) == JOYERR_NOERROR &&
|
||||
joyGetDevCaps(joystickID, &caps, sizeof(JOYCAPS)) == JOYERR_NOERROR) {
|
||||
|
||||
duplicate = false;
|
||||
for (deviceIndex2 = 0; deviceIndex2 < numDevices; deviceIndex2++) {
|
||||
if (((struct Gamepad_devicePrivate *) devices[deviceIndex2]->privateData)->joystickID == joystickID) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
deviceRecord = malloc(sizeof(struct Gamepad_device));
|
||||
deviceRecord->deviceID = nextDeviceID++;
|
||||
deviceRecord->description = getDeviceDescription(joystickID, caps);
|
||||
deviceRecord->vendorID = caps.wMid;
|
||||
deviceRecord->productID = caps.wPid;
|
||||
deviceRecord->numAxes = caps.wNumAxes + ((caps.wCaps & JOYCAPS_HASPOV) ? 2 : 0);
|
||||
deviceRecord->numButtons = caps.wNumButtons;
|
||||
deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes);
|
||||
deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons);
|
||||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
deviceRecordPrivate = malloc(sizeof(struct Gamepad_devicePrivate));
|
||||
deviceRecordPrivate->joystickID = joystickID;
|
||||
deviceRecordPrivate->lastState = info;
|
||||
|
||||
deviceRecordPrivate->xAxisIndex = 0;
|
||||
deviceRecordPrivate->yAxisIndex = 1;
|
||||
axisIndex = 2;
|
||||
deviceRecordPrivate->zAxisIndex = (caps.wCaps & JOYCAPS_HASZ) ? axisIndex++ : -1;
|
||||
deviceRecordPrivate->rAxisIndex = (caps.wCaps & JOYCAPS_HASR) ? axisIndex++ : -1;
|
||||
deviceRecordPrivate->uAxisIndex = (caps.wCaps & JOYCAPS_HASU) ? axisIndex++ : -1;
|
||||
deviceRecordPrivate->vAxisIndex = (caps.wCaps & JOYCAPS_HASV) ? axisIndex++ : -1;
|
||||
|
||||
deviceRecordPrivate->axisRanges = malloc(sizeof(UINT[2]) * axisIndex);
|
||||
deviceRecordPrivate->axisRanges[0][0] = caps.wXmin;
|
||||
deviceRecordPrivate->axisRanges[0][1] = caps.wXmax;
|
||||
deviceRecordPrivate->axisRanges[1][0] = caps.wYmin;
|
||||
deviceRecordPrivate->axisRanges[1][1] = caps.wYmax;
|
||||
if (deviceRecordPrivate->zAxisIndex != -1) {
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->zAxisIndex][0] = caps.wZmin;
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->zAxisIndex][1] = caps.wZmax;
|
||||
}
|
||||
if (deviceRecordPrivate->rAxisIndex != -1) {
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->rAxisIndex][0] = caps.wRmin;
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->rAxisIndex][1] = caps.wRmax;
|
||||
}
|
||||
if (deviceRecordPrivate->uAxisIndex != -1) {
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->uAxisIndex][0] = caps.wUmin;
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->uAxisIndex][1] = caps.wUmax;
|
||||
}
|
||||
if (deviceRecordPrivate->vAxisIndex != -1) {
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->vAxisIndex][0] = caps.wVmin;
|
||||
deviceRecordPrivate->axisRanges[deviceRecordPrivate->vAxisIndex][1] = caps.wVmax;
|
||||
}
|
||||
|
||||
deviceRecordPrivate->povXAxisIndex = (caps.wCaps & JOYCAPS_HASPOV) ? axisIndex++ : -1;
|
||||
deviceRecordPrivate->povYAxisIndex = (caps.wCaps & JOYCAPS_HASPOV) ? axisIndex++ : -1;
|
||||
|
||||
deviceRecord->privateData = deviceRecordPrivate;
|
||||
|
||||
if (Gamepad_deviceAttachCallback != NULL) {
|
||||
Gamepad_deviceAttachCallback(deviceRecord, Gamepad_deviceAttachContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static double currentTime() {
|
||||
// HACK: No timestamp data from joyGetInfoEx, so we make it up
|
||||
static LARGE_INTEGER frequency;
|
||||
LARGE_INTEGER currentTime;
|
||||
|
||||
if (frequency.QuadPart == 0) {
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
}
|
||||
QueryPerformanceCounter(¤tTime);
|
||||
|
||||
return (double) currentTime.QuadPart / frequency.QuadPart;
|
||||
}
|
||||
|
||||
static void handleAxisChange(struct Gamepad_device * device, int axisIndex, DWORD ivalue) {
|
||||
float value, lastValue;
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
|
||||
if (axisIndex < 0 || axisIndex >= (int) device->numAxes) {
|
||||
return;
|
||||
}
|
||||
|
||||
devicePrivate = device->privateData;
|
||||
value = (ivalue - devicePrivate->axisRanges[axisIndex][0]) / (float) (devicePrivate->axisRanges[axisIndex][1] - devicePrivate->axisRanges[axisIndex][0]) * 2.0f - 1.0f;
|
||||
|
||||
lastValue = device->axisStates[axisIndex];
|
||||
device->axisStates[axisIndex] = value;
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
Gamepad_axisMoveCallback(device, axisIndex, value, lastValue, currentTime(), Gamepad_axisMoveContext);
|
||||
}
|
||||
}
|
||||
|
||||
static void handleButtonChange(struct Gamepad_device * device, DWORD lastValue, DWORD value) {
|
||||
bool down;
|
||||
unsigned int buttonIndex;
|
||||
|
||||
for (buttonIndex = 0; buttonIndex < device->numButtons; buttonIndex++) {
|
||||
if ((lastValue ^ value) & (1 << buttonIndex)) {
|
||||
down = !!(value & (1 << buttonIndex));
|
||||
|
||||
device->buttonStates[buttonIndex] = down;
|
||||
if (down && Gamepad_buttonDownCallback != NULL) {
|
||||
Gamepad_buttonDownCallback(device, buttonIndex, currentTime(), Gamepad_buttonDownContext);
|
||||
} else if (!down && Gamepad_buttonUpCallback != NULL) {
|
||||
Gamepad_buttonUpCallback(device, buttonIndex, currentTime(), Gamepad_buttonUpContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void povToXY(DWORD pov, int * outX, int * outY) {
|
||||
if (pov == JOY_POVCENTERED) {
|
||||
*outX = *outY = 0;
|
||||
|
||||
} else {
|
||||
if (pov > JOY_POVFORWARD && pov < JOY_POVBACKWARD) {
|
||||
*outX = 1;
|
||||
|
||||
} else if (pov > JOY_POVBACKWARD) {
|
||||
*outX = -1;
|
||||
|
||||
} else {
|
||||
*outX = 0;
|
||||
}
|
||||
|
||||
if (pov > JOY_POVLEFT || pov < JOY_POVRIGHT) {
|
||||
*outY = -1;
|
||||
|
||||
} else if (pov > JOY_POVRIGHT && pov < JOY_POVLEFT) {
|
||||
*outY = 1;
|
||||
|
||||
} else {
|
||||
*outY = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void handlePOVChange(struct Gamepad_device * device, DWORD lastValue, DWORD value) {
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
int lastX, lastY, newX, newY;
|
||||
|
||||
devicePrivate = device->privateData;
|
||||
|
||||
if (devicePrivate->povXAxisIndex == -1 || devicePrivate->povYAxisIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
povToXY(lastValue, &lastX, &lastY);
|
||||
povToXY(value, &newX, &newY);
|
||||
|
||||
if (newX != lastX) {
|
||||
device->axisStates[devicePrivate->povXAxisIndex] = newX;
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
Gamepad_axisMoveCallback(device, devicePrivate->povXAxisIndex, newX, lastX, currentTime(), Gamepad_axisMoveContext);
|
||||
}
|
||||
}
|
||||
if (newY != lastY) {
|
||||
device->axisStates[devicePrivate->povYAxisIndex] = newY;
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
Gamepad_axisMoveCallback(device, devicePrivate->povYAxisIndex, newY, lastY, currentTime(), Gamepad_axisMoveContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Gamepad_processEvents() {
|
||||
unsigned int deviceIndex;
|
||||
static bool inProcessEvents;
|
||||
JOYINFOEX info;
|
||||
MMRESULT result;
|
||||
struct Gamepad_device * device;
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
|
||||
if (!inited || inProcessEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
inProcessEvents = true;
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
device = devices[deviceIndex];
|
||||
devicePrivate = device->privateData;
|
||||
|
||||
info.dwSize = sizeof(info);
|
||||
info.dwFlags = JOY_RETURNALL;
|
||||
result = joyGetPosEx(devicePrivate->joystickID, &info);
|
||||
if (result == JOYERR_UNPLUGGED) {
|
||||
if (Gamepad_deviceRemoveCallback != NULL) {
|
||||
Gamepad_deviceRemoveCallback(device, Gamepad_deviceRemoveContext);
|
||||
}
|
||||
|
||||
disposeDevice(device);
|
||||
numDevices--;
|
||||
for (; deviceIndex < numDevices; deviceIndex++) {
|
||||
devices[deviceIndex] = devices[deviceIndex + 1];
|
||||
}
|
||||
|
||||
} else if (result == JOYERR_NOERROR) {
|
||||
if (info.dwXpos != devicePrivate->lastState.dwXpos) {
|
||||
handleAxisChange(device, devicePrivate->xAxisIndex, info.dwXpos);
|
||||
}
|
||||
if (info.dwYpos != devicePrivate->lastState.dwYpos) {
|
||||
handleAxisChange(device, devicePrivate->yAxisIndex, info.dwYpos);
|
||||
}
|
||||
if (info.dwZpos != devicePrivate->lastState.dwZpos) {
|
||||
handleAxisChange(device, devicePrivate->zAxisIndex, info.dwZpos);
|
||||
}
|
||||
if (info.dwRpos != devicePrivate->lastState.dwRpos) {
|
||||
handleAxisChange(device, devicePrivate->rAxisIndex, info.dwRpos);
|
||||
}
|
||||
if (info.dwUpos != devicePrivate->lastState.dwUpos) {
|
||||
handleAxisChange(device, devicePrivate->uAxisIndex, info.dwUpos);
|
||||
}
|
||||
if (info.dwVpos != devicePrivate->lastState.dwVpos) {
|
||||
handleAxisChange(device, devicePrivate->vAxisIndex, info.dwVpos);
|
||||
}
|
||||
if (info.dwPOV != devicePrivate->lastState.dwPOV) {
|
||||
handlePOVChange(device, devicePrivate->lastState.dwPOV, info.dwPOV);
|
||||
}
|
||||
if (info.dwButtons != devicePrivate->lastState.dwButtons) {
|
||||
handleButtonChange(device, devicePrivate->lastState.dwButtons, info.dwButtons);
|
||||
}
|
||||
devicePrivate->lastState = info;
|
||||
}
|
||||
}
|
||||
inProcessEvents = false;
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Alex Diener
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#ifndef __GAMEPAD_H__
|
||||
#define __GAMEPAD_H__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct Gamepad_device {
|
||||
// Unique device identifier for application session, starting at 0 for the first device attached and
|
||||
// incrementing by 1 for each additional device. If a device is removed and subsequently reattached
|
||||
// during the same application session, it will have a new deviceID.
|
||||
unsigned int deviceID;
|
||||
|
||||
// Human-readable device name
|
||||
const char * description;
|
||||
|
||||
// USB vendor/product IDs as returned by the driver. Can be used to determine the particular model of device represented.
|
||||
int vendorID;
|
||||
int productID;
|
||||
|
||||
// Number of axis elements belonging to the device
|
||||
unsigned int numAxes;
|
||||
|
||||
// Number of button elements belonging to the device
|
||||
unsigned int numButtons;
|
||||
|
||||
// Array[numAxes] of values representing the current state of each axis, in the range [-1..1]
|
||||
float * axisStates;
|
||||
|
||||
// Array[numButtons] of values representing the current state of each button
|
||||
bool * buttonStates;
|
||||
|
||||
// Platform-specific device data storage. Don't touch unless you know what you're doing and don't
|
||||
// mind your code breaking in future versions of this library.
|
||||
void * privateData;
|
||||
};
|
||||
|
||||
/* Initializes gamepad library and detects initial devices. Call this before any other Gamepad_*()
|
||||
function, other than callback registration functions. If you want to receive deviceAttachFunc
|
||||
callbacks from devices detected in Gamepad_init(), you must call Gamepad_deviceAttachFunc()
|
||||
before calling Gamepad_init().
|
||||
|
||||
This function must be called from the same thread that will be calling Gamepad_processEvents()
|
||||
and Gamepad_detectDevices(). */
|
||||
void Gamepad_init();
|
||||
|
||||
/* Tears down all data structures created by the gamepad library and releases any memory that was
|
||||
allocated. It is not necessary to call this function at application termination, but it's
|
||||
provided in case you want to free memory associated with gamepads at some earlier time. */
|
||||
void Gamepad_shutdown();
|
||||
|
||||
/* Returns the number of currently attached gamepad devices. */
|
||||
unsigned int Gamepad_numDevices();
|
||||
|
||||
/* Returns the specified Gamepad_device struct, or NULL if deviceIndex is out of bounds. */
|
||||
struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex);
|
||||
|
||||
/* Polls for any devices that have been attached since the last call to Gamepad_detectDevices() or
|
||||
Gamepad_init(). If any new devices are found, the callback registered with
|
||||
Gamepad_deviceAttachFunc() (if any) will be called once per newly detected device.
|
||||
|
||||
Note that depending on implementation, you may receive button and axis event callbacks for
|
||||
devices that have not yet been detected with Gamepad_detectDevices(). You can safely ignore
|
||||
these events, but be aware that your callbacks might receive a device ID that hasn't been seen
|
||||
by your deviceAttachFunc. */
|
||||
void Gamepad_detectDevices();
|
||||
|
||||
/* Reads pending input from all attached devices and calls the appropriate input callbacks, if any
|
||||
have been registered. */
|
||||
void Gamepad_processEvents();
|
||||
|
||||
/* Registers a function to be called whenever a device is attached. The specified function will be
|
||||
called only during calls to Gamepad_init() and Gamepad_detectDevices(), in the thread from
|
||||
which those functions were called. Calling this function with a NULL argument will stop any
|
||||
previously registered callback from being called subsequently. */
|
||||
void Gamepad_deviceAttachFunc(void (* callback)(struct Gamepad_device * device, void * context), void * context);
|
||||
|
||||
/* Registers a function to be called whenever a device is detached. The specified function can be
|
||||
called at any time, and will not necessarily be called from the main thread. Calling this
|
||||
function with a NULL argument will stop any previously registered callback from being called
|
||||
subsequently. */
|
||||
void Gamepad_deviceRemoveFunc(void (* callback)(struct Gamepad_device * device, void * context), void * context);
|
||||
|
||||
/* Registers a function to be called whenever a button on any attached device is pressed. The
|
||||
specified function will be called only during calls to Gamepad_processEvents(), in the
|
||||
thread from which Gamepad_processEvents() was called. Calling this function with a NULL
|
||||
argument will stop any previously registered callback from being called subsequently. */
|
||||
void Gamepad_buttonDownFunc(void (* callback)(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context), void * context);
|
||||
|
||||
/* Registers a function to be called whenever a button on any attached device is released. The
|
||||
specified function will be called only during calls to Gamepad_processEvents(), in the
|
||||
thread from which Gamepad_processEvents() was called. Calling this function with a NULL
|
||||
argument will stop any previously registered callback from being called subsequently. */
|
||||
void Gamepad_buttonUpFunc(void (* callback)(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context), void * context);
|
||||
|
||||
/* Registers a function to be called whenever an axis on any attached device is moved. The
|
||||
specified function will be called only during calls to Gamepad_processEvents(), in the
|
||||
thread from which Gamepad_processEvents() was called. Calling this function with a NULL
|
||||
argument will stop any previously registered callback from being called subsequently. */
|
||||
void Gamepad_axisMoveFunc(void (* callback)(struct Gamepad_device * device, unsigned int axisID, float value, float lastValue, double timestamp, void * context), void * context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Alex Diener
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#ifndef __GAMEPAD_PRIVATE_H__
|
||||
#define __GAMEPAD_PRIVATE_H__
|
||||
|
||||
enum Gamepad_eventType {
|
||||
GAMEPAD_EVENT_DEVICE_ATTACHED,
|
||||
GAMEPAD_EVENT_DEVICE_REMOVED,
|
||||
GAMEPAD_EVENT_BUTTON_DOWN,
|
||||
GAMEPAD_EVENT_BUTTON_UP,
|
||||
GAMEPAD_EVENT_AXIS_MOVED
|
||||
};
|
||||
|
||||
struct Gamepad_buttonEvent {
|
||||
// Device that generated the event
|
||||
struct Gamepad_device * device;
|
||||
|
||||
// Relative time of the event, in seconds
|
||||
double timestamp;
|
||||
|
||||
// Button being pushed or released
|
||||
unsigned int buttonID;
|
||||
|
||||
// True if button is down
|
||||
bool down;
|
||||
};
|
||||
|
||||
struct Gamepad_axisEvent {
|
||||
// Device that generated the event
|
||||
struct Gamepad_device * device;
|
||||
|
||||
// Relative time of the event, in seconds
|
||||
double timestamp;
|
||||
|
||||
// Axis being moved
|
||||
unsigned int axisID;
|
||||
|
||||
// Axis position value, in the range [-1..1]
|
||||
float value;
|
||||
|
||||
// Previous axis position value, in the range [-1..1]
|
||||
float lastValue;
|
||||
};
|
||||
|
||||
extern void (* Gamepad_deviceAttachCallback)(struct Gamepad_device * device, void * context);
|
||||
extern void (* Gamepad_deviceRemoveCallback)(struct Gamepad_device * device, void * context);
|
||||
extern void (* Gamepad_buttonDownCallback)(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context);
|
||||
extern void (* Gamepad_buttonUpCallback)(struct Gamepad_device * device, unsigned int buttonID, double timestamp, void * context);
|
||||
extern void (* Gamepad_axisMoveCallback)(struct Gamepad_device * device, unsigned int axisID, float value, float lastValue, double timestamp, void * context);
|
||||
extern void * Gamepad_deviceAttachContext;
|
||||
extern void * Gamepad_deviceRemoveContext;
|
||||
extern void * Gamepad_buttonDownContext;
|
||||
extern void * Gamepad_buttonUpContext;
|
||||
extern void * Gamepad_axisMoveContext;
|
||||
|
||||
#endif
|
|
@ -1,3 +1,6 @@
|
|||
--------------------------------------------------------------------------------
|
||||
License of libstem Gamepad:
|
||||
|
||||
Copyright (c) 2014 Alex Diener
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
|
@ -16,4 +19,4 @@ freely, subject to the following restrictions:
|
|||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener alex@ludobloom.com
|
||||
Alex Diener alex@ludobloom.com
|
Loading…
Reference in a new issue