mirror of
https://github.com/QB64Official/qb64.git
synced 2024-07-03 07:41:21 +00:00
Primarily implements gamepad support (via _DEVICES, STICK/STRIG)
Corrects dependency detection bug in prev update which rendered _SCREENIMAGE unusable Implements new command _FPS which limits the maximum hardware fps (primarily for throttling SUB _GL) [default is 60] Usage example: _FPS 100
This commit is contained in:
parent
e86f50a3cf
commit
3928325615
|
@ -385,9 +385,10 @@ struct device_struct{
|
|||
int32 used;
|
||||
int32 type;
|
||||
//0=Unallocated
|
||||
//1=SDL joystick interface
|
||||
//2=?
|
||||
qbs *name;
|
||||
//1=Joystick/Gamepad
|
||||
//2=Keybaord
|
||||
//3=Mouse
|
||||
char *name;
|
||||
int32 connected;
|
||||
int32 lastbutton;
|
||||
int32 lastaxis;
|
||||
|
@ -400,13 +401,15 @@ struct device_struct{
|
|||
//--------------
|
||||
uint8 STRIG_button_pressed[256];//checked and cleared by the STRIG function
|
||||
//--------------
|
||||
uint8 id[1024];
|
||||
/////SDL_Joystick *SDL_js;
|
||||
int32 SDL_js_index;
|
||||
int32 SDL_buttons;
|
||||
int32 SDL_axes;
|
||||
int32 SDL_balls;
|
||||
int32 SDL_hats;
|
||||
void *handle_pointer;//handle as pointer
|
||||
int64 handle_int;//handle as integer
|
||||
char *description;//description provided by manufacturer
|
||||
int64 product_id;
|
||||
int64 vendor_id;
|
||||
int32 buttons;
|
||||
int32 axes;
|
||||
int32 balls;
|
||||
int32 hats;
|
||||
};
|
||||
#define QUEUED_EVENTS_LIMIT 1024
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <X11/Xutil.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "libqb/printer.h"
|
||||
|
||||
void alert(int32 x);
|
||||
|
@ -81,6 +82,8 @@ int32 window_exists=0;
|
|||
int32 create_window=0;
|
||||
uint8 *window_title=NULL;
|
||||
|
||||
double max_fps=60;//60 is the default
|
||||
int32 auto_fps=0;//set to 1 to make QB64 auto-adjust fps based on load
|
||||
|
||||
int32 os_resize_event=0;
|
||||
|
||||
|
@ -111,17 +114,24 @@ int32 sub_gl_called=0;
|
|||
|
||||
extern void evnt(uint32 linenumber);
|
||||
|
||||
extern "C" int qb64_custom_event(int event,int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,void *p1,void *p2);
|
||||
#ifdef QB64_WINDOWS
|
||||
extern "C" LRESULT qb64_os_event_windows(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, int *qb64_os_event_info);
|
||||
#endif
|
||||
|
||||
#ifdef QB64_LINUX
|
||||
#ifdef QB64_GUI //Cannot have X11 events without a GUI
|
||||
#ifndef QB64_MACOSX
|
||||
extern "C" void qb64_os_event_linux(XEvent *event, int *qb64_os_event_info);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
extern "C" int QB64_Custom_Event(int event,int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,void *p1,void *p2);
|
||||
#define QB64_EVENT_CLOSE 1
|
||||
#define QB64_EVENT_KEY 2
|
||||
#define QB64_EVENT_RELATIVE_MOUSE_MOVEMENT 3
|
||||
#define QB64_EVENT_KEY_PAUSE 1000
|
||||
|
||||
|
||||
|
||||
static int32 image_qbicon16_handle;
|
||||
static int32 image_qbicon32_handle;
|
||||
|
||||
|
@ -198,7 +208,7 @@ int32 dont_call_sub_gl=0;
|
|||
|
||||
void GLUT_DISPLAY_REQUEST();
|
||||
|
||||
void timerCB(int millisec)
|
||||
void timerCB(int millisec)//not currently being used
|
||||
{
|
||||
#ifdef QB64_GLUT
|
||||
glutPostRedisplay();
|
||||
|
@ -1060,9 +1070,23 @@ void key_update();
|
|||
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 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;
|
||||
//...
|
||||
|
@ -6792,7 +6816,7 @@ uint32 qb64_firsttimervalue;//based on time of day
|
|||
uint32 clock_firsttimervalue;//based on program launch time
|
||||
|
||||
|
||||
extern uint32 qbevent;
|
||||
|
||||
|
||||
uint8 wait_needed=1;
|
||||
|
||||
|
@ -14087,6 +14111,22 @@ void sub__delay(double seconds){
|
|||
}
|
||||
}
|
||||
|
||||
void sub__fps(double fps, int32 passed){
|
||||
//passed=1 means _AUTO
|
||||
//passed=2 means use fps
|
||||
if (new_error) return;
|
||||
if (passed!=1 && passed!=2){error(5); return;}
|
||||
if (passed==1){
|
||||
auto_fps=1;//_AUTO
|
||||
}
|
||||
if (passed==2){
|
||||
if (fps<1){error(5); return;}
|
||||
if (fps>200) fps=200;
|
||||
max_fps=fps;
|
||||
auto_fps=0;
|
||||
}
|
||||
}
|
||||
|
||||
void sub__limit(double fps){
|
||||
if (new_error) return;
|
||||
static double prev=0;
|
||||
|
@ -21786,12 +21826,6 @@ int32 func__printwidth(qbs* text, int32 screenhandle, int32 passed){
|
|||
return start;
|
||||
}
|
||||
|
||||
extern ontimer_struct *ontimer;
|
||||
extern onkey_struct *onkey;
|
||||
extern int32 onkey_inprogress;
|
||||
extern onstrig_struct *onstrig;
|
||||
extern int32 onstrig_inprogress;
|
||||
|
||||
void sub_run_init(){
|
||||
//Reset ON KEY trapping
|
||||
//note: KEY bar F-key bindings are not affected
|
||||
|
@ -28442,14 +28476,18 @@ void sub__maptriangle(int32 cull_options,float sx1,float sy1,float sx2,float sy2
|
|||
void GLUT_TIMER_EVENT(int ignore){
|
||||
#ifdef QB64_GLUT
|
||||
glutPostRedisplay();
|
||||
glutTimerFunc(8,GLUT_TIMER_EVENT,0);
|
||||
int32 msdelay=1000.0/max_fps;
|
||||
if (msdelay<1) msdelay=1;
|
||||
glutTimerFunc(msdelay,GLUT_TIMER_EVENT,0);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void GLUT_IDLEFUNC(){
|
||||
#ifdef QB64_GLUT
|
||||
glutPostRedisplay();
|
||||
Sleep(8);//<=125hz
|
||||
int32 msdelay=1000.0/max_fps;
|
||||
if (msdelay<1) msdelay=1;
|
||||
Sleep(msdelay);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -28536,7 +28574,6 @@ void sub__maptriangle(int32 cull_options,float sx1,float sy1,float sx2,float sy2
|
|||
|
||||
|
||||
|
||||
|
||||
/********** Render State **********/
|
||||
render_state.dest=NULL;
|
||||
render_state.source=NULL;
|
||||
|
@ -29182,6 +29219,46 @@ render_state.cull_mode=CULL_MODE__UNKNOWN;
|
|||
|
||||
|
||||
|
||||
|
||||
//Init _DEVICEs
|
||||
i=1;
|
||||
//keyboard
|
||||
devices[i].type=2;
|
||||
devices[i].name="[KEYBOARD][BUTTON]";
|
||||
devices[i].lastbutton=512;
|
||||
//calculate queue message size
|
||||
x=512+8;
|
||||
devices[i].event_size=x;
|
||||
//create initial 'current' and 'previous' events
|
||||
devices[i].events=(uint8*)calloc(2,x);
|
||||
devices[i].max_events=2;
|
||||
devices[i].queued_events=2;
|
||||
devices[i].connected=1;
|
||||
devices[i].used=1;
|
||||
devices[i].description="Keyboard";
|
||||
i++;
|
||||
//mouse
|
||||
devices[i].type=3;
|
||||
devices[i].name="[MOUSE][BUTTON][AXIS][WHEEL]";
|
||||
devices[i].lastbutton=3;
|
||||
devices[i].lastaxis=2;
|
||||
devices[i].lastwheel=3;
|
||||
//calculate queue message size
|
||||
x=devices[i].lastbutton+devices[i].lastaxis*4+devices[i].lastwheel*4+8;
|
||||
devices[i].event_size=x;
|
||||
//create initial 'current' and 'previous' events
|
||||
devices[i].events=(uint8*)calloc(2,x);
|
||||
devices[i].max_events=2;
|
||||
devices[i].queued_events=2;
|
||||
devices[i].connected=1;
|
||||
devices[i].used=1;
|
||||
devices[i].description="Mouse";
|
||||
device_last=i;
|
||||
|
||||
#ifdef DEPENDENCY_DEVICEINPUT
|
||||
QB64_GAMEPAD_INIT();
|
||||
#endif
|
||||
|
||||
#ifdef QB64_WINDOWS
|
||||
_beginthread(QBMAIN_WINDOWS,0,NULL);
|
||||
#else
|
||||
|
@ -29333,8 +29410,10 @@ render_state.cull_mode=CULL_MODE__UNKNOWN;
|
|||
int32 update=0;//0=update input,1=update display
|
||||
|
||||
main_loop:
|
||||
|
||||
|
||||
|
||||
#ifdef DEPENDENCY_DEVICEINPUT
|
||||
QB64_GAMEPAD_POLL();
|
||||
#endif
|
||||
|
||||
if (lock_mainloop==1){
|
||||
lock_mainloop=2;
|
||||
|
@ -30618,28 +30697,29 @@ render_state.cull_mode=CULL_MODE__UNKNOWN;
|
|||
//NO_S_D_L//SDL_WaitThread(thread, NULL);
|
||||
#endif
|
||||
while (exit_ok!=3) Sleep(16);
|
||||
|
||||
if (lprint_buffered){
|
||||
sub__printimage(lprint_image);//print any pending content
|
||||
}
|
||||
|
||||
//close all open files
|
||||
sub_close(NULL,0);
|
||||
|
||||
|
||||
//NO_S_D_L//SDL_ShowCursor(0);
|
||||
//NO_S_D_L//SDL_FreeCursor(mycursor);
|
||||
//shutdown device interface
|
||||
#ifdef DEPENDENCY_DEVICEINPUT
|
||||
QB64_GAMEPAD_SHUTDOWN();
|
||||
#endif
|
||||
|
||||
if (!cloud_app){
|
||||
snd_un_init();
|
||||
|
||||
//program ends here
|
||||
}
|
||||
|
||||
if (cloud_app){
|
||||
FILE *f = fopen("..\\final.txt", "w");
|
||||
if (f != NULL)
|
||||
{
|
||||
fprintf(f, "Program exited normally");
|
||||
fclose(f);
|
||||
}
|
||||
if (f != NULL){
|
||||
fprintf(f, "Program exited normally");
|
||||
fclose(f);
|
||||
}
|
||||
exit(0);//should log error
|
||||
}
|
||||
|
||||
|
@ -32413,9 +32493,153 @@ render_state.cull_mode=CULL_MODE__UNKNOWN;
|
|||
port60h_events++;
|
||||
}
|
||||
|
||||
#define OS_EVENT_PRE_PROCESSING 1
|
||||
#define OS_EVENT_POST_PROCESSING 2
|
||||
#define OS_EVENT_RETURN_IMMEDIATELY 3
|
||||
|
||||
#ifdef QB64_WINDOWS
|
||||
extern "C" LRESULT qb64_os_event_windows(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, int *qb64_os_event_info){
|
||||
if (*qb64_os_event_info==OS_EVENT_PRE_PROCESSING){
|
||||
//example usage
|
||||
/*
|
||||
if (uMsg==WM_CLOSE){
|
||||
alert("goodbye");
|
||||
*qb64_os_event_info=OS_EVENT_RETURN_IMMEDIATELY;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
extern "C" int QB64_Custom_Event(int event,int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,void *p1,void *p2){
|
||||
if (uMsg==WM_KEYDOWN){
|
||||
|
||||
if (device_last){//core devices required?
|
||||
|
||||
/*
|
||||
16-23 The scan code. The value depends on the OEM.
|
||||
24 Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
|
||||
*/
|
||||
|
||||
static int32 code,special;
|
||||
special=0;//set to 2 for keys which we cannot detect a release for
|
||||
code=(lParam>>16)&511;
|
||||
|
||||
keydown_special:
|
||||
static device_struct *d;
|
||||
d=&devices[1];//keyboard
|
||||
if (*(d->events+((d->queued_events-1)*d->event_size)+code)!=1){//don't add message if already on
|
||||
uint8 *cp,*cp2;
|
||||
if (d->queued_events==d->max_events){//expand/shift event buffer
|
||||
if (d->max_events>=(QUEUED_EVENTS_LIMIT/4)){//note: default event limit divied by 4
|
||||
//discard base message
|
||||
memmove(d->events,d->events+d->event_size,(d->queued_events-1)*d->event_size);
|
||||
d->queued_events--;
|
||||
}else{
|
||||
cp=(uint8*)calloc(d->max_events*2,d->event_size);
|
||||
memcpy(cp,d->events,d->queued_events*d->event_size);//copy existing events
|
||||
cp2=d->events;
|
||||
d->events=cp;
|
||||
free(cp2);
|
||||
d->max_events*=2;
|
||||
}
|
||||
}
|
||||
memmove(d->events+d->queued_events*d->event_size,d->events+(d->queued_events-1)*d->event_size,d->event_size);//duplicate last event
|
||||
*(int64*)(d->events+(d->queued_events*d->event_size)+(d->event_size-8))=device_event_index++;//store global event index
|
||||
//make required changes
|
||||
*(d->events+(d->queued_events*d->event_size)+code)=1;
|
||||
if (special==2){special=1; d->queued_events++; goto keydown_special;}
|
||||
if (special==1) *(d->events+(d->queued_events*d->event_size)+code)=0;
|
||||
d->queued_events++;
|
||||
}//not 1
|
||||
}//core devices required
|
||||
|
||||
}//WM_KEYDOWN
|
||||
|
||||
|
||||
if (uMsg==WM_KEYUP){
|
||||
|
||||
if (device_last){//core devices required?
|
||||
|
||||
/*
|
||||
16-23 The scan code. The value depends on the OEM.
|
||||
24 Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
|
||||
*/
|
||||
|
||||
static int32 code;
|
||||
|
||||
code=(lParam>>16)&511;
|
||||
|
||||
static device_struct *d;
|
||||
d=&devices[1];//keyboard
|
||||
if (*(d->events+((d->queued_events-1)*d->event_size)+code)!=0){//don't add message if already on
|
||||
uint8 *cp,*cp2;
|
||||
if (d->queued_events==d->max_events){//expand/shift event buffer
|
||||
if (d->max_events>=(QUEUED_EVENTS_LIMIT/4)){//note: default event limit divied by 4
|
||||
//discard base message
|
||||
memmove(d->events,d->events+d->event_size,(d->queued_events-1)*d->event_size);
|
||||
d->queued_events--;
|
||||
}else{
|
||||
cp=(uint8*)calloc(d->max_events*2,d->event_size);
|
||||
memcpy(cp,d->events,d->queued_events*d->event_size);//copy existing events
|
||||
cp2=d->events;
|
||||
d->events=cp;
|
||||
free(cp2);
|
||||
d->max_events*=2;
|
||||
}
|
||||
}
|
||||
memmove(d->events+d->queued_events*d->event_size,d->events+(d->queued_events-1)*d->event_size,d->event_size);//duplicate last event
|
||||
*(int64*)(d->events+(d->queued_events*d->event_size)+(d->event_size-8))=device_event_index++;//store global event index
|
||||
//make required changes
|
||||
*(d->events+(d->queued_events*d->event_size)+code)=0;
|
||||
d->queued_events++;
|
||||
}//not 1
|
||||
}//core devices required
|
||||
|
||||
}//WM_KEYUP
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
if (*qb64_os_event_info==OS_EVENT_POST_PROCESSING){
|
||||
|
||||
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef QB64_LINUX
|
||||
#ifdef QB64_GUI //Cannot have X11 events without a GUI
|
||||
#ifndef QB64_MACOSX
|
||||
extern "C" void qb64_os_event_linux(XEvent *event, int *qb64_os_event_info){
|
||||
if (*qb64_os_event_info==OS_EVENT_PRE_PROCESSING){
|
||||
|
||||
|
||||
|
||||
}
|
||||
if (*qb64_os_event_info==OS_EVENT_POST_PROCESSING){
|
||||
|
||||
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern "C" int qb64_custom_event(int event,int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,void *p1,void *p2){
|
||||
if (event==QB64_EVENT_CLOSE){
|
||||
exit_value|=1;
|
||||
return NULL;
|
||||
|
@ -32432,7 +32656,7 @@ render_state.cull_mode=CULL_MODE__UNKNOWN;
|
|||
return -1;
|
||||
}//key
|
||||
|
||||
if (event==QB64_EVENT_RELATIVE_MOUSE_MOVEMENT){ //QB64_Custom_Event(QB64_EVENT_RELATIVE_MOUSE_MOVEMENT,xPosRelative,yPosRelative,0,0,0,0,0,0,NULL,NULL);
|
||||
if (event==QB64_EVENT_RELATIVE_MOUSE_MOVEMENT){ //qb64_custom_event(QB64_EVENT_RELATIVE_MOUSE_MOVEMENT,xPosRelative,yPosRelative,0,0,0,0,0,0,NULL,NULL);
|
||||
static int32 i;
|
||||
//message #1
|
||||
i=(last_mouse_message+1)&65535;
|
||||
|
@ -32456,7 +32680,7 @@ render_state.cull_mode=CULL_MODE__UNKNOWN;
|
|||
}//QB64_EVENT_RELATIVE_MOUSE_MOVEMENT
|
||||
|
||||
return -1;//Unknown command (use for debugging purposes only)
|
||||
}//QB64_Custom_Event
|
||||
}//qb64_custom_event
|
||||
|
||||
void reinit_glut_callbacks(){
|
||||
|
||||
|
|
|
@ -1,8 +1,56 @@
|
|||
#ifndef FREEGLUT_STATIC
|
||||
#define FREEGLUT_STATIC
|
||||
#define FREEGLUT_STATIC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* freeglut_main.c
|
||||
*
|
||||
* The windows message processing methods.
|
||||
*
|
||||
* Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
|
||||
* Written by Pawel W. Olszta, <olszta@sourceforge.net>
|
||||
* Creation date: Fri Dec 3 1999
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "freeglut.h"
|
||||
#include "freeglut_internal.h"
|
||||
#ifdef HAVE_ERRNO_H
|
||||
# include <errno.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#ifdef HAVE_VFPRINTF
|
||||
# define VFPRINTF(s,f,a) vfprintf((s),(f),(a))
|
||||
#elif defined(HAVE__DOPRNT)
|
||||
# define VFPRINTF(s,f,a) _doprnt((f),(a),(s))
|
||||
#else
|
||||
# define VFPRINTF(s,f,a)
|
||||
#endif
|
||||
|
||||
int qb64_custom_event(int event,int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,void *p1,void *p2);
|
||||
#ifdef TARGET_HOST_MS_WINDOWS
|
||||
LRESULT qb64_os_event_windows(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, int *qb64_os_event_info);
|
||||
#endif
|
||||
#if TARGET_HOST_POSIX_X11
|
||||
void qb64_os_event_linux(XEvent *event, int *qb64_os_event_info);
|
||||
#endif
|
||||
|
||||
int QB64_Custom_Event(int event,int v1,int v2,int v3,int v4,int v5,int v6,int v7,int v8,void *p1,void *p2);
|
||||
#define QB64_EVENT_CLOSE 1
|
||||
#define QB64_EVENT_KEY 2
|
||||
#define QB64_EVENT_RELATIVE_MOUSE_MOVEMENT 3
|
||||
|
@ -294,46 +342,6 @@ typedef enum {
|
|||
#define KMOD_ALT (KMOD_LALT|KMOD_RALT)
|
||||
#define KMOD_META (KMOD_LMETA|KMOD_RMETA)
|
||||
|
||||
/*
|
||||
* freeglut_main.c
|
||||
*
|
||||
* The windows message processing methods.
|
||||
*
|
||||
* Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
|
||||
* Written by Pawel W. Olszta, <olszta@sourceforge.net>
|
||||
* Creation date: Fri Dec 3 1999
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "freeglut.h"
|
||||
#include "freeglut_internal.h"
|
||||
#ifdef HAVE_ERRNO_H
|
||||
# include <errno.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#ifdef HAVE_VFPRINTF
|
||||
# define VFPRINTF(s,f,a) vfprintf((s),(f),(a))
|
||||
#elif defined(HAVE__DOPRNT)
|
||||
# define VFPRINTF(s,f,a) _doprnt((f),(a),(s))
|
||||
#else
|
||||
# define VFPRINTF(s,f,a)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
|
||||
|
@ -1287,6 +1295,9 @@ void FGAPIENTRY glutMainLoopEvent( void )
|
|||
window->State.MouseX = event.a.x; \
|
||||
window->State.MouseY = event.a.y;
|
||||
|
||||
|
||||
|
||||
|
||||
FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
|
||||
|
||||
while( XPending( fgDisplay.Display ) )
|
||||
|
@ -1296,6 +1307,12 @@ void FGAPIENTRY glutMainLoopEvent( void )
|
|||
fghPrintEvent( &event );
|
||||
#endif
|
||||
|
||||
int qb64_os_event_info=0;
|
||||
|
||||
qb64_os_event_info=1;
|
||||
qb64_os_event_linux(&event, &qb64_os_event_info);
|
||||
if (qb64_os_event_info==3) return;
|
||||
|
||||
switch( event.type )
|
||||
{
|
||||
case ClientMessage:
|
||||
|
@ -1747,6 +1764,11 @@ void FGAPIENTRY glutMainLoopEvent( void )
|
|||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
qb64_os_event_info=2;
|
||||
qb64_os_event_linux(&event, &qb64_os_event_info);
|
||||
if (qb64_os_event_info==3) return;//(although we would return anyway)
|
||||
|
||||
}
|
||||
|
||||
#elif TARGET_HOST_MS_WINDOWS
|
||||
|
@ -1897,6 +1919,16 @@ static int fghGetWin32Modifiers (void)
|
|||
LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
|
||||
LPARAM lParam )
|
||||
{
|
||||
|
||||
int qb64_os_event_info=0;
|
||||
LRESULT qb64_os_event_return=1;
|
||||
|
||||
qb64_os_event_info=1;
|
||||
qb64_os_event_return=qb64_os_event_windows(
|
||||
hWnd, uMsg, wParam,lParam, &qb64_os_event_info
|
||||
);
|
||||
if (qb64_os_event_info==3) return qb64_os_event_return;
|
||||
|
||||
static unsigned char lControl = 0, rControl = 0, lShift = 0,
|
||||
rShift = 0, lAlt = 0, rAlt = 0;
|
||||
|
||||
|
@ -2198,7 +2230,7 @@ LRESULT CALLBACK fgWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam,
|
|||
if ( fgState.ActionOnWindowClose != GLUT_ACTION_CONTINUE_EXECUTION )
|
||||
PostQuitMessage(0);
|
||||
*/
|
||||
QB64_Custom_Event(QB64_EVENT_CLOSE,0,0,0,0,0,0,0,0,NULL,NULL);
|
||||
qb64_custom_event(QB64_EVENT_CLOSE,0,0,0,0,0,0,0,0,NULL,NULL);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -2227,7 +2259,7 @@ if (raw_setup){
|
|||
{
|
||||
int xPosRelative = raw->data.mouse.lLastX;
|
||||
int yPosRelative = raw->data.mouse.lLastY;
|
||||
if (xPosRelative||yPosRelative) QB64_Custom_Event(QB64_EVENT_RELATIVE_MOUSE_MOVEMENT,xPosRelative,yPosRelative,0,0,0,0,0,0,NULL,NULL);
|
||||
if (xPosRelative||yPosRelative) qb64_custom_event(QB64_EVENT_RELATIVE_MOUSE_MOVEMENT,xPosRelative,yPosRelative,0,0,0,0,0,0,NULL,NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2475,11 +2507,11 @@ if (raw_setup){
|
|||
|
||||
//QB64
|
||||
if (wParam==VK_PAUSE){
|
||||
QB64_Custom_Event(QB64_EVENT_KEY,VK+QBVK_PAUSE,1,0,0,0,0,0,0,NULL,NULL);
|
||||
qb64_custom_event(QB64_EVENT_KEY,VK+QBVK_PAUSE,1,0,0,0,0,0,0,NULL,NULL);
|
||||
break;
|
||||
}
|
||||
if (wParam==VK_CANCEL){
|
||||
QB64_Custom_Event(QB64_EVENT_KEY,VK+QBVK_BREAK,1,0,0,0,0,0,0,NULL,NULL);
|
||||
qb64_custom_event(QB64_EVENT_KEY,VK+QBVK_BREAK,1,0,0,0,0,0,0,NULL,NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2580,11 +2612,11 @@ if (wParam==VK_CANCEL){
|
|||
|
||||
//QB64
|
||||
if (wParam==VK_PAUSE){
|
||||
QB64_Custom_Event(QB64_EVENT_KEY,VK+QBVK_PAUSE,-1,0,0,0,0,0,0,NULL,NULL);
|
||||
qb64_custom_event(QB64_EVENT_KEY,VK+QBVK_PAUSE,-1,0,0,0,0,0,0,NULL,NULL);
|
||||
break;
|
||||
}
|
||||
if (wParam==VK_CANCEL){
|
||||
QB64_Custom_Event(QB64_EVENT_KEY,VK+QBVK_BREAK,-1,0,0,0,0,0,0,NULL,NULL);
|
||||
qb64_custom_event(QB64_EVENT_KEY,VK+QBVK_BREAK,-1,0,0,0,0,0,0,NULL,NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2880,6 +2912,12 @@ if (wParam==VK_CANCEL){
|
|||
break;
|
||||
}
|
||||
|
||||
qb64_os_event_info=2;
|
||||
qb64_os_event_return=qb64_os_event_windows(
|
||||
hWnd, uMsg, wParam,lParam, &qb64_os_event_info
|
||||
);
|
||||
if (qb64_os_event_info==3) return qb64_os_event_return;
|
||||
|
||||
return lRet;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
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,4 +1,4 @@
|
|||
Copyright (c) 2010 Alex Diener
|
||||
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
|
||||
|
@ -16,4 +16,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 adiener@sacredsoftware.net
|
||||
Alex Diener alex@ludobloom.com
|
|
@ -0,0 +1,787 @@
|
|||
.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
|
|
@ -0,0 +1,5 @@
|
|||
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.
|
|
@ -0,0 +1,162 @@
|
|||
<?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>
|
|
@ -0,0 +1,22 @@
|
|||
<?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>
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
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
|
|
@ -0,0 +1,142 @@
|
|||
<?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>
|
|
@ -0,0 +1,30 @@
|
|||
<?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>
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
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,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2010 Alex Diener
|
||||
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
|
||||
|
@ -17,15 +17,17 @@
|
|||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener adiener@sacredsoftware.net
|
||||
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>
|
||||
|
@ -44,8 +46,8 @@ struct Gamepad_devicePrivate {
|
|||
};
|
||||
|
||||
struct Gamepad_queuedEvent {
|
||||
EventDispatcher * dispatcher;
|
||||
const char * eventType;
|
||||
unsigned int deviceID;
|
||||
enum Gamepad_eventType eventType;
|
||||
void * eventData;
|
||||
};
|
||||
|
||||
|
@ -59,74 +61,24 @@ static size_t eventQueueSize = 0;
|
|||
static size_t eventCount = 0;
|
||||
static pthread_mutex_t eventQueueMutex;
|
||||
|
||||
static EventDispatcher * eventDispatcher = NULL;
|
||||
static bool inited = false;
|
||||
|
||||
#define test_bit(bitIndex, array) \
|
||||
((array[(bitIndex) / (sizeof(int) * 8)] >> ((bitIndex) % (sizeof(int) * 8))) & 0x1)
|
||||
|
||||
static char ** findGamepadPaths(unsigned int * outNumGamepads) {
|
||||
DIR * dev_input;
|
||||
struct dirent * entity;
|
||||
unsigned int numGamepads = 0;
|
||||
char ** gamepadDevs = NULL;
|
||||
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];
|
||||
|
||||
dev_input = opendir("/dev/input");
|
||||
if (dev_input != NULL) {
|
||||
for (entity = readdir(dev_input); entity != NULL; entity = readdir(dev_input)) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
numGamepads++;
|
||||
gamepadDevs = realloc(gamepadDevs, sizeof(char *) * numGamepads);
|
||||
gamepadDevs[numGamepads - 1] = malloc(strlen(fileName) + 1);
|
||||
strcpy(gamepadDevs[numGamepads - 1], fileName);
|
||||
}
|
||||
}
|
||||
closedir(dev_input);
|
||||
}
|
||||
|
||||
*outNumGamepads = numGamepads;
|
||||
return gamepadDevs;
|
||||
}
|
||||
|
||||
void Gamepad_init() {
|
||||
if (!inited) {
|
||||
pthread_mutex_init(&devicesMutex, NULL);
|
||||
pthread_mutex_init(&eventQueueMutex, NULL);
|
||||
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) {
|
||||
device->eventDispatcher->dispose(device->eventDispatcher);
|
||||
|
||||
close(((struct Gamepad_devicePrivate *) device->privateData)->fd);
|
||||
free(((struct Gamepad_devicePrivate *) device->privateData)->path);
|
||||
free(device->privateData);
|
||||
|
@ -134,7 +86,6 @@ static void disposeDevice(struct Gamepad_device * device) {
|
|||
free((void *) device->description);
|
||||
free(device->axisStates);
|
||||
free(device->buttonStates);
|
||||
free(device->eventDispatcher);
|
||||
|
||||
free(device);
|
||||
}
|
||||
|
@ -169,7 +120,7 @@ void Gamepad_shutdown() {
|
|||
devices = NULL;
|
||||
|
||||
for (eventIndex = 0; eventIndex < eventCount; eventIndex++) {
|
||||
if (!strcmp(eventQueue[eventIndex].eventType, GAMEPAD_EVENT_DEVICE_REMOVED)) {
|
||||
if (eventQueue[eventIndex].eventType == GAMEPAD_EVENT_DEVICE_REMOVED) {
|
||||
disposeDevice(eventQueue[eventIndex].eventData);
|
||||
}
|
||||
}
|
||||
|
@ -179,23 +130,10 @@ void Gamepad_shutdown() {
|
|||
free(eventQueue);
|
||||
eventQueue = NULL;
|
||||
|
||||
if (eventDispatcher != NULL) {
|
||||
eventDispatcher->dispose(eventDispatcher);
|
||||
free(eventDispatcher);
|
||||
eventDispatcher = NULL;
|
||||
}
|
||||
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
EventDispatcher * Gamepad_eventDispatcher() {
|
||||
if (eventDispatcher == NULL) {
|
||||
eventDispatcher = EventDispatcher_create(NULL);
|
||||
}
|
||||
return eventDispatcher;
|
||||
}
|
||||
|
||||
unsigned int Gamepad_numDevices() {
|
||||
unsigned int result;
|
||||
|
||||
|
@ -219,10 +157,10 @@ struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static void queueEvent(EventDispatcher * dispatcher, const char * eventType, void * eventData) {
|
||||
static void queueEvent(unsigned int deviceID, enum Gamepad_eventType eventType, void * eventData) {
|
||||
struct Gamepad_queuedEvent queuedEvent;
|
||||
|
||||
queuedEvent.dispatcher = dispatcher;
|
||||
queuedEvent.deviceID = deviceID;
|
||||
queuedEvent.eventType = eventType;
|
||||
queuedEvent.eventData = eventData;
|
||||
|
||||
|
@ -235,7 +173,7 @@ static void queueEvent(EventDispatcher * dispatcher, const char * eventType, voi
|
|||
pthread_mutex_unlock(&eventQueueMutex);
|
||||
}
|
||||
|
||||
static void queueAxisEvent(struct Gamepad_device * device, double timestamp, unsigned int axisID, float value) {
|
||||
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));
|
||||
|
@ -243,8 +181,9 @@ static void queueAxisEvent(struct Gamepad_device * device, double timestamp, uns
|
|||
axisEvent->timestamp = timestamp;
|
||||
axisEvent->axisID = axisID;
|
||||
axisEvent->value = value;
|
||||
axisEvent->lastValue = lastValue;
|
||||
|
||||
queueEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, axisEvent);
|
||||
queueEvent(device->deviceID, GAMEPAD_EVENT_AXIS_MOVED, axisEvent);
|
||||
}
|
||||
|
||||
static void queueButtonEvent(struct Gamepad_device * device, double timestamp, unsigned int buttonID, bool down) {
|
||||
|
@ -256,7 +195,7 @@ static void queueButtonEvent(struct Gamepad_device * device, double timestamp, u
|
|||
buttonEvent->buttonID = buttonID;
|
||||
buttonEvent->down = down;
|
||||
|
||||
queueEvent(device->eventDispatcher, down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, buttonEvent);
|
||||
queueEvent(device->deviceID, down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, buttonEvent);
|
||||
}
|
||||
|
||||
static void * deviceThread(void * context) {
|
||||
|
@ -280,7 +219,8 @@ static void * deviceThread(void * context) {
|
|||
queueAxisEvent(device,
|
||||
event.time.tv_sec + event.time.tv_usec * 0.000001,
|
||||
devicePrivate->axisMap[event.code],
|
||||
value);
|
||||
value,
|
||||
device->axisStates[devicePrivate->axisMap[event.code]]);
|
||||
|
||||
device->axisStates[devicePrivate->axisMap[event.code]] = value;
|
||||
|
||||
|
@ -298,7 +238,7 @@ static void * deviceThread(void * context) {
|
|||
}
|
||||
}
|
||||
|
||||
queueEvent(eventDispatcher, GAMEPAD_EVENT_DEVICE_REMOVED, device);
|
||||
queueEvent(device->deviceID, GAMEPAD_EVENT_DEVICE_REMOVED, device);
|
||||
|
||||
pthread_mutex_lock(&devicesMutex);
|
||||
for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) {
|
||||
|
@ -318,123 +258,197 @@ static void * deviceThread(void * context) {
|
|||
}
|
||||
|
||||
void Gamepad_detectDevices() {
|
||||
unsigned int numPaths;
|
||||
char ** gamepadPaths;
|
||||
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 pathIndex, gamepadIndex;
|
||||
unsigned int gamepadIndex;
|
||||
struct stat statBuf;
|
||||
struct Gamepad_device * deviceRecord;
|
||||
struct Gamepad_devicePrivate * deviceRecordPrivate;
|
||||
int fd;
|
||||
char name[128];
|
||||
char * description;
|
||||
int evKeyBits[(KEY_CNT - 1) / sizeof(int) * 8 + 1];
|
||||
int evAbsBits[(ABS_CNT - 1) / sizeof(int) * 8 + 1];
|
||||
int bit;
|
||||
struct input_id id;
|
||||
time_t currentTime;
|
||||
static time_t lastInputStatTime;
|
||||
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
gamepadPaths = findGamepadPaths(&numPaths);
|
||||
|
||||
pthread_mutex_lock(&devicesMutex);
|
||||
for (pathIndex = 0; pathIndex < numPaths; pathIndex++) {
|
||||
duplicate = false;
|
||||
for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) {
|
||||
if (!strcmp(((struct Gamepad_devicePrivate *) devices[gamepadIndex]->privateData)->path, gamepadPaths[pathIndex])) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate) {
|
||||
free(gamepadPaths[pathIndex]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!stat(gamepadPaths[pathIndex], &statBuf)) {
|
||||
deviceRecord = malloc(sizeof(struct Gamepad_device));
|
||||
deviceRecord->deviceID = nextDeviceID++;
|
||||
deviceRecord->eventDispatcher = EventDispatcher_create(deviceRecord);
|
||||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
fd = open(gamepadPaths[pathIndex], O_RDONLY, 0);
|
||||
|
||||
deviceRecordPrivate = malloc(sizeof(struct Gamepad_devicePrivate));
|
||||
deviceRecordPrivate->fd = fd;
|
||||
deviceRecordPrivate->path = gamepadPaths[pathIndex];
|
||||
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(gamepadPaths[pathIndex] + 1));
|
||||
strcpy(description, gamepadPaths[pathIndex]);
|
||||
}
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
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++;
|
||||
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);
|
||||
}
|
||||
|
||||
deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes);
|
||||
deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons);
|
||||
|
||||
Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, deviceRecord);
|
||||
|
||||
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;
|
||||
unsigned int eventIndex;
|
||||
static bool inProcessEvents;
|
||||
|
||||
if (!inited) {
|
||||
if (!inited || inProcessEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
inProcessEvents = true;
|
||||
pthread_mutex_lock(&eventQueueMutex);
|
||||
for (eventIndex = 0; eventIndex < eventCount; eventIndex++) {
|
||||
eventQueue[eventIndex].dispatcher->dispatchEvent(eventQueue[eventIndex].dispatcher, eventQueue[eventIndex].eventType, eventQueue[eventIndex].eventData);
|
||||
if (!strcmp(eventQueue[eventIndex].eventType, GAMEPAD_EVENT_DEVICE_REMOVED)) {
|
||||
processQueuedEvent(eventQueue[eventIndex]);
|
||||
if (eventQueue[eventIndex].eventType == GAMEPAD_EVENT_DEVICE_REMOVED) {
|
||||
disposeDevice(eventQueue[eventIndex].eventData);
|
||||
}
|
||||
}
|
||||
eventCount = 0;
|
||||
pthread_mutex_unlock(&eventQueueMutex);
|
||||
inProcessEvents = false;
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2010 Alex Diener
|
||||
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
|
||||
|
@ -17,15 +17,18 @@
|
|||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener adiener@sacredsoftware.net
|
||||
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;
|
||||
|
@ -46,8 +49,8 @@ struct Gamepad_devicePrivate {
|
|||
};
|
||||
|
||||
struct Gamepad_queuedEvent {
|
||||
EventDispatcher * dispatcher;
|
||||
const char * eventType;
|
||||
unsigned int deviceID;
|
||||
enum Gamepad_eventType eventType;
|
||||
void * eventData;
|
||||
};
|
||||
|
||||
|
@ -64,8 +67,6 @@ static struct Gamepad_queuedEvent * deviceEventQueue = NULL;
|
|||
static size_t deviceEventQueueSize = 0;
|
||||
static size_t deviceEventCount = 0;
|
||||
|
||||
static EventDispatcher * eventDispatcher = NULL;
|
||||
|
||||
static void hatValueToXY(CFIndex value, CFIndex range, int * outX, int * outY) {
|
||||
if (value == range) {
|
||||
*outX = *outY = 0;
|
||||
|
@ -93,10 +94,10 @@ static void hatValueToXY(CFIndex value, CFIndex range, int * outX, int * outY) {
|
|||
}
|
||||
}
|
||||
|
||||
static void queueInputEvent(EventDispatcher * dispatcher, const char * eventType, void * eventData) {
|
||||
static void queueInputEvent(unsigned int deviceID, enum Gamepad_eventType eventType, void * eventData) {
|
||||
struct Gamepad_queuedEvent queuedEvent;
|
||||
|
||||
queuedEvent.dispatcher = dispatcher;
|
||||
queuedEvent.deviceID = deviceID;
|
||||
queuedEvent.eventType = eventType;
|
||||
queuedEvent.eventData = eventData;
|
||||
|
||||
|
@ -107,7 +108,7 @@ static void queueInputEvent(EventDispatcher * dispatcher, const char * eventType
|
|||
inputEventQueue[inputEventCount++] = queuedEvent;
|
||||
}
|
||||
|
||||
static void queueAxisEvent(struct Gamepad_device * device, double timestamp, unsigned int axisID, float value) {
|
||||
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));
|
||||
|
@ -115,8 +116,9 @@ static void queueAxisEvent(struct Gamepad_device * device, double timestamp, uns
|
|||
axisEvent->timestamp = timestamp;
|
||||
axisEvent->axisID = axisID;
|
||||
axisEvent->value = value;
|
||||
axisEvent->lastValue = lastValue;
|
||||
|
||||
queueInputEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, axisEvent);
|
||||
queueInputEvent(device->deviceID, GAMEPAD_EVENT_AXIS_MOVED, axisEvent);
|
||||
}
|
||||
|
||||
static void queueButtonEvent(struct Gamepad_device * device, double timestamp, unsigned int buttonID, bool down) {
|
||||
|
@ -128,7 +130,7 @@ static void queueButtonEvent(struct Gamepad_device * device, double timestamp, u
|
|||
buttonEvent->buttonID = buttonID;
|
||||
buttonEvent->down = down;
|
||||
|
||||
queueInputEvent(device->eventDispatcher, down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, buttonEvent);
|
||||
queueInputEvent(device->deviceID, down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, buttonEvent);
|
||||
}
|
||||
|
||||
static void onDeviceValueChanged(void * context, IOReturn result, void * sender, IOHIDValueRef value) {
|
||||
|
@ -163,7 +165,6 @@ static void onDeviceValueChanged(void * context, IOReturn result, void * sender,
|
|||
int x, y;
|
||||
|
||||
// Fix for Saitek X52
|
||||
hidDeviceRecord->axisElements[axisIndex].hasNullState = false;
|
||||
if (!hidDeviceRecord->axisElements[axisIndex].hasNullState) {
|
||||
if (integerValue < hidDeviceRecord->axisElements[axisIndex].logicalMin) {
|
||||
integerValue = hidDeviceRecord->axisElements[axisIndex].logicalMax - hidDeviceRecord->axisElements[axisIndex].logicalMin + 1;
|
||||
|
@ -178,7 +179,8 @@ static void onDeviceValueChanged(void * context, IOReturn result, void * sender,
|
|||
queueAxisEvent(deviceRecord,
|
||||
IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
||||
axisIndex,
|
||||
x);
|
||||
x,
|
||||
deviceRecord->axisStates[axisIndex]);
|
||||
|
||||
deviceRecord->axisStates[axisIndex] = x;
|
||||
}
|
||||
|
@ -187,7 +189,8 @@ static void onDeviceValueChanged(void * context, IOReturn result, void * sender,
|
|||
queueAxisEvent(deviceRecord,
|
||||
IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
||||
axisIndex + 1,
|
||||
y);
|
||||
y,
|
||||
deviceRecord->axisStates[axisIndex + 1]);
|
||||
|
||||
deviceRecord->axisStates[axisIndex + 1] = y;
|
||||
}
|
||||
|
@ -206,7 +209,8 @@ static void onDeviceValueChanged(void * context, IOReturn result, void * sender,
|
|||
queueAxisEvent(deviceRecord,
|
||||
IOHIDValueGetTimeStamp(value) * timebaseInfo.numer / timebaseInfo.denom * 0.000000001,
|
||||
axisIndex,
|
||||
floatValue);
|
||||
floatValue,
|
||||
deviceRecord->axisStates[axisIndex]);
|
||||
|
||||
deviceRecord->axisStates[axisIndex] = floatValue;
|
||||
}
|
||||
|
@ -270,7 +274,6 @@ static void onDeviceMatched(void * context, IOReturn result, void * sender, IOHI
|
|||
deviceRecord->productID = IOHIDDeviceGetProductID(device);
|
||||
deviceRecord->numAxes = 0;
|
||||
deviceRecord->numButtons = 0;
|
||||
deviceRecord->eventDispatcher = EventDispatcher_create(deviceRecord);
|
||||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
|
@ -286,11 +289,12 @@ static void onDeviceMatched(void * context, IOReturn result, void * sender, IOHI
|
|||
strcpy(description, "[Unknown]");
|
||||
|
||||
} else {
|
||||
const char * cStringPtr;
|
||||
CFIndex length;
|
||||
|
||||
cStringPtr = CFStringGetCStringPtr(cfProductName, CFStringGetSmallestEncoding(cfProductName));
|
||||
description = malloc(strlen(cStringPtr + 1));
|
||||
strcpy(description, cStringPtr);
|
||||
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;
|
||||
|
||||
|
@ -331,7 +335,7 @@ static void onDeviceMatched(void * context, IOReturn result, void * sender, IOHI
|
|||
|
||||
IOHIDDeviceRegisterInputValueCallback(device, onDeviceValueChanged, deviceRecord);
|
||||
|
||||
queuedEvent.dispatcher = Gamepad_eventDispatcher();
|
||||
queuedEvent.deviceID = deviceRecord->deviceID;
|
||||
queuedEvent.eventType = GAMEPAD_EVENT_DEVICE_ATTACHED;
|
||||
queuedEvent.eventData = deviceRecord;
|
||||
|
||||
|
@ -348,7 +352,7 @@ static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
|||
IOHIDDeviceRegisterInputValueCallback(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->deviceRef, NULL, NULL);
|
||||
|
||||
for (inputEventIndex = 0; inputEventIndex < inputEventCount; inputEventIndex++) {
|
||||
if (inputEventQueue[inputEventIndex].dispatcher == deviceRecord->eventDispatcher) {
|
||||
if (inputEventQueue[inputEventIndex].deviceID == deviceRecord->deviceID) {
|
||||
unsigned int inputEventIndex2;
|
||||
|
||||
free(inputEventQueue[inputEventIndex].eventData);
|
||||
|
@ -361,7 +365,7 @@ static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
|||
}
|
||||
|
||||
for (deviceEventIndex = 0; deviceEventIndex < deviceEventCount; deviceEventIndex++) {
|
||||
if (deviceEventQueue[deviceEventIndex].dispatcher == deviceRecord->eventDispatcher) {
|
||||
if (deviceEventQueue[deviceEventIndex].deviceID == deviceRecord->deviceID) {
|
||||
unsigned int deviceEventIndex2;
|
||||
|
||||
deviceEventCount--;
|
||||
|
@ -372,8 +376,6 @@ static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
|||
}
|
||||
}
|
||||
|
||||
deviceRecord->eventDispatcher->dispose(deviceRecord->eventDispatcher);
|
||||
|
||||
free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->axisElements);
|
||||
free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->buttonElements);
|
||||
free(deviceRecord->privateData);
|
||||
|
@ -381,7 +383,6 @@ static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
|||
free((void *) deviceRecord->description);
|
||||
free(deviceRecord->axisStates);
|
||||
free(deviceRecord->buttonStates);
|
||||
free(deviceRecord->eventDispatcher);
|
||||
|
||||
free(deviceRecord);
|
||||
}
|
||||
|
@ -391,7 +392,9 @@ static void onDeviceRemoved(void * context, IOReturn result, void * sender, IOHI
|
|||
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
if (((struct Gamepad_devicePrivate *) devices[deviceIndex]->privateData)->deviceRef == device) {
|
||||
Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_REMOVED, devices[deviceIndex]);
|
||||
if (Gamepad_deviceRemoveCallback != NULL) {
|
||||
Gamepad_deviceRemoveCallback(devices[deviceIndex], Gamepad_deviceRemoveContext);
|
||||
}
|
||||
|
||||
disposeDevice(devices[deviceIndex]);
|
||||
numDevices--;
|
||||
|
@ -412,8 +415,6 @@ void Gamepad_init() {
|
|||
CFArrayRef array;
|
||||
|
||||
hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
|
||||
IOHIDManagerOpen(hidManager, kIOHIDOptionsTypeNone);
|
||||
IOHIDManagerScheduleWithRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
|
||||
keys[0] = CFSTR(kIOHIDDeviceUsagePageKey);
|
||||
keys[1] = CFSTR(kIOHIDDeviceUsageKey);
|
||||
|
@ -451,6 +452,13 @@ void Gamepad_init() {
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -459,9 +467,6 @@ void Gamepad_shutdown() {
|
|||
unsigned int deviceIndex;
|
||||
|
||||
IOHIDManagerUnscheduleFromRunLoop(hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
IOHIDManagerClose(hidManager, 0);
|
||||
CFRelease(hidManager);
|
||||
hidManager = NULL;
|
||||
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
disposeDevice(devices[deviceIndex]);
|
||||
|
@ -470,21 +475,12 @@ void Gamepad_shutdown() {
|
|||
devices = NULL;
|
||||
numDevices = 0;
|
||||
|
||||
if (eventDispatcher != NULL) {
|
||||
eventDispatcher->dispose(eventDispatcher);
|
||||
free(eventDispatcher);
|
||||
eventDispatcher = NULL;
|
||||
}
|
||||
IOHIDManagerClose(hidManager, 0);
|
||||
CFRelease(hidManager);
|
||||
hidManager = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
EventDispatcher * Gamepad_eventDispatcher() {
|
||||
if (eventDispatcher == NULL) {
|
||||
eventDispatcher = EventDispatcher_create(NULL);
|
||||
}
|
||||
return eventDispatcher;
|
||||
}
|
||||
|
||||
unsigned int Gamepad_numDevices() {
|
||||
return numDevices;
|
||||
}
|
||||
|
@ -496,6 +492,43 @@ struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex) {
|
|||
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;
|
||||
|
||||
|
@ -503,23 +536,27 @@ void Gamepad_detectDevices() {
|
|||
return;
|
||||
}
|
||||
|
||||
CFRunLoopRunInMode(GAMEPAD_RUN_LOOP_MODE, 0, true);
|
||||
for (eventIndex = 0; eventIndex < deviceEventCount; eventIndex++) {
|
||||
deviceEventQueue[eventIndex].dispatcher->dispatchEvent(deviceEventQueue[eventIndex].dispatcher, deviceEventQueue[eventIndex].eventType, deviceEventQueue[eventIndex].eventData);
|
||||
processQueuedEvent(deviceEventQueue[eventIndex]);
|
||||
}
|
||||
deviceEventCount = 0;
|
||||
}
|
||||
|
||||
void Gamepad_processEvents() {
|
||||
unsigned int eventIndex;
|
||||
static bool inProcessEvents;
|
||||
|
||||
if (hidManager == NULL) {
|
||||
if (hidManager == NULL || inProcessEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
inProcessEvents = true;
|
||||
CFRunLoopRunInMode(GAMEPAD_RUN_LOOP_MODE, 0, true);
|
||||
for (eventIndex = 0; eventIndex < inputEventCount; eventIndex++) {
|
||||
inputEventQueue[eventIndex].dispatcher->dispatchEvent(inputEventQueue[eventIndex].dispatcher, inputEventQueue[eventIndex].eventType, inputEventQueue[eventIndex].eventData);
|
||||
processQueuedEvent(inputEventQueue[eventIndex]);
|
||||
free(inputEventQueue[eventIndex].eventData);
|
||||
}
|
||||
inputEventCount = 0;
|
||||
inProcessEvents = false;
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
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
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2010 Alex Diener
|
||||
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
|
||||
|
@ -17,10 +17,11 @@
|
|||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Alex Diener adiener@sacredsoftware.net
|
||||
Alex Diener alex@ludobloom.com
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "gamepad/Gamepad_private.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
|
@ -44,7 +45,6 @@ static struct Gamepad_device ** devices = NULL;
|
|||
static unsigned int numDevices = 0;
|
||||
static unsigned int nextDeviceID = 0;
|
||||
|
||||
static EventDispatcher * eventDispatcher = NULL;
|
||||
static bool inited = false;
|
||||
|
||||
void Gamepad_init() {
|
||||
|
@ -55,15 +55,12 @@ void Gamepad_init() {
|
|||
}
|
||||
|
||||
static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
||||
deviceRecord->eventDispatcher->dispose(deviceRecord->eventDispatcher);
|
||||
|
||||
free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->axisRanges);
|
||||
free(deviceRecord->privateData);
|
||||
|
||||
free((void *) deviceRecord->description);
|
||||
free(deviceRecord->axisStates);
|
||||
free(deviceRecord->buttonStates);
|
||||
free(deviceRecord->eventDispatcher);
|
||||
|
||||
free(deviceRecord);
|
||||
}
|
||||
|
@ -78,22 +75,10 @@ void Gamepad_shutdown() {
|
|||
free(devices);
|
||||
devices = NULL;
|
||||
numDevices = 0;
|
||||
if (eventDispatcher != NULL) {
|
||||
eventDispatcher->dispose(eventDispatcher);
|
||||
free(eventDispatcher);
|
||||
eventDispatcher = NULL;
|
||||
}
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
EventDispatcher * Gamepad_eventDispatcher() {
|
||||
if (eventDispatcher == NULL) {
|
||||
eventDispatcher = EventDispatcher_create(NULL);
|
||||
}
|
||||
return eventDispatcher;
|
||||
}
|
||||
|
||||
unsigned int Gamepad_numDevices() {
|
||||
return numDevices;
|
||||
}
|
||||
|
@ -108,7 +93,7 @@ struct Gamepad_device * Gamepad_deviceAtIndex(unsigned int deviceIndex) {
|
|||
#define REG_STRING_MAX 256
|
||||
|
||||
static char * getDeviceDescription(UINT joystickID, JOYCAPS caps) {
|
||||
char * description;
|
||||
char * description = NULL;
|
||||
char subkey[REG_STRING_MAX];
|
||||
HKEY topKey, key;
|
||||
LONG result;
|
||||
|
@ -199,7 +184,6 @@ void Gamepad_detectDevices() {
|
|||
deviceRecord->numButtons = caps.wNumButtons;
|
||||
deviceRecord->axisStates = calloc(sizeof(float), deviceRecord->numAxes);
|
||||
deviceRecord->buttonStates = calloc(sizeof(bool), deviceRecord->numButtons);
|
||||
deviceRecord->eventDispatcher = EventDispatcher_create(deviceRecord);
|
||||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
|
@ -242,7 +226,9 @@ void Gamepad_detectDevices() {
|
|||
|
||||
deviceRecord->privateData = deviceRecordPrivate;
|
||||
|
||||
Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, deviceRecord);
|
||||
if (Gamepad_deviceAttachCallback != NULL) {
|
||||
Gamepad_deviceAttachCallback(deviceRecord, Gamepad_deviceAttachContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -260,8 +246,8 @@ static double currentTime() {
|
|||
return (double) currentTime.QuadPart / frequency.QuadPart;
|
||||
}
|
||||
|
||||
static void handleAxisChange(struct Gamepad_device * device, int axisIndex, DWORD value) {
|
||||
struct Gamepad_axisEvent axisEvent;
|
||||
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) {
|
||||
|
@ -269,29 +255,29 @@ static void handleAxisChange(struct Gamepad_device * device, int axisIndex, DWOR
|
|||
}
|
||||
|
||||
devicePrivate = device->privateData;
|
||||
value = (ivalue - devicePrivate->axisRanges[axisIndex][0]) / (float) (devicePrivate->axisRanges[axisIndex][1] - devicePrivate->axisRanges[axisIndex][0]) * 2.0f - 1.0f;
|
||||
|
||||
axisEvent.device = device;
|
||||
axisEvent.timestamp = currentTime();
|
||||
axisEvent.axisID = axisIndex;
|
||||
axisEvent.value = (value - devicePrivate->axisRanges[axisIndex][0]) / (float) (devicePrivate->axisRanges[axisIndex][1] - devicePrivate->axisRanges[axisIndex][0]) * 2.0f - 1.0f;
|
||||
|
||||
device->axisStates[axisIndex] = axisEvent.value;
|
||||
device->eventDispatcher->dispatchEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, &axisEvent);
|
||||
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) {
|
||||
struct Gamepad_buttonEvent buttonEvent;
|
||||
bool down;
|
||||
unsigned int buttonIndex;
|
||||
|
||||
for (buttonIndex = 0; buttonIndex < device->numButtons; buttonIndex++) {
|
||||
if ((lastValue ^ value) & (1 << buttonIndex)) {
|
||||
buttonEvent.device = device;
|
||||
buttonEvent.timestamp = currentTime();
|
||||
buttonEvent.buttonID = buttonIndex;
|
||||
buttonEvent.down = !!(value & (1 << buttonIndex));
|
||||
down = !!(value & (1 << buttonIndex));
|
||||
|
||||
device->buttonStates[buttonIndex] = buttonEvent.down;
|
||||
device->eventDispatcher->dispatchEvent(device->eventDispatcher, buttonEvent.down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, &buttonEvent);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -326,7 +312,6 @@ static void povToXY(DWORD pov, int * outX, int * outY) {
|
|||
static void handlePOVChange(struct Gamepad_device * device, DWORD lastValue, DWORD value) {
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
int lastX, lastY, newX, newY;
|
||||
struct Gamepad_axisEvent axisEvent;
|
||||
|
||||
devicePrivate = device->privateData;
|
||||
|
||||
|
@ -338,36 +323,32 @@ static void handlePOVChange(struct Gamepad_device * device, DWORD lastValue, DWO
|
|||
povToXY(value, &newX, &newY);
|
||||
|
||||
if (newX != lastX) {
|
||||
axisEvent.device = device;
|
||||
axisEvent.timestamp = currentTime();
|
||||
axisEvent.axisID = devicePrivate->povXAxisIndex;
|
||||
axisEvent.value = newX;
|
||||
|
||||
device->axisStates[devicePrivate->povXAxisIndex] = axisEvent.value;
|
||||
device->eventDispatcher->dispatchEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, &axisEvent);
|
||||
device->axisStates[devicePrivate->povXAxisIndex] = newX;
|
||||
if (Gamepad_axisMoveCallback != NULL) {
|
||||
Gamepad_axisMoveCallback(device, devicePrivate->povXAxisIndex, newX, lastX, currentTime(), Gamepad_axisMoveContext);
|
||||
}
|
||||
}
|
||||
if (newY != lastY) {
|
||||
axisEvent.device = device;
|
||||
axisEvent.timestamp = currentTime();
|
||||
axisEvent.axisID = devicePrivate->povYAxisIndex;
|
||||
axisEvent.value = newY;
|
||||
|
||||
device->axisStates[devicePrivate->povYAxisIndex] = axisEvent.value;
|
||||
device->eventDispatcher->dispatchEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, &axisEvent);
|
||||
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) {
|
||||
if (!inited || inProcessEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
inProcessEvents = true;
|
||||
for (deviceIndex = 0; deviceIndex < numDevices; deviceIndex++) {
|
||||
device = devices[deviceIndex];
|
||||
devicePrivate = device->privateData;
|
||||
|
@ -376,7 +357,9 @@ void Gamepad_processEvents() {
|
|||
info.dwFlags = JOY_RETURNALL;
|
||||
result = joyGetPosEx(devicePrivate->joystickID, &info);
|
||||
if (result == JOYERR_UNPLUGGED) {
|
||||
Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_REMOVED, device);
|
||||
if (Gamepad_deviceRemoveCallback != NULL) {
|
||||
Gamepad_deviceRemoveCallback(device, Gamepad_deviceRemoveContext);
|
||||
}
|
||||
|
||||
disposeDevice(device);
|
||||
numDevices--;
|
||||
|
@ -412,5 +395,6 @@ void Gamepad_processEvents() {
|
|||
devicePrivate->lastState = info;
|
||||
}
|
||||
}
|
||||
inProcessEvents = false;
|
||||
}
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
#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 +1,3 @@
|
|||
VERSION_MAJOR=1
|
||||
VERSION_MINOR=1
|
||||
VERSION_MINOR=4
|
||||
VERSION_TWEAK=0
|
|
@ -1,420 +0,0 @@
|
|||
.PHONY: all
|
||||
all: library unittest testharness test include
|
||||
|
||||
UNAME = ${shell uname}
|
||||
ifeq (${UNAME},Linux)
|
||||
HOST_PLATFORM = linux
|
||||
else ifeq (${UNAME},Darwin)
|
||||
HOST_PLATFORM = macosx
|
||||
else
|
||||
HOST_PLATFORM = windows
|
||||
endif
|
||||
|
||||
TARGET_PLATFORMS_macosx = macosx
|
||||
TARGET_PLATFORMS_linux = linux
|
||||
TARGET_PLATFORMS_windows = windows
|
||||
|
||||
include version
|
||||
|
||||
PROJECT_NAME = gamepad
|
||||
|
||||
LIBRARY_TARGETS = library
|
||||
EXECUTABLE_TARGETS = unittest
|
||||
APPLICATION_TARGETS = testharness
|
||||
TARGETS = ${LIBRARY_TARGETS} ${EXECUTABLE_TARGETS} ${APPLICATION_TARGETS}
|
||||
CONFIGURATIONS = debug profile release
|
||||
PLATFORMS = ${filter ${TARGET_PLATFORMS_${HOST_PLATFORM}},macosx linux windows}
|
||||
ARCHS = ppc i386 i686 x86_64
|
||||
|
||||
TARGET_NAME_library = libstem_gamepad
|
||||
TARGET_NAME_unittest = unittest
|
||||
TARGET_NAME_testharness = GamepadTestHarness
|
||||
|
||||
#Per-target configurations
|
||||
CONFIGURATIONS_library = debug profile release
|
||||
CONFIGURATIONS_unittest = debug
|
||||
CONFIGURATIONS_testharness = debug profile
|
||||
|
||||
#Per-target platforms
|
||||
PLATFORMS_library = ${filter ${PLATFORMS},macosx linux windows}
|
||||
PLATFORMS_unittest = ${filter ${PLATFORMS},macosx linux windows}
|
||||
PLATFORMS_testharness = ${filter ${PLATFORMS},macosx linux windows}
|
||||
|
||||
#Per-target compile/link settings
|
||||
CCFLAGS_unittest = -I test_source -DSUITE_FILE_LIST='${foreach file,${SOURCES_unittest_suites},"${basename ${notdir ${file}}}",} NULL'
|
||||
|
||||
#Per-configuration compile/link settings
|
||||
CCFLAGS_debug = -g
|
||||
CCFLAGS_profile = -g -O3
|
||||
CCFLAGS_release = -O3
|
||||
|
||||
#Per-platform compile/link settings
|
||||
CC_macosx_ppc = /usr/bin/gcc-4.2 -arch ppc
|
||||
CC_macosx_i386 = /Developer/usr/bin/clang -arch i386
|
||||
CC_macosx_x86_64 = /Developer/usr/bin/clang -arch x86_64
|
||||
AR_macosx = /usr/bin/ar
|
||||
RANLIB_macosx = /usr/bin/ranlib
|
||||
SDKROOT_macosx = /Developer/SDKs/MacOSX10.5.sdk
|
||||
ARCHS_macosx = ppc i386 x86_64
|
||||
CCFLAGS_macosx = -isysroot ${SDKROOT_macosx} -mmacosx-version-min=10.5
|
||||
LINKFLAGS_macosx = -isysroot ${SDKROOT_macosx} -mmacosx-version-min=10.5 -framework IOKit -framework CoreFoundation -framework OpenGL -framework GLUT
|
||||
|
||||
CC_linux_i686 = /usr/bin/gcc
|
||||
AR_linux = /usr/bin/ar
|
||||
RANLIB_linux = /usr/bin/ranlib
|
||||
ARCHS_linux = i686
|
||||
CCFLAGS_linux =
|
||||
LINKFLAGS_linux = -lm -ldl -lglut -Wl,-E
|
||||
|
||||
CC_windows_i686 = \\MinGW\\bin\\gcc.exe
|
||||
AR_windows = \\MinGW\\bin\\ar.exe
|
||||
RANLIB_windows = \\MinGW\\bin\\ranlib.exe
|
||||
ARCHS_windows = i686
|
||||
CCFLAGS_windows = -DFREEGLUT_STATIC
|
||||
LINKFLAGS_windows = -lfreeglut_static -lopengl32 -lglu32 -lwinmm -lgdi32 -mwindows -mconsole
|
||||
|
||||
#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
|
||||
INCLUDE_CCFLAGS = -I source -I include
|
||||
OTHER_CCFLAGS = -std=gnu99
|
||||
CCFLAGS = ${DEFINE_CCFLAGS} ${WARNING_CCFLAGS} ${INCLUDE_CCFLAGS} ${OTHER_CCFLAGS}
|
||||
|
||||
FRAMEWORK_LINKFLAGS =
|
||||
LIBRARY_LINKFLAGS =
|
||||
OTHER_LINKFLAGS =
|
||||
LINKFLAGS = ${FRAMEWORK_LINKFLAGS} ${LIBRARY_LINKFLAGS} ${OTHER_LINKFLAGS}
|
||||
|
||||
#Per-target depencies
|
||||
|
||||
LIBRARY_DEPENDENCIES_unittest =
|
||||
LIBRARY_DEPENDENCIES_testharness = utilities/libstem_utilities.a glutshell/libstemshell_glut.a
|
||||
|
||||
#Per-target source file lists
|
||||
|
||||
SOURCES_library = \
|
||||
source/gamepad/Gamepad_${HOST_PLATFORM}.c \
|
||||
source/utilities/EventDispatcher.c
|
||||
|
||||
SOURCES_unittest = \
|
||||
test_source/unittest/framework/unittest_main.c \
|
||||
test_source/unittest/framework/TestList.c \
|
||||
${SOURCES_unittest_suites}
|
||||
|
||||
SOURCES_unittest_suites = \
|
||||
test_source/unittest/suites/GamepadTest.c
|
||||
|
||||
SOURCES_testharness = \
|
||||
test_source/testharness/TestHarness_main.c
|
||||
|
||||
SOURCES = ${sort ${foreach target,${TARGETS},${SOURCES_${target}}}}
|
||||
|
||||
INCLUDES = \
|
||||
source/gamepad/Gamepad.h \
|
||||
source/utilities/EventDispatcher.h
|
||||
|
||||
|
||||
|
||||
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}}, \
|
||||
build/intermediate/${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 compile_template #(target, configuration, platform, arch, source_file)
|
||||
build/intermediate/${2}-${3}-${4}/${notdir ${basename ${5}}}.o: ${5}
|
||||
mkdir -p build/intermediate/${2}-${3}-${4}
|
||||
${CC_${3}_${4}} ${CCFLAGS} ${CCFLAGS_${1}} ${CCFLAGS_${2}} ${CCFLAGS_${3}} -c -o $$@ $$^
|
||||
endef
|
||||
|
||||
#Produces object build targets for all source files in each configuration/platform/arch
|
||||
${foreach target,${TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${foreach arch,${ARCHS_${platform}}, \
|
||||
${foreach source,${SOURCES_${target}}, \
|
||||
${eval ${call compile_template,${target},${configuration},${platform},${arch},${source}}} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define library_template #(target, configuration, platform, arch, output_file)
|
||||
build/intermediate/${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/${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)
|
||||
build/library/debug-${3}/${TARGET_NAME_library}.a \
|
||||
${foreach library,${LIBRARY_DEPENDENCIES_${1}}, \
|
||||
lib/${dir ${library}}${configuration}-${platform}/${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}},${call library_dependency_template,${target},${configuration},${platform}}}} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define thin_binary_list_template #(target_name, configuration, platform)
|
||||
${foreach arch,${ARCHS_${3}}, \
|
||||
build/intermediate/${2}-${3}-${arch}/${1} \
|
||||
}
|
||||
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_NAME_${target}}.a,${configuration},${platform}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#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_NAME_${target}},${configuration},${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_NAME_${target}},${configuration},${platform}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
define assemble_library_macosx #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}.a: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
lipo -create -output $$@ $$^
|
||||
endef
|
||||
|
||||
define assemble_library_linux #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}.a: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
cp $$^ $$@
|
||||
endef
|
||||
|
||||
define assemble_library_windows #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}.a: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
cp $$^ $$@
|
||||
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 assemble_executable_macosx #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
lipo -create -output $$@ $$^
|
||||
endef
|
||||
|
||||
define assemble_executable_linux #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
cp $$^ $$@
|
||||
endef
|
||||
|
||||
define assemble_executable_windows #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}.exe: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
cp $$^ $$@
|
||||
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 = test_resources/Info_testharness_macosx.plist
|
||||
|
||||
define assemble_application_macosx #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}.app/Contents/MacOS/${TARGET_NAME_${1}}: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
mkdir -p $${dir $$@}../Resources
|
||||
sed -e "s/\$$$${PRODUCT_NAME}/${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_${3}}/g" \
|
||||
-e "s/\$$$${PLATFORM_LOWER}/${PLIST_PLATFORM_LOWER_${3}}/g" \
|
||||
-e "s/\$$$${SDK}/${PLIST_SDK_NAME_${3}}/g" \
|
||||
${PLIST_FILE_${1}_${3}} > $${dir $$@}/../Info.plist
|
||||
echo "APPL????" > $${dir $$@}../PkgInfo
|
||||
lipo -create -output $$@ $$^
|
||||
endef
|
||||
|
||||
define assemble_application_linux #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
cp $$^ $$@
|
||||
endef
|
||||
|
||||
define assemble_application_windows #(target, configuration, platform)
|
||||
build/${1}/${2}-${3}/${TARGET_NAME_${1}}.exe: ${THIN_BINARIES_${1}_${2}_${3}}
|
||||
mkdir -p $${dir $$@}
|
||||
cp $$^ $$@
|
||||
endef
|
||||
|
||||
#Produces final application build targets
|
||||
${foreach target,${APPLICATION_TARGETS}, \
|
||||
${foreach configuration,${CONFIGURATIONS_${target}}, \
|
||||
${foreach platform,${PLATFORMS_${target}}, \
|
||||
${eval ${call assemble_application_${HOST_PLATFORM},${target},${configuration},${platform}}} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
define library_target_template_macosx #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}.a}}
|
||||
endef
|
||||
|
||||
define library_target_template_linux #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}.a}}
|
||||
endef
|
||||
|
||||
define library_target_template_windows #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}.a}}
|
||||
endef
|
||||
|
||||
define executable_target_template_macosx #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}}}
|
||||
endef
|
||||
|
||||
define executable_target_template_linux #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}}}
|
||||
endef
|
||||
|
||||
define executable_target_template_windows #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}.exe}}
|
||||
endef
|
||||
|
||||
define application_target_template_macosx #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}.app/Contents/MacOS/${TARGET_NAME_${1}}}}
|
||||
endef
|
||||
|
||||
define application_target_template_linux #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}}}
|
||||
endef
|
||||
|
||||
define application_target_template_windows #(target)
|
||||
.PHONY: ${1}
|
||||
${1}: ${foreach configuration,${CONFIGURATIONS_${1}},${foreach platform,${PLATFORMS_${1}},build/${1}/${configuration}-${platform}/${TARGET_NAME_${1}}.exe}}
|
||||
endef
|
||||
|
||||
${foreach target,${LIBRARY_TARGETS}, \
|
||||
${eval ${call library_target_template_${HOST_PLATFORM},${target}}} \
|
||||
}
|
||||
|
||||
${foreach target,${EXECUTABLE_TARGETS}, \
|
||||
${eval ${call executable_target_template_${HOST_PLATFORM},${target}}} \
|
||||
}
|
||||
|
||||
${foreach target,${APPLICATION_TARGETS}, \
|
||||
${eval ${call application_target_template_${HOST_PLATFORM},${target}}} \
|
||||
}
|
||||
|
||||
.PHONY: test
|
||||
test: unittest ${foreach platform,${PLATFORMS_unittest},run_unittests_${platform}}
|
||||
|
||||
.PHONY: run_unittests_macosx
|
||||
run_unittests_macosx:
|
||||
./build/unittest/debug-macosx/unittest
|
||||
|
||||
.PHONY: run_unittests_linux
|
||||
run_unittests_linux:
|
||||
./build/unittest/debug-linux/unittest
|
||||
|
||||
.PHONY: run_unittests_windows
|
||||
run_unittests_windows:
|
||||
./build/unittest/debug-windows/unittest.exe
|
||||
|
||||
.PHONY: include
|
||||
include: ${INCLUDES}
|
||||
mkdir -p build/include
|
||||
cp $^ build/include
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf build
|
||||
rm -rf dist
|
||||
rm -rf dist_append
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef __SHELL_H__
|
||||
#define __SHELL_H__
|
||||
|
||||
void Shell_mainLoop();
|
||||
void Shell_redisplay();
|
||||
|
||||
double Shell_getCurrentTime();
|
||||
const char * Shell_getResourcePath();
|
||||
|
||||
#endif
|
|
@ -1,176 +0,0 @@
|
|||
// Adapted from GameShell (http://onesadcookie.com/svn/GameShell/Source/Common/GSKeyCodesInternal.h). Thanks Keith!
|
||||
|
||||
#ifndef __SHELL_KEY_CODES_H__
|
||||
#define __SHELL_KEY_CODES_H__
|
||||
|
||||
#define KEYBOARD_A 0x04
|
||||
#define KEYBOARD_B 0x05
|
||||
#define KEYBOARD_C 0x06
|
||||
#define KEYBOARD_D 0x07
|
||||
#define KEYBOARD_E 0x08
|
||||
#define KEYBOARD_F 0x09
|
||||
#define KEYBOARD_G 0x0A
|
||||
#define KEYBOARD_H 0x0B
|
||||
#define KEYBOARD_I 0x0C
|
||||
#define KEYBOARD_J 0x0D
|
||||
#define KEYBOARD_K 0x0E
|
||||
#define KEYBOARD_L 0x0F
|
||||
#define KEYBOARD_M 0x10
|
||||
#define KEYBOARD_N 0x11
|
||||
#define KEYBOARD_O 0x12
|
||||
#define KEYBOARD_P 0x13
|
||||
#define KEYBOARD_Q 0x14
|
||||
#define KEYBOARD_R 0x15
|
||||
#define KEYBOARD_S 0x16
|
||||
#define KEYBOARD_T 0x17
|
||||
#define KEYBOARD_U 0x18
|
||||
#define KEYBOARD_V 0x19
|
||||
#define KEYBOARD_W 0x1A
|
||||
#define KEYBOARD_X 0x1B
|
||||
#define KEYBOARD_Y 0x1C
|
||||
#define KEYBOARD_Z 0x1D
|
||||
#define KEYBOARD_1 0x1E
|
||||
#define KEYBOARD_2 0x1F
|
||||
#define KEYBOARD_3 0x20
|
||||
#define KEYBOARD_4 0x21
|
||||
#define KEYBOARD_5 0x22
|
||||
#define KEYBOARD_6 0x23
|
||||
#define KEYBOARD_7 0x24
|
||||
#define KEYBOARD_8 0x25
|
||||
#define KEYBOARD_9 0x26
|
||||
#define KEYBOARD_0 0x27
|
||||
#define KEYBOARD_RETURN_OR_ENTER 0x28
|
||||
#define KEYBOARD_ESCAPE 0x29
|
||||
#define KEYBOARD_DELETE_OR_BACKSPACE 0x2A
|
||||
#define KEYBOARD_TAB 0x2B
|
||||
#define KEYBOARD_SPACEBAR 0x2C
|
||||
#define KEYBOARD_HYPHEN 0x2D
|
||||
#define KEYBOARD_EQUAL_SIGN 0x2E
|
||||
#define KEYBOARD_OPEN_BRACKET 0x2F
|
||||
#define KEYBOARD_CLOSE_BRACKET 0x30
|
||||
#define KEYBOARD_BACKSLASH 0x31
|
||||
#define KEYBOARD_NON_USPOUND 0x32
|
||||
#define KEYBOARD_SEMICOLON 0x33
|
||||
#define KEYBOARD_QUOTE 0x34
|
||||
#define KEYBOARD_GRAVE_ACCENT_AND_TILDE 0x35
|
||||
#define KEYBOARD_COMMA 0x36
|
||||
#define KEYBOARD_PERIOD 0x37
|
||||
#define KEYBOARD_SLASH 0x38
|
||||
#define KEYBOARD_CAPS_LOCK 0x39
|
||||
#define KEYBOARD_F1 0x3A
|
||||
#define KEYBOARD_F2 0x3B
|
||||
#define KEYBOARD_F3 0x3C
|
||||
#define KEYBOARD_F4 0x3D
|
||||
#define KEYBOARD_F5 0x3E
|
||||
#define KEYBOARD_F6 0x3F
|
||||
#define KEYBOARD_F7 0x40
|
||||
#define KEYBOARD_F8 0x41
|
||||
#define KEYBOARD_F9 0x42
|
||||
#define KEYBOARD_F10 0x43
|
||||
#define KEYBOARD_F11 0x44
|
||||
#define KEYBOARD_F12 0x45
|
||||
#define KEYBOARD_PRINT_SCREEN 0x46
|
||||
#define KEYBOARD_SCROLL_LOCK 0x47
|
||||
#define KEYBOARD_PAUSE 0x48
|
||||
#define KEYBOARD_INSERT 0x49
|
||||
#define KEYBOARD_HOME 0x4A
|
||||
#define KEYBOARD_PAGE_UP 0x4B
|
||||
#define KEYBOARD_DELETE_FORWARD 0x4C
|
||||
#define KEYBOARD_END 0x4D
|
||||
#define KEYBOARD_PAGE_DOWN 0x4E
|
||||
#define KEYBOARD_RIGHT_ARROW 0x4F
|
||||
#define KEYBOARD_LEFT_ARROW 0x50
|
||||
#define KEYBOARD_DOWN_ARROW 0x51
|
||||
#define KEYBOARD_UP_ARROW 0x52
|
||||
#define KEYPAD_NUM_LOCK 0x53
|
||||
#define KEYPAD_SLASH 0x54
|
||||
#define KEYPAD_ASTERISK 0x55
|
||||
#define KEYPAD_HYPHEN 0x56
|
||||
#define KEYPAD_PLUS 0x57
|
||||
#define KEYPAD_ENTER 0x58
|
||||
#define KEYPAD_1 0x59
|
||||
#define KEYPAD_2 0x5A
|
||||
#define KEYPAD_3 0x5B
|
||||
#define KEYPAD_4 0x5C
|
||||
#define KEYPAD_5 0x5D
|
||||
#define KEYPAD_6 0x5E
|
||||
#define KEYPAD_7 0x5F
|
||||
#define KEYPAD_8 0x60
|
||||
#define KEYPAD_9 0x61
|
||||
#define KEYPAD_0 0x62
|
||||
#define KEYPAD_PERIOD 0x63
|
||||
#define KEYBOARD_NON_US_BACKSLASH 0x64
|
||||
#define KEYBOARD_APPLICATION 0x65
|
||||
#define KEYBOARD_POWER 0x66
|
||||
#define KEYPAD_EQUAL_SIGN 0x67
|
||||
#define KEYBOARD_F13 0x68
|
||||
#define KEYBOARD_F14 0x69
|
||||
#define KEYBOARD_F15 0x6A
|
||||
#define KEYBOARD_F16 0x6B
|
||||
#define KEYBOARD_F17 0x6C
|
||||
#define KEYBOARD_F18 0x6D
|
||||
#define KEYBOARD_F19 0x6E
|
||||
#define KEYBOARD_F20 0x6F
|
||||
#define KEYBOARD_F21 0x70
|
||||
#define KEYBOARD_F22 0x71
|
||||
#define KEYBOARD_F23 0x72
|
||||
#define KEYBOARD_F24 0x73
|
||||
#define KEYBOARD_EXECUTE 0x74
|
||||
#define KEYBOARD_HELP 0x75
|
||||
#define KEYBOARD_MENU 0x76
|
||||
#define KEYBOARD_SELECT 0x77
|
||||
#define KEYBOARD_STOP 0x78
|
||||
#define KEYBOARD_AGAIN 0x79
|
||||
#define KEYBOARD_UNDO 0x7A
|
||||
#define KEYBOARD_CUT 0x7B
|
||||
#define KEYBOARD_COPY 0x7C
|
||||
#define KEYBOARD_PASTE 0x7D
|
||||
#define KEYBOARD_FIND 0x7E
|
||||
#define KEYBOARD_MUTE 0x7F
|
||||
#define KEYBOARD_VOLUME_UP 0x80
|
||||
#define KEYBOARD_VOLUME_DOWN 0x81
|
||||
#define KEYBOARD_LOCKING_CAPS_LOCK 0x82
|
||||
#define KEYBOARD_LOCKING_NUM_LOCK 0x83
|
||||
#define KEYBOARD_LOCKING_SCROLL_LOCK 0x84
|
||||
#define KEYPAD_COMMA 0x85
|
||||
#define KEYPAD_EQUAL_SIGN_AS400 0x86
|
||||
#define KEYBOARD_INTERNATIONAL_1 0x87
|
||||
#define KEYBOARD_INTERNATIONAL_2 0x88
|
||||
#define KEYBOARD_INTERNATIONAL_3 0x89
|
||||
#define KEYBOARD_INTERNATIONAL_4 0x8A
|
||||
#define KEYBOARD_INTERNATIONAL_5 0x8B
|
||||
#define KEYBOARD_INTERNATIONAL_6 0x8C
|
||||
#define KEYBOARD_INTERNATIONAL_7 0x8D
|
||||
#define KEYBOARD_INTERNATIONAL_8 0x8E
|
||||
#define KEYBOARD_INTERNATIONAL_9 0x8F
|
||||
#define KEYBOARD_LANG1 0x90
|
||||
#define KEYBOARD_LANG2 0x91
|
||||
#define KEYBOARD_LANG3 0x92
|
||||
#define KEYBOARD_LANG4 0x93
|
||||
#define KEYBOARD_LANG5 0x94
|
||||
#define KEYBOARD_LANG6 0x95
|
||||
#define KEYBOARD_LANG7 0x96
|
||||
#define KEYBOARD_LANG8 0x97
|
||||
#define KEYBOARD_LANG9 0x98
|
||||
#define KEYBOARD_ALTERNATE_ERASE 0x99
|
||||
#define KEYBOARD_SYS_REQ_OR_ATTENTION 0x9A
|
||||
#define KEYBOARD_CANCEL 0x9B
|
||||
#define KEYBOARD_CLEAR 0x9C
|
||||
#define KEYBOARD_PRIOR 0x9D
|
||||
#define KEYBOARD_RETURN 0x9E
|
||||
#define KEYBOARD_SEPARATOR 0x9F
|
||||
#define KEYBOARD_OUT 0xA0
|
||||
#define KEYBOARD_OPER 0xA1
|
||||
#define KEYBOARD_CLEAR_OR_AGAIN 0xA2
|
||||
#define KEYBOARD_CR_SEL_OR_PROPS 0xA3
|
||||
#define KEYBOARD_EX_SEL 0xA4
|
||||
#define KEYBOARD_LEFT_CONTROL 0xE0
|
||||
#define KEYBOARD_LEFT_SHIFT 0xE1
|
||||
#define KEYBOARD_LEFT_ALT 0xE2
|
||||
#define KEYBOARD_LEFT_GUI 0xE3
|
||||
#define KEYBOARD_RIGHT_CONTROL 0xE4
|
||||
#define KEYBOARD_RIGHT_SHIFT 0xE5
|
||||
#define KEYBOARD_RIGHT_ALT 0xE6
|
||||
#define KEYBOARD_RIGHT_GUI 0xE7
|
||||
|
||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef __TARGET_H__
|
||||
#define __TARGET_H__
|
||||
|
||||
const char * Target_getName();
|
||||
|
||||
void Target_init(int argc, char ** argv);
|
||||
void Target_draw();
|
||||
|
||||
void Target_keyDown(int charCode, int keyCode);
|
||||
void Target_keyUp(int charCode, int keyCode);
|
||||
void Target_mouseDown(int buttonNumber, float x, float y);
|
||||
void Target_mouseUp(int buttonNumber, float x, float y);
|
||||
void Target_mouseMoved(float x, float y);
|
||||
void Target_mouseDragged(int buttonMask, float x, float y);
|
||||
|
||||
void Target_resized(int newWidth, int newHeight);
|
||||
|
||||
#endif
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2010 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 adiener@sacredsoftware.net
|
||||
*/
|
||||
|
||||
#ifndef __GAMEPAD_H__
|
||||
#define __GAMEPAD_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "utilities/EventDispatcher.h"
|
||||
|
||||
// eventData -> struct Gamepad_device
|
||||
#define GAMEPAD_EVENT_DEVICE_ATTACHED "GAMEPAD_EVENT_DEVICE_ATTACHED" // Only dispatched when Gamepad_init or Gamepad_detectDevices is called
|
||||
#define GAMEPAD_EVENT_DEVICE_REMOVED "GAMEPAD_EVENT_DEVICE_REMOVED" // Can be dispatched at any time
|
||||
|
||||
// eventData -> struct Gamepad_buttonEvent
|
||||
#define GAMEPAD_EVENT_BUTTON_DOWN "GAMEPAD_EVENT_BUTTON_DOWN" // Only dispatched when Gamepad_processEvents is called
|
||||
#define GAMEPAD_EVENT_BUTTON_UP "GAMEPAD_EVENT_BUTTON_UP" // Only dispatched when Gamepad_processEvents is called
|
||||
|
||||
// eventData -> struct Gamepad_axisEvent
|
||||
#define GAMEPAD_EVENT_AXIS_MOVED "GAMEPAD_EVENT_AXIS_MOVED" // Only dispatched when Gamepad_processEvents is called
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct Gamepad_device {
|
||||
// Unique device identifier for application session. 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;
|
||||
|
||||
// Broadcasts GAMEPAD_EVENT_BUTTON_DOWN, GAMEPAD_EVENT_BUTTON_UP, and GAMEPAD_EVENT_AXIS_MOVED
|
||||
EventDispatcher * eventDispatcher;
|
||||
|
||||
// Platform-specific device data storage; don't mess with it
|
||||
void * privateData;
|
||||
};
|
||||
|
||||
/* Initializes gamepad library and detects initial devices. Call this before any other Gamepad_*()
|
||||
function, EXCEPT Gamepad_eventDispatcher(). In order to get receive GAMEPAD_EVENT_DEVICE_ATTACHED
|
||||
events from devices detected in Gamepad_init(), you must register handlers for those events before
|
||||
calling Gamepad_init(). */
|
||||
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. */
|
||||
void Gamepad_shutdown();
|
||||
|
||||
/* EventDispatcher used by gamepad library to broadcast GAMEPAD_EVENT_DEVICE_ATTACHED and
|
||||
GAMEPAD_EVENT_DEVICE_REMOVED events. */
|
||||
EventDispatcher * Gamepad_eventDispatcher();
|
||||
|
||||
/* 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, a GAMEPAD_EVENT_DEVICE_ATTACHED event will be
|
||||
broadcast via Gamepad_eventDispatcher() for each one. */
|
||||
void Gamepad_detectDevices();
|
||||
|
||||
/* Reads pending input from all attached devices and broadcasts GAMEPAD_EVENT_BUTTON_DOWN,
|
||||
GAMEPAD_EVENT_BUTTON_UP, and GAMEPAD_EVENT_AXIS_MOVED events through the eventDispatcher of the
|
||||
device that generated the event. */
|
||||
void Gamepad_processEvents();
|
||||
|
||||
#endif
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2010 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 adiener@sacredsoftware.net
|
||||
*/
|
||||
|
||||
#include "utilities/EventDispatcher.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct EventTarget {
|
||||
char * eventID;
|
||||
EventDispatcherCallback callback;
|
||||
void * context;
|
||||
};
|
||||
|
||||
EventDispatcher * EventDispatcher_create(void * owner) {
|
||||
EventDispatcher * self;
|
||||
|
||||
self = malloc(sizeof(EventDispatcher));
|
||||
EventDispatcher_init(self, owner);
|
||||
return self;
|
||||
}
|
||||
|
||||
void EventDispatcher_init(EventDispatcher * self, void * owner) {
|
||||
self->dispose = EventDispatcher_dispose;
|
||||
self->registerForEvent = EventDispatcher_registerForEvent;
|
||||
self->unregisterForEvent = EventDispatcher_unregisterForEvent;
|
||||
self->dispatchEvent = EventDispatcher_dispatchEvent;
|
||||
|
||||
self->owner = owner;
|
||||
self->numberOfTargets = 0;
|
||||
self->targetListSize = 1;
|
||||
self->targets = (struct EventTarget *) malloc(sizeof(struct EventTarget) * self->targetListSize);
|
||||
}
|
||||
|
||||
void EventDispatcher_dispose(void * selfPtr) {
|
||||
EventDispatcher * self = selfPtr;
|
||||
int targetIndex;
|
||||
|
||||
for (targetIndex = 0; targetIndex < self->numberOfTargets; targetIndex++) {
|
||||
free(self->targets[targetIndex].eventID);
|
||||
}
|
||||
free(self->targets);
|
||||
}
|
||||
|
||||
void EventDispatcher_registerForEvent(void * selfPtr, const char * eventID, EventDispatcherCallback callback, void * context) {
|
||||
EventDispatcher * self = selfPtr;
|
||||
size_t length;
|
||||
|
||||
if (self->numberOfTargets >= self->targetListSize) {
|
||||
self->targetListSize *= 2;
|
||||
self->targets = (struct EventTarget *) realloc(self->targets, sizeof(struct EventTarget) * self->targetListSize);
|
||||
}
|
||||
|
||||
length = strlen(eventID);
|
||||
self->targets[self->numberOfTargets].eventID = malloc(length + 1);
|
||||
strncpy(self->targets[self->numberOfTargets].eventID, eventID, length + 1);
|
||||
self->targets[self->numberOfTargets].callback = callback;
|
||||
self->targets[self->numberOfTargets].context = context;
|
||||
self->numberOfTargets++;
|
||||
}
|
||||
|
||||
void EventDispatcher_unregisterForEvent(void * selfPtr, const char * eventID, EventDispatcherCallback callback) {
|
||||
EventDispatcher * self = selfPtr;
|
||||
int targetIndex;
|
||||
|
||||
for (targetIndex = 0; targetIndex < self->numberOfTargets; targetIndex++) {
|
||||
if (!strcmp(eventID, self->targets[targetIndex].eventID) && self->targets[targetIndex].callback == callback) {
|
||||
free(self->targets[targetIndex].eventID);
|
||||
self->numberOfTargets--;
|
||||
for (; targetIndex < self->numberOfTargets; targetIndex++) {
|
||||
self->targets[targetIndex] = self->targets[targetIndex + 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EventDispatcher_dispatchEvent(void * selfPtr, const char * eventID, void * eventData) {
|
||||
EventDispatcher * self = selfPtr;
|
||||
int targetIndex;
|
||||
int numberOfTargetsCopy;
|
||||
struct EventTarget * targetsCopy;
|
||||
bool eventHandled, anyEventsHandled;
|
||||
|
||||
numberOfTargetsCopy = self->numberOfTargets;
|
||||
targetsCopy = malloc(sizeof(struct EventTarget) * numberOfTargetsCopy);
|
||||
memcpy(targetsCopy, self->targets, sizeof(struct EventTarget) * numberOfTargetsCopy);
|
||||
|
||||
anyEventsHandled = false;
|
||||
for (targetIndex = 0; targetIndex < numberOfTargetsCopy; targetIndex++) {
|
||||
if (!strcmp(eventID, self->targets[targetIndex].eventID)) {
|
||||
eventHandled = targetsCopy[targetIndex].callback(self->owner, eventID, eventData, targetsCopy[targetIndex].context);
|
||||
|
||||
if (eventHandled) {
|
||||
anyEventsHandled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(targetsCopy);
|
||||
|
||||
return anyEventsHandled;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2010 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 adiener@sacredsoftware.net
|
||||
*/
|
||||
|
||||
#ifndef __EVENT_DISPATCHER_H__
|
||||
#define __EVENT_DISPATCHER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct EventDispatcher EventDispatcher;
|
||||
|
||||
/* Signature for event handler callbacks.
|
||||
|
||||
sender: Object that dispatched the event. More specifically, the object passed to EventDispatcher_create.
|
||||
eventID: Name of event that was triggered
|
||||
eventData: Arbitrary data passed by dispatcher. Its format is known by convention depending on the event ID being dispatched.
|
||||
context: Value passed as context to registerForEvent
|
||||
|
||||
This function should return true if the event was handled, or false if it was ignored. */
|
||||
typedef bool (* EventDispatcherCallback)(void * sender, const char * eventID, void * eventData, void * context);
|
||||
|
||||
struct EventTarget;
|
||||
|
||||
#define EventDispatcher_structContents \
|
||||
void * owner; \
|
||||
\
|
||||
int numberOfTargets; \
|
||||
int targetListSize; \
|
||||
struct EventTarget * targets; \
|
||||
\
|
||||
void (* dispose)(void * self); \
|
||||
void (* registerForEvent)(void * self, const char * eventID, EventDispatcherCallback callback, void * context); \
|
||||
void (* unregisterForEvent)(void * self, const char * eventID, EventDispatcherCallback callback); \
|
||||
bool (* dispatchEvent)(void * self, const char * eventID, void * eventData);
|
||||
|
||||
struct EventDispatcher {
|
||||
EventDispatcher_structContents
|
||||
};
|
||||
|
||||
/* Allocate and initialize a new EventDispatcher object. owner will be passed to event callbacks as
|
||||
the sender parameter. */
|
||||
EventDispatcher * EventDispatcher_create(void * owner);
|
||||
|
||||
/* Initialize an already allocated EventDispatcher. owner will be passed to event callbacks as the
|
||||
sender parameter. */
|
||||
void EventDispatcher_init(EventDispatcher * self, void * owner);
|
||||
|
||||
/* Free all memory allocated by EventDispatcher and remove all registered listeners. Does NOT free
|
||||
the EventDispatcher itself. */
|
||||
void EventDispatcher_dispose(void * selfPtr);
|
||||
|
||||
/* Register for notification of events of type eventID */
|
||||
void EventDispatcher_registerForEvent(void * selfPtr, const char * eventID, EventDispatcherCallback callback, void * context);
|
||||
|
||||
/* Remove a previous registration for events of type eventID */
|
||||
void EventDispatcher_unregisterForEvent(void * selfPtr, const char * eventID, EventDispatcherCallback callback);
|
||||
|
||||
/* Dispatch an event to all registered listeners for that event ID. Returns true if any listener is
|
||||
registered and returns true from its handler callback. */
|
||||
bool EventDispatcher_dispatchEvent(void * selfPtr, const char * eventID, void * eventData);
|
||||
|
||||
#endif
|
|
@ -1,242 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include "shell/Shell.h"
|
||||
#include "shell/ShellKeyCodes.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <GLUT/glut.h>
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
static bool verbose = false;
|
||||
|
||||
bool onButtonDown(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_buttonEvent * event;
|
||||
|
||||
event = eventData;
|
||||
if (verbose) {
|
||||
printf("Button %u down (%d) on device %u at %f\n", event->buttonID, (int) event->down, event->device->deviceID, event->timestamp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onButtonUp(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_buttonEvent * event;
|
||||
|
||||
event = eventData;
|
||||
if (verbose) {
|
||||
printf("Button %u up (%d) on device %u at %f\n", event->buttonID, (int) event->down, event->device->deviceID, event->timestamp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onAxisMoved(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_axisEvent * event;
|
||||
|
||||
event = eventData;
|
||||
if (verbose) {
|
||||
printf("Axis %u moved to %f on device %u at %f\n", event->axisID, event->value, event->device->deviceID, event->timestamp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onDeviceAttached(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_device * device;
|
||||
|
||||
device = eventData;
|
||||
if (verbose) {
|
||||
printf("Device ID %u attached (vendor = 0x%X; product = 0x%X)\n", device->deviceID, device->vendorID, device->productID);
|
||||
}
|
||||
device->eventDispatcher->registerForEvent(device->eventDispatcher, GAMEPAD_EVENT_BUTTON_DOWN, onButtonDown, device);
|
||||
device->eventDispatcher->registerForEvent(device->eventDispatcher, GAMEPAD_EVENT_BUTTON_UP, onButtonUp, device);
|
||||
device->eventDispatcher->registerForEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, onAxisMoved, device);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onDeviceRemoved(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_device * device;
|
||||
|
||||
device = eventData;
|
||||
if (verbose) {
|
||||
printf("Device ID %u removed\n", device->deviceID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char * Target_getName() {
|
||||
return "Gamepad test harness";
|
||||
}
|
||||
|
||||
static unsigned int windowWidth = 800, windowHeight = 600;
|
||||
|
||||
static void initGamepad() {
|
||||
Gamepad_eventDispatcher()->registerForEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, onDeviceAttached, NULL);
|
||||
Gamepad_eventDispatcher()->registerForEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_REMOVED, onDeviceRemoved, NULL);
|
||||
Gamepad_init();
|
||||
}
|
||||
|
||||
void Target_init(int argc, char ** argv) {
|
||||
int argIndex;
|
||||
|
||||
for (argIndex = 1; argIndex < argc; argIndex++) {
|
||||
if (!strcmp(argv[argIndex], "-v")) {
|
||||
verbose = true;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Shell_mainLoop();
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
void Target_draw() {
|
||||
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");
|
||||
}
|
||||
|
||||
Shell_redisplay();
|
||||
}
|
||||
|
||||
void Target_keyDown(int charCode, int keyCode) {
|
||||
if (keyCode == KEYBOARD_R) {
|
||||
Gamepad_shutdown();
|
||||
initGamepad();
|
||||
}
|
||||
}
|
||||
|
||||
void Target_keyUp(int charCode, int keyCode) {
|
||||
}
|
||||
|
||||
void Target_mouseDown(int buttonNumber, float x, float y) {
|
||||
}
|
||||
|
||||
void Target_mouseUp(int buttonNumber, float x, float y) {
|
||||
}
|
||||
|
||||
void Target_mouseMoved(float x, float y) {
|
||||
}
|
||||
|
||||
void Target_mouseDragged(int buttonMask, float x, float y) {
|
||||
}
|
||||
|
||||
void Target_resized(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);
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include "unittest/framework/TestSuite.h"
|
||||
|
||||
TestSuite ** getTestSuites() {
|
||||
static char * testFileNames[] = {SUITE_FILE_LIST};
|
||||
static TestSuite * testSuites[sizeof(testFileNames) / sizeof(char *)];
|
||||
char suiteFunctionName[256];
|
||||
unsigned int suiteIndex;
|
||||
struct TestSuite * (* suiteFunction)();
|
||||
#if defined(WIN32)
|
||||
HMODULE moduleHandle;
|
||||
|
||||
moduleHandle = GetModuleHandle(NULL);
|
||||
#endif
|
||||
|
||||
for (suiteIndex = 0; suiteIndex < sizeof(testFileNames) / sizeof(char *) - 1; suiteIndex++) {
|
||||
snprintf(suiteFunctionName, 256, "%s_suite", testFileNames[suiteIndex]);
|
||||
#if defined(WIN32)
|
||||
suiteFunction = (struct TestSuite * (*)()) GetProcAddress(moduleHandle, suiteFunctionName);
|
||||
#else
|
||||
suiteFunction = (struct TestSuite * (*)()) dlsym(RTLD_DEFAULT, suiteFunctionName);
|
||||
#endif
|
||||
if (suiteFunction == NULL) {
|
||||
fprintf(stderr, "Couldn't load test suite %s (no symbol named %s found)\n", testFileNames[suiteIndex], suiteFunctionName);
|
||||
abort();
|
||||
}
|
||||
testSuites[suiteIndex] = suiteFunction();
|
||||
}
|
||||
testSuites[suiteIndex] = NULL;
|
||||
|
||||
return testSuites;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef __TEST_SUITE_H__
|
||||
#define __TEST_SUITE_H__
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct TestSuite TestSuite;
|
||||
|
||||
extern void (* g_unitTestFailureCallback)(const char * file, const char * function, int line, const char * format, ...) __attribute__((__noreturn__)) __attribute__((format(printf, 4, 5)));
|
||||
|
||||
struct TestSuite {
|
||||
char * description;
|
||||
unsigned int numberOfTestCases;
|
||||
void (** testCases)();
|
||||
};
|
||||
|
||||
#define TestCase_assert(condition, ...) \
|
||||
if (!(condition)) { \
|
||||
(*g_unitTestFailureCallback)(__FILE__, __FUNCTION__, __LINE__, __VA_ARGS__); \
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#define DLLEXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define DLLEXPORT
|
||||
#endif
|
||||
#define TEST_SUITE(name, ...) \
|
||||
DLLEXPORT TestSuite * name##_suite() { \
|
||||
return testSuite(#name, __VA_ARGS__, NULL); \
|
||||
}
|
||||
|
||||
static inline TestSuite * testSuite(const char * description, ...) __attribute__((sentinel));
|
||||
static inline TestSuite * testSuite(const char * description, ...) {
|
||||
TestSuite * suite;
|
||||
va_list args;
|
||||
unsigned int testCaseIndex;
|
||||
|
||||
suite = malloc(sizeof(TestSuite));
|
||||
|
||||
va_start(args, description);
|
||||
for (suite->numberOfTestCases = 0; va_arg(args, void (*)()) != NULL; suite->numberOfTestCases++);
|
||||
va_end(args);
|
||||
|
||||
suite->description = malloc(strlen(description) + 1);
|
||||
strcpy(suite->description, description);
|
||||
suite->testCases = malloc(sizeof(void (*)()) * suite->numberOfTestCases);
|
||||
va_start(args, description);
|
||||
for (testCaseIndex = 0; testCaseIndex < suite->numberOfTestCases; testCaseIndex++) {
|
||||
suite->testCases[testCaseIndex] = va_arg(args, void (*)());
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,84 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "unittest/framework/TestSuite.h"
|
||||
|
||||
extern TestSuite ** getTestSuites();
|
||||
|
||||
void (* g_unitTestFailureCallback)(const char * file, const char * function, int line, const char * format, ...) __attribute__((__noreturn__)) __attribute__((format(printf, 4, 5)));
|
||||
|
||||
static int failures = 0;
|
||||
static jmp_buf jmpEnv;
|
||||
|
||||
static int lengthOfSharedPrefix(const char * string1, const char * string2) {
|
||||
int charIndex;
|
||||
|
||||
for (charIndex = 0; string1[charIndex] != '\x00' && string2[charIndex] != '\x00'; charIndex++) {
|
||||
if (string1[charIndex] != string2[charIndex]) break;
|
||||
}
|
||||
return charIndex;
|
||||
}
|
||||
|
||||
static void assertFailureCallback(const char * file, const char * function, int line, const char * format, ...) __attribute__((__noreturn__)) __attribute__((format(printf, 4, 5)));
|
||||
static void assertFailureCallback(const char * file, const char * function, int line, const char * format, ...) {
|
||||
va_list args;
|
||||
static char * sourceRoot = NULL;
|
||||
|
||||
if (sourceRoot == NULL) {
|
||||
int charIndex;
|
||||
int length;
|
||||
|
||||
length = strlen(__FILE__);
|
||||
sourceRoot = malloc(length + 1);
|
||||
strcpy(sourceRoot, __FILE__);
|
||||
for (charIndex = 0; charIndex < length; charIndex++) {
|
||||
if (!strcmp(sourceRoot + charIndex, "unittest/unittest_main.c")) {
|
||||
sourceRoot[charIndex] = '\x00';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file += lengthOfSharedPrefix(sourceRoot, file);
|
||||
printf(" FAILURE in %s (%s:%d):\n ", function, file, line);
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
putchar('\n');
|
||||
|
||||
failures++;
|
||||
longjmp(jmpEnv, 1);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
TestSuite ** testSuites;
|
||||
unsigned int numberOfTestSuites;
|
||||
unsigned int testSuiteIndex, testCaseIndex;
|
||||
|
||||
if (argc > 1) {
|
||||
chdir(argv[1]);
|
||||
}
|
||||
|
||||
g_unitTestFailureCallback = assertFailureCallback;
|
||||
|
||||
testSuites = getTestSuites();
|
||||
for (numberOfTestSuites = 0; testSuites[numberOfTestSuites] != NULL; numberOfTestSuites++);
|
||||
|
||||
putchar('\n');
|
||||
for (testSuiteIndex = 0; testSuiteIndex < numberOfTestSuites; testSuiteIndex++) {
|
||||
printf("%s (%d/%d) running %d test%s...\n", testSuites[testSuiteIndex]->description, testSuiteIndex + 1, numberOfTestSuites, testSuites[testSuiteIndex]->numberOfTestCases, testSuites[testSuiteIndex]->numberOfTestCases == 1 ? "" : "s");
|
||||
for (testCaseIndex = 0; testCaseIndex < testSuites[testSuiteIndex]->numberOfTestCases; testCaseIndex++) {
|
||||
if (setjmp(jmpEnv) != 0) {
|
||||
continue;
|
||||
}
|
||||
testSuites[testSuiteIndex]->testCases[testCaseIndex]();
|
||||
}
|
||||
}
|
||||
printf("\nTests completed (%d failure%s)\n\n", failures, failures == 1 ? "" : "s");
|
||||
|
||||
return failures ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#include "unittest/framework/TestSuite.h"
|
||||
|
||||
static void blank() {
|
||||
// No tests
|
||||
}
|
||||
|
||||
TEST_SUITE(GamepadTest, blank)
|
1
internal/c/parts/input/game_controller/notes.txt
Normal file
1
internal/c/parts/input/game_controller/notes.txt
Normal file
|
@ -0,0 +1 @@
|
|||
http://forums.tigsource.com/index.php?topic=10675.80
|
14
internal/c/parts/input/game_controller/os/lnx/build.sh
Normal file
14
internal/c/parts/input/game_controller/os/lnx/build.sh
Normal file
|
@ -0,0 +1,14 @@
|
|||
#!/bin/sh
|
||||
gcc -s -c -w -Wall ../../src/Gamepad_linux.c -o temp/Gamepad_linux.o
|
||||
gcc -s -c -w -Wall ../../src/Gamepad_private.c -o temp/Gamepad_private.o
|
||||
ar rcs src.a temp/Gamepad_private.o temp/Gamepad_linux.o
|
||||
echo "Press any key to continue..."
|
||||
Pause()
|
||||
{
|
||||
OLDCONFIG=`stty -g`
|
||||
stty -icanon -echo min 1 time 0
|
||||
dd count=1 2>/dev/null
|
||||
stty $OLDCONFIG
|
||||
}
|
||||
Pause
|
||||
|
14
internal/c/parts/input/game_controller/os/osx/build.command
Normal file
14
internal/c/parts/input/game_controller/os/osx/build.command
Normal file
|
@ -0,0 +1,14 @@
|
|||
cd "$(dirname "$0")"
|
||||
gcc -s -c -w -Wall ../../src/Gamepad_macosx.c -o temp/Gamepad_macosx.o
|
||||
gcc -s -c -w -Wall ../../src/Gamepad_private.c -o temp/Gamepad_private.o
|
||||
ar rcs src.a temp/Gamepad_private.o temp/Gamepad_macosx.o
|
||||
echo "Press any key to continue..."
|
||||
Pause()
|
||||
{
|
||||
OLDCONFIG=`stty -g`
|
||||
stty -icanon -echo min 1 time 0
|
||||
dd count=1 2>/dev/null
|
||||
stty $OLDCONFIG
|
||||
}
|
||||
Pause
|
||||
|
4
internal/c/parts/input/game_controller/os/win/build.bat
Normal file
4
internal/c/parts/input/game_controller/os/win/build.bat
Normal file
|
@ -0,0 +1,4 @@
|
|||
..\..\..\..\..\c_compiler\bin\gcc -s -c -w -Wall ..\..\src\Gamepad_windows_mm.c -o temp\Gamepad_windows_mm.o
|
||||
..\..\..\..\..\c_compiler\bin\gcc -s -c -w -Wall ..\..\src\Gamepad_private.c -o temp\Gamepad_private.o
|
||||
..\..\..\..\..\c_compiler\bin\ar rcs src.a temp\Gamepad_private.o temp\Gamepad_windows_mm.o
|
||||
pause
|
|
@ -1,299 +1,333 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "src/gamepad/Gamepad.h"
|
||||
|
||||
#include "../../../os.h"
|
||||
|
||||
#ifdef QB64_MACOSX
|
||||
#include <GLUT/glut.h>
|
||||
#include <OpenGL/gl.h>
|
||||
#else
|
||||
#include <GL/glut.h>
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
#ifdef QB64_WINDOWS
|
||||
#include "src/Gamepad_windows.c"
|
||||
#else
|
||||
#ifdef QB64_MACOSX
|
||||
#include "src/Gamepad_macosx.c"
|
||||
#else
|
||||
//assume LINUX
|
||||
#include "src/Gamepad_linux.c"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* these shouldn't be necessary
|
||||
#include "src/shell/Shell.h"
|
||||
#include "src/shell/ShellKeyCodes.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;
|
||||
};
|
||||
*/
|
||||
|
||||
static int verbose = 1; //whether printf prints out information about events
|
||||
|
||||
//"It appears to define some callbacks here"
|
||||
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);
|
||||
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
|
||||
|
||||
uint8 *cp,*cp2;
|
||||
if (d->queued_events==d->max_events){//expand/shift event buffer
|
||||
if (d->max_events>=QUEUED_EVENTS_LIMIT){
|
||||
//discard base message
|
||||
memmove(d->events,d->events+d->event_size,(d->queued_events-1)*d->event_size);
|
||||
d->queued_events--;
|
||||
}else{
|
||||
cp=(uint8*)calloc(d->max_events*2,d->event_size);
|
||||
memcpy(cp,d->events,d->queued_events*d->event_size);//copy existing events
|
||||
cp2=d->events;
|
||||
d->events=cp;
|
||||
free(cp2);
|
||||
d->max_events*=2;
|
||||
}
|
||||
}
|
||||
memmove(d->events+d->queued_events*d->event_size,d->events+(d->queued_events-1)*d->event_size,d->event_size);//duplicate last event
|
||||
*(int64*)(d->events+(d->queued_events*d->event_size)+(d->event_size-8))=device_event_index++;//store global event index
|
||||
//make required changes
|
||||
*(d->events+(d->queued_events*d->event_size)+button)=1;
|
||||
d->queued_events++;
|
||||
//set STRIG_button_pressed for button
|
||||
if (button>=0&&button<=255){
|
||||
d->STRIG_button_pressed[button]=1;
|
||||
}
|
||||
}//js index
|
||||
}//type==1
|
||||
}//used
|
||||
}//di
|
||||
|
||||
bool onButtonDown(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_buttonEvent * event;
|
||||
|
||||
event = eventData;
|
||||
if (verbose) {
|
||||
printf("Button %u down (%d) on device %u at %f\n", event->buttonID, (int) event->down, event->device->deviceID, event->timestamp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool onButtonUp(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_buttonEvent * event;
|
||||
|
||||
event = eventData;
|
||||
if (verbose) {
|
||||
printf("Button %u up (%d) on device %u at %f\n", event->buttonID, (int) event->down, event->device->deviceID, event->timestamp);
|
||||
}
|
||||
return true;
|
||||
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);
|
||||
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){
|
||||
uint8 *cp,*cp2;
|
||||
if (d->queued_events==d->max_events){//expand/shift event buffer
|
||||
if (d->max_events>=QUEUED_EVENTS_LIMIT){
|
||||
//discard base message
|
||||
memmove(d->events,d->events+d->event_size,(d->queued_events-1)*d->event_size);
|
||||
d->queued_events--;
|
||||
}else{
|
||||
cp=(uint8*)calloc(d->max_events*2,d->event_size);
|
||||
memcpy(cp,d->events,d->queued_events*d->event_size);//copy existing events
|
||||
cp2=d->events;
|
||||
d->events=cp;
|
||||
free(cp2);
|
||||
d->max_events*=2;
|
||||
}
|
||||
}
|
||||
memmove(d->events+d->queued_events*d->event_size,d->events+(d->queued_events-1)*d->event_size,d->event_size);//duplicate last event
|
||||
*(int64*)(d->events+(d->queued_events*d->event_size)+(d->event_size-8))=device_event_index++;//store global event index
|
||||
//make required changes
|
||||
*(d->events+(d->queued_events*d->event_size)+button)=0;
|
||||
d->queued_events++;
|
||||
}//js index
|
||||
}//type==1
|
||||
}//used
|
||||
}//di
|
||||
|
||||
}
|
||||
|
||||
bool onAxisMoved(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_axisEvent * event;
|
||||
|
||||
event = eventData;
|
||||
if (verbose) {
|
||||
printf("Axis %u moved to %f on device %u at %f\n", event->axisID, event->value, event->device->deviceID, event->timestamp);
|
||||
}
|
||||
return true;
|
||||
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);
|
||||
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){
|
||||
uint8 *cp,*cp2;
|
||||
if (d->queued_events==d->max_events){//expand/shift event buffer
|
||||
if (d->max_events>=QUEUED_EVENTS_LIMIT){
|
||||
//discard base message
|
||||
memmove(d->events,d->events+d->event_size,(d->queued_events-1)*d->event_size);
|
||||
d->queued_events--;
|
||||
}else{
|
||||
cp=(uint8*)calloc(d->max_events*2,d->event_size);
|
||||
memcpy(cp,d->events,d->queued_events*d->event_size);//copy existing events
|
||||
cp2=d->events;
|
||||
d->events=cp;
|
||||
free(cp2);
|
||||
d->max_events*=2;
|
||||
}
|
||||
}
|
||||
memmove(d->events+d->queued_events*d->event_size,d->events+(d->queued_events-1)*d->event_size,d->event_size);//duplicate last event
|
||||
*(int64*)(d->events+(d->queued_events*d->event_size)+(d->event_size-8))=device_event_index++;//store global event index
|
||||
//make required changes
|
||||
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 o;
|
||||
o=d->lastbutton+axis*4;
|
||||
*(float*)(d->events+(d->queued_events*d->event_size)+o)=f;
|
||||
d->queued_events++;
|
||||
}//js index
|
||||
}//type==1
|
||||
}//used
|
||||
}//di
|
||||
|
||||
}
|
||||
|
||||
bool onDeviceAttached(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_device * device;
|
||||
|
||||
device = eventData;
|
||||
if (verbose) {
|
||||
printf("Device ID %u attached (vendor = 0x%X; product = 0x%X)\n", device->deviceID, device->vendorID, device->productID);
|
||||
}
|
||||
device->eventDispatcher->registerForEvent(device->eventDispatcher, GAMEPAD_EVENT_BUTTON_DOWN, onButtonDown, device);
|
||||
device->eventDispatcher->registerForEvent(device->eventDispatcher, GAMEPAD_EVENT_BUTTON_UP, onButtonUp, device);
|
||||
device->eventDispatcher->registerForEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, onAxisMoved, device);
|
||||
return true;
|
||||
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);
|
||||
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;
|
||||
//}
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool onDeviceRemoved(void * sender, const char * eventID, void * eventData, void * context) {
|
||||
struct Gamepad_device * device;
|
||||
|
||||
device = eventData;
|
||||
if (verbose) {
|
||||
printf("Device ID %u removed\n", device->deviceID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}//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=1;
|
||||
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);
|
||||
//calculate queue message size
|
||||
x=devices[i].lastbutton+(devices[i].lastaxis+devices[i].lastwheel)*4+8;
|
||||
devices[i].event_size=x;
|
||||
//create initial 'current' and 'previous' events
|
||||
devices[i].events=(uint8*)calloc(2,x);
|
||||
devices[i].max_events=2;
|
||||
devices[i].queued_events=2;
|
||||
devices[i].connected=1;
|
||||
devices[i].used=1;
|
||||
device_last=i;
|
||||
|
||||
}
|
||||
|
||||
const char * Target_getName() {
|
||||
return "Gamepad test harness";
|
||||
void onDeviceRemoved(struct Gamepad_device * device, void * context) {
|
||||
if (verbose) {
|
||||
sprintf(verboseMessage,"Device ID %u removed with context %p\n", device->deviceID, context);
|
||||
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
|
||||
|
||||
|
||||
}
|
||||
|
||||
//"initialization code is here, in its own function..."
|
||||
static void initGamepad() {
|
||||
Gamepad_eventDispatcher()->registerForEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, onDeviceAttached, NULL);
|
||||
Gamepad_eventDispatcher()->registerForEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_REMOVED, onDeviceRemoved, NULL);
|
||||
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_GameControllerInit(){
|
||||
initGamepad();
|
||||
void QB64_GAMEPAD_INIT(){
|
||||
initGamepad();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------EVERYTHING PAST HERE IS FLUFF ----------------------------
|
||||
// (and has been commented out!)
|
||||
/*
|
||||
|
||||
//"OMG wtf is this function????? some kind of glutty, shelly thing-a-me-bob"
|
||||
static unsigned int windowWidth = 800, windowHeight = 600;
|
||||
|
||||
void Target_init(int argc, char ** argv) {
|
||||
int argIndex;
|
||||
|
||||
for (argIndex = 1; argIndex < argc; argIndex++) {
|
||||
if (!strcmp(argv[argIndex], "-v")) {
|
||||
verbose = true;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
Shell_mainLoop();
|
||||
void QB64_GAMEPAD_POLL(){
|
||||
Gamepad_detectDevices();
|
||||
Gamepad_processEvents();
|
||||
}
|
||||
|
||||
//"why is this even here?"
|
||||
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]);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
#define POLL_ITERATION_INTERVAL 30
|
||||
|
||||
void Target_draw() {
|
||||
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");
|
||||
}
|
||||
|
||||
Shell_redisplay();
|
||||
}
|
||||
|
||||
void Target_keyDown(int charCode, int keyCode) {
|
||||
if (keyCode == KEYBOARD_R) {
|
||||
Gamepad_shutdown();
|
||||
initGamepad();
|
||||
}
|
||||
}
|
||||
|
||||
void Target_keyUp(int charCode, int keyCode) {
|
||||
}
|
||||
|
||||
void Target_mouseDown(int buttonNumber, float x, float y) {
|
||||
}
|
||||
|
||||
void Target_mouseUp(int buttonNumber, float x, float y) {
|
||||
}
|
||||
|
||||
void Target_mouseMoved(float x, float y) {
|
||||
}
|
||||
|
||||
void Target_mouseDragged(int buttonMask, float x, float y) {
|
||||
}
|
||||
|
||||
void Target_resized(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);
|
||||
}
|
||||
*/
|
|
@ -1,440 +1,454 @@
|
|||
/*
|
||||
Copyright (c) 2010 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 adiener@sacredsoftware.net
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.h"
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <linux/input.h>
|
||||
#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 {
|
||||
EventDispatcher * dispatcher;
|
||||
const char * 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 EventDispatcher * eventDispatcher = NULL;
|
||||
static bool inited = false;
|
||||
|
||||
#define test_bit(bitIndex, array) \
|
||||
((array[(bitIndex) / (sizeof(int) * 8)] >> ((bitIndex) % (sizeof(int) * 8))) & 0x1)
|
||||
|
||||
static char ** findGamepadPaths(unsigned int * outNumGamepads) {
|
||||
DIR * dev_input;
|
||||
struct dirent * entity;
|
||||
unsigned int numGamepads = 0;
|
||||
char ** gamepadDevs = NULL;
|
||||
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];
|
||||
|
||||
dev_input = opendir("/dev/input");
|
||||
if (dev_input != NULL) {
|
||||
for (entity = readdir(dev_input); entity != NULL; entity = readdir(dev_input)) {
|
||||
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);
|
||||
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;
|
||||
}
|
||||
close(fd);
|
||||
|
||||
numGamepads++;
|
||||
gamepadDevs = realloc(gamepadDevs, sizeof(char *) * numGamepads);
|
||||
gamepadDevs[numGamepads - 1] = malloc(strlen(fileName) + 1);
|
||||
strcpy(gamepadDevs[numGamepads - 1], fileName);
|
||||
}
|
||||
}
|
||||
closedir(dev_input);
|
||||
}
|
||||
|
||||
*outNumGamepads = numGamepads;
|
||||
return gamepadDevs;
|
||||
}
|
||||
|
||||
void Gamepad_init() {
|
||||
if (!inited) {
|
||||
pthread_mutex_init(&devicesMutex, NULL);
|
||||
pthread_mutex_init(&eventQueueMutex, NULL);
|
||||
inited = true;
|
||||
Gamepad_detectDevices();
|
||||
}
|
||||
}
|
||||
|
||||
static void disposeDevice(struct Gamepad_device * device) {
|
||||
device->eventDispatcher->dispose(device->eventDispatcher);
|
||||
|
||||
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->eventDispatcher);
|
||||
|
||||
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 (!strcmp(eventQueue[eventIndex].eventType, GAMEPAD_EVENT_DEVICE_REMOVED)) {
|
||||
disposeDevice(eventQueue[eventIndex].eventData);
|
||||
}
|
||||
}
|
||||
|
||||
eventQueueSize = 0;
|
||||
eventCount = 0;
|
||||
free(eventQueue);
|
||||
eventQueue = NULL;
|
||||
|
||||
if (eventDispatcher != NULL) {
|
||||
eventDispatcher->dispose(eventDispatcher);
|
||||
free(eventDispatcher);
|
||||
eventDispatcher = NULL;
|
||||
}
|
||||
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
EventDispatcher * Gamepad_eventDispatcher() {
|
||||
if (eventDispatcher == NULL) {
|
||||
eventDispatcher = EventDispatcher_create(NULL);
|
||||
}
|
||||
return eventDispatcher;
|
||||
}
|
||||
|
||||
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(EventDispatcher * dispatcher, const char * eventType, void * eventData) {
|
||||
struct Gamepad_queuedEvent queuedEvent;
|
||||
|
||||
queuedEvent.dispatcher = dispatcher;
|
||||
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) {
|
||||
struct Gamepad_axisEvent * axisEvent;
|
||||
|
||||
axisEvent = malloc(sizeof(struct Gamepad_axisEvent));
|
||||
axisEvent->device = device;
|
||||
axisEvent->timestamp = timestamp;
|
||||
axisEvent->axisID = axisID;
|
||||
axisEvent->value = value;
|
||||
|
||||
queueEvent(device->eventDispatcher, 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->eventDispatcher, 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]] = 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(eventDispatcher, 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() {
|
||||
unsigned int numPaths;
|
||||
char ** gamepadPaths;
|
||||
bool duplicate;
|
||||
unsigned int pathIndex, gamepadIndex;
|
||||
struct stat statBuf;
|
||||
struct Gamepad_device * deviceRecord;
|
||||
struct Gamepad_devicePrivate * deviceRecordPrivate;
|
||||
int fd;
|
||||
char name[128];
|
||||
char * description;
|
||||
int evKeyBits[(KEY_CNT - 1) / sizeof(int) * 8 + 1];
|
||||
int evAbsBits[(ABS_CNT - 1) / sizeof(int) * 8 + 1];
|
||||
int bit;
|
||||
struct input_id id;
|
||||
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
gamepadPaths = findGamepadPaths(&numPaths);
|
||||
|
||||
pthread_mutex_lock(&devicesMutex);
|
||||
for (pathIndex = 0; pathIndex < numPaths; pathIndex++) {
|
||||
duplicate = false;
|
||||
for (gamepadIndex = 0; gamepadIndex < numDevices; gamepadIndex++) {
|
||||
if (!strcmp(((struct Gamepad_devicePrivate *) devices[gamepadIndex]->privateData)->path, gamepadPaths[pathIndex])) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate) {
|
||||
free(gamepadPaths[pathIndex]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!stat(gamepadPaths[pathIndex], &statBuf)) {
|
||||
deviceRecord = malloc(sizeof(struct Gamepad_device));
|
||||
deviceRecord->deviceID = nextDeviceID++;
|
||||
deviceRecord->eventDispatcher = EventDispatcher_create(deviceRecord);
|
||||
devices = realloc(devices, sizeof(struct Gamepad_device *) * (numDevices + 1));
|
||||
devices[numDevices++] = deviceRecord;
|
||||
|
||||
fd = open(gamepadPaths[pathIndex], O_RDONLY, 0);
|
||||
|
||||
deviceRecordPrivate = malloc(sizeof(struct Gamepad_devicePrivate));
|
||||
deviceRecordPrivate->fd = fd;
|
||||
deviceRecordPrivate->path = gamepadPaths[pathIndex];
|
||||
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(gamepadPaths[pathIndex] + 1));
|
||||
strcpy(description, gamepadPaths[pathIndex]);
|
||||
}
|
||||
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);
|
||||
|
||||
Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, deviceRecord);
|
||||
|
||||
pthread_create(&deviceRecordPrivate->thread, NULL, deviceThread, deviceRecord);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&devicesMutex);
|
||||
}
|
||||
|
||||
void Gamepad_processEvents() {
|
||||
unsigned int eventIndex;
|
||||
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&eventQueueMutex);
|
||||
for (eventIndex = 0; eventIndex < eventCount; eventIndex++) {
|
||||
eventQueue[eventIndex].dispatcher->dispatchEvent(eventQueue[eventIndex].dispatcher, eventQueue[eventIndex].eventType, eventQueue[eventIndex].eventData);
|
||||
if (!strcmp(eventQueue[eventIndex].eventType, GAMEPAD_EVENT_DEVICE_REMOVED)) {
|
||||
disposeDevice(eventQueue[eventIndex].eventData);
|
||||
}
|
||||
}
|
||||
eventCount = 0;
|
||||
pthread_mutex_unlock(&eventQueueMutex);
|
||||
}
|
||||
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
61
internal/c/parts/input/game_controller/src/Gamepad_private.c
Normal file
61
internal/c/parts/input/game_controller/src/Gamepad_private.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
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,416 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2010 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 adiener@sacredsoftware.net
|
||||
*/
|
||||
|
||||
#include "gamepad/Gamepad.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 EventDispatcher * eventDispatcher = NULL;
|
||||
static bool inited = false;
|
||||
|
||||
void Gamepad_init() {
|
||||
if (!inited) {
|
||||
inited = true;
|
||||
Gamepad_detectDevices();
|
||||
}
|
||||
}
|
||||
|
||||
static void disposeDevice(struct Gamepad_device * deviceRecord) {
|
||||
deviceRecord->eventDispatcher->dispose(deviceRecord->eventDispatcher);
|
||||
|
||||
free(((struct Gamepad_devicePrivate *) deviceRecord->privateData)->axisRanges);
|
||||
free(deviceRecord->privateData);
|
||||
|
||||
free((void *) deviceRecord->description);
|
||||
free(deviceRecord->axisStates);
|
||||
free(deviceRecord->buttonStates);
|
||||
free(deviceRecord->eventDispatcher);
|
||||
|
||||
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;
|
||||
if (eventDispatcher != NULL) {
|
||||
eventDispatcher->dispose(eventDispatcher);
|
||||
free(eventDispatcher);
|
||||
eventDispatcher = NULL;
|
||||
}
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
EventDispatcher * Gamepad_eventDispatcher() {
|
||||
if (eventDispatcher == NULL) {
|
||||
eventDispatcher = EventDispatcher_create(NULL);
|
||||
}
|
||||
return eventDispatcher;
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
deviceRecord->eventDispatcher = EventDispatcher_create(deviceRecord);
|
||||
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;
|
||||
|
||||
Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_ATTACHED, deviceRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 value) {
|
||||
struct Gamepad_axisEvent axisEvent;
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
|
||||
if (axisIndex < 0 || axisIndex >= (int) device->numAxes) {
|
||||
return;
|
||||
}
|
||||
|
||||
devicePrivate = device->privateData;
|
||||
|
||||
axisEvent.device = device;
|
||||
axisEvent.timestamp = currentTime();
|
||||
axisEvent.axisID = axisIndex;
|
||||
axisEvent.value = (value - devicePrivate->axisRanges[axisIndex][0]) / (float) (devicePrivate->axisRanges[axisIndex][1] - devicePrivate->axisRanges[axisIndex][0]) * 2.0f - 1.0f;
|
||||
|
||||
device->axisStates[axisIndex] = axisEvent.value;
|
||||
device->eventDispatcher->dispatchEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, &axisEvent);
|
||||
}
|
||||
|
||||
static void handleButtonChange(struct Gamepad_device * device, DWORD lastValue, DWORD value) {
|
||||
struct Gamepad_buttonEvent buttonEvent;
|
||||
unsigned int buttonIndex;
|
||||
|
||||
for (buttonIndex = 0; buttonIndex < device->numButtons; buttonIndex++) {
|
||||
if ((lastValue ^ value) & (1 << buttonIndex)) {
|
||||
buttonEvent.device = device;
|
||||
buttonEvent.timestamp = currentTime();
|
||||
buttonEvent.buttonID = buttonIndex;
|
||||
buttonEvent.down = !!(value & (1 << buttonIndex));
|
||||
|
||||
device->buttonStates[buttonIndex] = buttonEvent.down;
|
||||
device->eventDispatcher->dispatchEvent(device->eventDispatcher, buttonEvent.down ? GAMEPAD_EVENT_BUTTON_DOWN : GAMEPAD_EVENT_BUTTON_UP, &buttonEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
struct Gamepad_axisEvent axisEvent;
|
||||
|
||||
devicePrivate = device->privateData;
|
||||
|
||||
if (devicePrivate->povXAxisIndex == -1 || devicePrivate->povYAxisIndex == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
povToXY(lastValue, &lastX, &lastY);
|
||||
povToXY(value, &newX, &newY);
|
||||
|
||||
if (newX != lastX) {
|
||||
axisEvent.device = device;
|
||||
axisEvent.timestamp = currentTime();
|
||||
axisEvent.axisID = devicePrivate->povXAxisIndex;
|
||||
axisEvent.value = newX;
|
||||
|
||||
device->axisStates[devicePrivate->povXAxisIndex] = axisEvent.value;
|
||||
device->eventDispatcher->dispatchEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, &axisEvent);
|
||||
}
|
||||
if (newY != lastY) {
|
||||
axisEvent.device = device;
|
||||
axisEvent.timestamp = currentTime();
|
||||
axisEvent.axisID = devicePrivate->povYAxisIndex;
|
||||
axisEvent.value = newY;
|
||||
|
||||
device->axisStates[devicePrivate->povYAxisIndex] = axisEvent.value;
|
||||
device->eventDispatcher->dispatchEvent(device->eventDispatcher, GAMEPAD_EVENT_AXIS_MOVED, &axisEvent);
|
||||
}
|
||||
}
|
||||
|
||||
void Gamepad_processEvents() {
|
||||
unsigned int deviceIndex;
|
||||
JOYINFOEX info;
|
||||
MMRESULT result;
|
||||
struct Gamepad_device * device;
|
||||
struct Gamepad_devicePrivate * devicePrivate;
|
||||
|
||||
if (!inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
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) {
|
||||
Gamepad_eventDispatcher()->dispatchEvent(Gamepad_eventDispatcher(), GAMEPAD_EVENT_DEVICE_REMOVED, device);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
1055
internal/c/parts/input/game_controller/src/Gamepad_windows_dinput.c
Normal file
1055
internal/c/parts/input/game_controller/src/Gamepad_windows_dinput.c
Normal file
File diff suppressed because it is too large
Load diff
400
internal/c/parts/input/game_controller/src/Gamepad_windows_mm.c
Normal file
400
internal/c/parts/input/game_controller/src/Gamepad_windows_mm.c
Normal file
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
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 +1,128 @@
|
|||
/*
|
||||
Copyright (c) 2010 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 adiener@sacredsoftware.net
|
||||
*/
|
||||
|
||||
#ifndef __GAMEPAD_H__
|
||||
#define __GAMEPAD_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "utilities/EventDispatcher.h"
|
||||
|
||||
// eventData -> struct Gamepad_device
|
||||
#define GAMEPAD_EVENT_DEVICE_ATTACHED "GAMEPAD_EVENT_DEVICE_ATTACHED" // Only dispatched when Gamepad_init or Gamepad_detectDevices is called
|
||||
#define GAMEPAD_EVENT_DEVICE_REMOVED "GAMEPAD_EVENT_DEVICE_REMOVED" // Can be dispatched at any time
|
||||
|
||||
// eventData -> struct Gamepad_buttonEvent
|
||||
#define GAMEPAD_EVENT_BUTTON_DOWN "GAMEPAD_EVENT_BUTTON_DOWN" // Only dispatched when Gamepad_processEvents is called
|
||||
#define GAMEPAD_EVENT_BUTTON_UP "GAMEPAD_EVENT_BUTTON_UP" // Only dispatched when Gamepad_processEvents is called
|
||||
|
||||
// eventData -> struct Gamepad_axisEvent
|
||||
#define GAMEPAD_EVENT_AXIS_MOVED "GAMEPAD_EVENT_AXIS_MOVED" // Only dispatched when Gamepad_processEvents is called
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct Gamepad_device {
|
||||
// Unique device identifier for application session. 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;
|
||||
|
||||
// Broadcasts GAMEPAD_EVENT_BUTTON_DOWN, GAMEPAD_EVENT_BUTTON_UP, and GAMEPAD_EVENT_AXIS_MOVED
|
||||
EventDispatcher * eventDispatcher;
|
||||
|
||||
// Platform-specific device data storage; don't mess with it
|
||||
void * privateData;
|
||||
};
|
||||
|
||||
/* Initializes gamepad library and detects initial devices. Call this before any other Gamepad_*()
|
||||
function, EXCEPT Gamepad_eventDispatcher(). In order to get receive GAMEPAD_EVENT_DEVICE_ATTACHED
|
||||
events from devices detected in Gamepad_init(), you must register handlers for those events before
|
||||
calling Gamepad_init(). */
|
||||
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. */
|
||||
void Gamepad_shutdown();
|
||||
|
||||
/* EventDispatcher used by gamepad library to broadcast GAMEPAD_EVENT_DEVICE_ATTACHED and
|
||||
GAMEPAD_EVENT_DEVICE_REMOVED events. */
|
||||
EventDispatcher * Gamepad_eventDispatcher();
|
||||
|
||||
/* 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, a GAMEPAD_EVENT_DEVICE_ATTACHED event will be
|
||||
broadcast via Gamepad_eventDispatcher() for each one. */
|
||||
void Gamepad_detectDevices();
|
||||
|
||||
/* Reads pending input from all attached devices and broadcasts GAMEPAD_EVENT_BUTTON_DOWN,
|
||||
GAMEPAD_EVENT_BUTTON_UP, and GAMEPAD_EVENT_AXIS_MOVED events through the eventDispatcher of the
|
||||
device that generated the event. */
|
||||
void Gamepad_processEvents();
|
||||
|
||||
#endif
|
||||
/*
|
||||
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
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
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,10 +0,0 @@
|
|||
#ifndef __SHELL_H__
|
||||
#define __SHELL_H__
|
||||
|
||||
void Shell_mainLoop();
|
||||
void Shell_redisplay();
|
||||
|
||||
double Shell_getCurrentTime();
|
||||
const char * Shell_getResourcePath();
|
||||
|
||||
#endif
|
|
@ -1,176 +0,0 @@
|
|||
// Adapted from GameShell (http://onesadcookie.com/svn/GameShell/Source/Common/GSKeyCodesInternal.h). Thanks Keith!
|
||||
|
||||
#ifndef __SHELL_KEY_CODES_H__
|
||||
#define __SHELL_KEY_CODES_H__
|
||||
|
||||
#define KEYBOARD_A 0x04
|
||||
#define KEYBOARD_B 0x05
|
||||
#define KEYBOARD_C 0x06
|
||||
#define KEYBOARD_D 0x07
|
||||
#define KEYBOARD_E 0x08
|
||||
#define KEYBOARD_F 0x09
|
||||
#define KEYBOARD_G 0x0A
|
||||
#define KEYBOARD_H 0x0B
|
||||
#define KEYBOARD_I 0x0C
|
||||
#define KEYBOARD_J 0x0D
|
||||
#define KEYBOARD_K 0x0E
|
||||
#define KEYBOARD_L 0x0F
|
||||
#define KEYBOARD_M 0x10
|
||||
#define KEYBOARD_N 0x11
|
||||
#define KEYBOARD_O 0x12
|
||||
#define KEYBOARD_P 0x13
|
||||
#define KEYBOARD_Q 0x14
|
||||
#define KEYBOARD_R 0x15
|
||||
#define KEYBOARD_S 0x16
|
||||
#define KEYBOARD_T 0x17
|
||||
#define KEYBOARD_U 0x18
|
||||
#define KEYBOARD_V 0x19
|
||||
#define KEYBOARD_W 0x1A
|
||||
#define KEYBOARD_X 0x1B
|
||||
#define KEYBOARD_Y 0x1C
|
||||
#define KEYBOARD_Z 0x1D
|
||||
#define KEYBOARD_1 0x1E
|
||||
#define KEYBOARD_2 0x1F
|
||||
#define KEYBOARD_3 0x20
|
||||
#define KEYBOARD_4 0x21
|
||||
#define KEYBOARD_5 0x22
|
||||
#define KEYBOARD_6 0x23
|
||||
#define KEYBOARD_7 0x24
|
||||
#define KEYBOARD_8 0x25
|
||||
#define KEYBOARD_9 0x26
|
||||
#define KEYBOARD_0 0x27
|
||||
#define KEYBOARD_RETURN_OR_ENTER 0x28
|
||||
#define KEYBOARD_ESCAPE 0x29
|
||||
#define KEYBOARD_DELETE_OR_BACKSPACE 0x2A
|
||||
#define KEYBOARD_TAB 0x2B
|
||||
#define KEYBOARD_SPACEBAR 0x2C
|
||||
#define KEYBOARD_HYPHEN 0x2D
|
||||
#define KEYBOARD_EQUAL_SIGN 0x2E
|
||||
#define KEYBOARD_OPEN_BRACKET 0x2F
|
||||
#define KEYBOARD_CLOSE_BRACKET 0x30
|
||||
#define KEYBOARD_BACKSLASH 0x31
|
||||
#define KEYBOARD_NON_USPOUND 0x32
|
||||
#define KEYBOARD_SEMICOLON 0x33
|
||||
#define KEYBOARD_QUOTE 0x34
|
||||
#define KEYBOARD_GRAVE_ACCENT_AND_TILDE 0x35
|
||||
#define KEYBOARD_COMMA 0x36
|
||||
#define KEYBOARD_PERIOD 0x37
|
||||
#define KEYBOARD_SLASH 0x38
|
||||
#define KEYBOARD_CAPS_LOCK 0x39
|
||||
#define KEYBOARD_F1 0x3A
|
||||
#define KEYBOARD_F2 0x3B
|
||||
#define KEYBOARD_F3 0x3C
|
||||
#define KEYBOARD_F4 0x3D
|
||||
#define KEYBOARD_F5 0x3E
|
||||
#define KEYBOARD_F6 0x3F
|
||||
#define KEYBOARD_F7 0x40
|
||||
#define KEYBOARD_F8 0x41
|
||||
#define KEYBOARD_F9 0x42
|
||||
#define KEYBOARD_F10 0x43
|
||||
#define KEYBOARD_F11 0x44
|
||||
#define KEYBOARD_F12 0x45
|
||||
#define KEYBOARD_PRINT_SCREEN 0x46
|
||||
#define KEYBOARD_SCROLL_LOCK 0x47
|
||||
#define KEYBOARD_PAUSE 0x48
|
||||
#define KEYBOARD_INSERT 0x49
|
||||
#define KEYBOARD_HOME 0x4A
|
||||
#define KEYBOARD_PAGE_UP 0x4B
|
||||
#define KEYBOARD_DELETE_FORWARD 0x4C
|
||||
#define KEYBOARD_END 0x4D
|
||||
#define KEYBOARD_PAGE_DOWN 0x4E
|
||||
#define KEYBOARD_RIGHT_ARROW 0x4F
|
||||
#define KEYBOARD_LEFT_ARROW 0x50
|
||||
#define KEYBOARD_DOWN_ARROW 0x51
|
||||
#define KEYBOARD_UP_ARROW 0x52
|
||||
#define KEYPAD_NUM_LOCK 0x53
|
||||
#define KEYPAD_SLASH 0x54
|
||||
#define KEYPAD_ASTERISK 0x55
|
||||
#define KEYPAD_HYPHEN 0x56
|
||||
#define KEYPAD_PLUS 0x57
|
||||
#define KEYPAD_ENTER 0x58
|
||||
#define KEYPAD_1 0x59
|
||||
#define KEYPAD_2 0x5A
|
||||
#define KEYPAD_3 0x5B
|
||||
#define KEYPAD_4 0x5C
|
||||
#define KEYPAD_5 0x5D
|
||||
#define KEYPAD_6 0x5E
|
||||
#define KEYPAD_7 0x5F
|
||||
#define KEYPAD_8 0x60
|
||||
#define KEYPAD_9 0x61
|
||||
#define KEYPAD_0 0x62
|
||||
#define KEYPAD_PERIOD 0x63
|
||||
#define KEYBOARD_NON_US_BACKSLASH 0x64
|
||||
#define KEYBOARD_APPLICATION 0x65
|
||||
#define KEYBOARD_POWER 0x66
|
||||
#define KEYPAD_EQUAL_SIGN 0x67
|
||||
#define KEYBOARD_F13 0x68
|
||||
#define KEYBOARD_F14 0x69
|
||||
#define KEYBOARD_F15 0x6A
|
||||
#define KEYBOARD_F16 0x6B
|
||||
#define KEYBOARD_F17 0x6C
|
||||
#define KEYBOARD_F18 0x6D
|
||||
#define KEYBOARD_F19 0x6E
|
||||
#define KEYBOARD_F20 0x6F
|
||||
#define KEYBOARD_F21 0x70
|
||||
#define KEYBOARD_F22 0x71
|
||||
#define KEYBOARD_F23 0x72
|
||||
#define KEYBOARD_F24 0x73
|
||||
#define KEYBOARD_EXECUTE 0x74
|
||||
#define KEYBOARD_HELP 0x75
|
||||
#define KEYBOARD_MENU 0x76
|
||||
#define KEYBOARD_SELECT 0x77
|
||||
#define KEYBOARD_STOP 0x78
|
||||
#define KEYBOARD_AGAIN 0x79
|
||||
#define KEYBOARD_UNDO 0x7A
|
||||
#define KEYBOARD_CUT 0x7B
|
||||
#define KEYBOARD_COPY 0x7C
|
||||
#define KEYBOARD_PASTE 0x7D
|
||||
#define KEYBOARD_FIND 0x7E
|
||||
#define KEYBOARD_MUTE 0x7F
|
||||
#define KEYBOARD_VOLUME_UP 0x80
|
||||
#define KEYBOARD_VOLUME_DOWN 0x81
|
||||
#define KEYBOARD_LOCKING_CAPS_LOCK 0x82
|
||||
#define KEYBOARD_LOCKING_NUM_LOCK 0x83
|
||||
#define KEYBOARD_LOCKING_SCROLL_LOCK 0x84
|
||||
#define KEYPAD_COMMA 0x85
|
||||
#define KEYPAD_EQUAL_SIGN_AS400 0x86
|
||||
#define KEYBOARD_INTERNATIONAL_1 0x87
|
||||
#define KEYBOARD_INTERNATIONAL_2 0x88
|
||||
#define KEYBOARD_INTERNATIONAL_3 0x89
|
||||
#define KEYBOARD_INTERNATIONAL_4 0x8A
|
||||
#define KEYBOARD_INTERNATIONAL_5 0x8B
|
||||
#define KEYBOARD_INTERNATIONAL_6 0x8C
|
||||
#define KEYBOARD_INTERNATIONAL_7 0x8D
|
||||
#define KEYBOARD_INTERNATIONAL_8 0x8E
|
||||
#define KEYBOARD_INTERNATIONAL_9 0x8F
|
||||
#define KEYBOARD_LANG1 0x90
|
||||
#define KEYBOARD_LANG2 0x91
|
||||
#define KEYBOARD_LANG3 0x92
|
||||
#define KEYBOARD_LANG4 0x93
|
||||
#define KEYBOARD_LANG5 0x94
|
||||
#define KEYBOARD_LANG6 0x95
|
||||
#define KEYBOARD_LANG7 0x96
|
||||
#define KEYBOARD_LANG8 0x97
|
||||
#define KEYBOARD_LANG9 0x98
|
||||
#define KEYBOARD_ALTERNATE_ERASE 0x99
|
||||
#define KEYBOARD_SYS_REQ_OR_ATTENTION 0x9A
|
||||
#define KEYBOARD_CANCEL 0x9B
|
||||
#define KEYBOARD_CLEAR 0x9C
|
||||
#define KEYBOARD_PRIOR 0x9D
|
||||
#define KEYBOARD_RETURN 0x9E
|
||||
#define KEYBOARD_SEPARATOR 0x9F
|
||||
#define KEYBOARD_OUT 0xA0
|
||||
#define KEYBOARD_OPER 0xA1
|
||||
#define KEYBOARD_CLEAR_OR_AGAIN 0xA2
|
||||
#define KEYBOARD_CR_SEL_OR_PROPS 0xA3
|
||||
#define KEYBOARD_EX_SEL 0xA4
|
||||
#define KEYBOARD_LEFT_CONTROL 0xE0
|
||||
#define KEYBOARD_LEFT_SHIFT 0xE1
|
||||
#define KEYBOARD_LEFT_ALT 0xE2
|
||||
#define KEYBOARD_LEFT_GUI 0xE3
|
||||
#define KEYBOARD_RIGHT_CONTROL 0xE4
|
||||
#define KEYBOARD_RIGHT_SHIFT 0xE5
|
||||
#define KEYBOARD_RIGHT_ALT 0xE6
|
||||
#define KEYBOARD_RIGHT_GUI 0xE7
|
||||
|
||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef __TARGET_H__
|
||||
#define __TARGET_H__
|
||||
|
||||
const char * Target_getName();
|
||||
|
||||
void Target_init(int argc, char ** argv);
|
||||
void Target_draw();
|
||||
|
||||
void Target_keyDown(int charCode, int keyCode);
|
||||
void Target_keyUp(int charCode, int keyCode);
|
||||
void Target_mouseDown(int buttonNumber, float x, float y);
|
||||
void Target_mouseUp(int buttonNumber, float x, float y);
|
||||
void Target_mouseMoved(float x, float y);
|
||||
void Target_mouseDragged(int buttonMask, float x, float y);
|
||||
|
||||
void Target_resized(int newWidth, int newHeight);
|
||||
|
||||
#endif
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2010 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 adiener@sacredsoftware.net
|
||||
*/
|
||||
|
||||
#include "utilities/EventDispatcher.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct EventTarget {
|
||||
char * eventID;
|
||||
EventDispatcherCallback callback;
|
||||
void * context;
|
||||
};
|
||||
|
||||
EventDispatcher * EventDispatcher_create(void * owner) {
|
||||
EventDispatcher * self;
|
||||
|
||||
self = malloc(sizeof(EventDispatcher));
|
||||
EventDispatcher_init(self, owner);
|
||||
return self;
|
||||
}
|
||||
|
||||
void EventDispatcher_init(EventDispatcher * self, void * owner) {
|
||||
self->dispose = EventDispatcher_dispose;
|
||||
self->registerForEvent = EventDispatcher_registerForEvent;
|
||||
self->unregisterForEvent = EventDispatcher_unregisterForEvent;
|
||||
self->dispatchEvent = EventDispatcher_dispatchEvent;
|
||||
|
||||
self->owner = owner;
|
||||
self->numberOfTargets = 0;
|
||||
self->targetListSize = 1;
|
||||
self->targets = (struct EventTarget *) malloc(sizeof(struct EventTarget) * self->targetListSize);
|
||||
}
|
||||
|
||||
void EventDispatcher_dispose(void * selfPtr) {
|
||||
EventDispatcher * self = selfPtr;
|
||||
int targetIndex;
|
||||
|
||||
for (targetIndex = 0; targetIndex < self->numberOfTargets; targetIndex++) {
|
||||
free(self->targets[targetIndex].eventID);
|
||||
}
|
||||
free(self->targets);
|
||||
}
|
||||
|
||||
void EventDispatcher_registerForEvent(void * selfPtr, const char * eventID, EventDispatcherCallback callback, void * context) {
|
||||
EventDispatcher * self = selfPtr;
|
||||
size_t length;
|
||||
|
||||
if (self->numberOfTargets >= self->targetListSize) {
|
||||
self->targetListSize *= 2;
|
||||
self->targets = (struct EventTarget *) realloc(self->targets, sizeof(struct EventTarget) * self->targetListSize);
|
||||
}
|
||||
|
||||
length = strlen(eventID);
|
||||
self->targets[self->numberOfTargets].eventID = malloc(length + 1);
|
||||
strncpy(self->targets[self->numberOfTargets].eventID, eventID, length + 1);
|
||||
self->targets[self->numberOfTargets].callback = callback;
|
||||
self->targets[self->numberOfTargets].context = context;
|
||||
self->numberOfTargets++;
|
||||
}
|
||||
|
||||
void EventDispatcher_unregisterForEvent(void * selfPtr, const char * eventID, EventDispatcherCallback callback) {
|
||||
EventDispatcher * self = selfPtr;
|
||||
int targetIndex;
|
||||
|
||||
for (targetIndex = 0; targetIndex < self->numberOfTargets; targetIndex++) {
|
||||
if (!strcmp(eventID, self->targets[targetIndex].eventID) && self->targets[targetIndex].callback == callback) {
|
||||
free(self->targets[targetIndex].eventID);
|
||||
self->numberOfTargets--;
|
||||
for (; targetIndex < self->numberOfTargets; targetIndex++) {
|
||||
self->targets[targetIndex] = self->targets[targetIndex + 1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EventDispatcher_dispatchEvent(void * selfPtr, const char * eventID, void * eventData) {
|
||||
EventDispatcher * self = selfPtr;
|
||||
int targetIndex;
|
||||
int numberOfTargetsCopy;
|
||||
struct EventTarget * targetsCopy;
|
||||
bool eventHandled, anyEventsHandled;
|
||||
|
||||
numberOfTargetsCopy = self->numberOfTargets;
|
||||
targetsCopy = malloc(sizeof(struct EventTarget) * numberOfTargetsCopy);
|
||||
memcpy(targetsCopy, self->targets, sizeof(struct EventTarget) * numberOfTargetsCopy);
|
||||
|
||||
anyEventsHandled = false;
|
||||
for (targetIndex = 0; targetIndex < numberOfTargetsCopy; targetIndex++) {
|
||||
if (!strcmp(eventID, self->targets[targetIndex].eventID)) {
|
||||
eventHandled = targetsCopy[targetIndex].callback(self->owner, eventID, eventData, targetsCopy[targetIndex].context);
|
||||
|
||||
if (eventHandled) {
|
||||
anyEventsHandled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(targetsCopy);
|
||||
|
||||
return anyEventsHandled;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2010 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 adiener@sacredsoftware.net
|
||||
*/
|
||||
|
||||
#ifndef __EVENT_DISPATCHER_H__
|
||||
#define __EVENT_DISPATCHER_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct EventDispatcher EventDispatcher;
|
||||
|
||||
/* Signature for event handler callbacks.
|
||||
|
||||
sender: Object that dispatched the event. More specifically, the object passed to EventDispatcher_create.
|
||||
eventID: Name of event that was triggered
|
||||
eventData: Arbitrary data passed by dispatcher. Its format is known by convention depending on the event ID being dispatched.
|
||||
context: Value passed as context to registerForEvent
|
||||
|
||||
This function should return true if the event was handled, or false if it was ignored. */
|
||||
typedef bool (* EventDispatcherCallback)(void * sender, const char * eventID, void * eventData, void * context);
|
||||
|
||||
struct EventTarget;
|
||||
|
||||
#define EventDispatcher_structContents \
|
||||
void * owner; \
|
||||
\
|
||||
int numberOfTargets; \
|
||||
int targetListSize; \
|
||||
struct EventTarget * targets; \
|
||||
\
|
||||
void (* dispose)(void * self); \
|
||||
void (* registerForEvent)(void * self, const char * eventID, EventDispatcherCallback callback, void * context); \
|
||||
void (* unregisterForEvent)(void * self, const char * eventID, EventDispatcherCallback callback); \
|
||||
bool (* dispatchEvent)(void * self, const char * eventID, void * eventData);
|
||||
|
||||
struct EventDispatcher {
|
||||
EventDispatcher_structContents
|
||||
};
|
||||
|
||||
/* Allocate and initialize a new EventDispatcher object. owner will be passed to event callbacks as
|
||||
the sender parameter. */
|
||||
EventDispatcher * EventDispatcher_create(void * owner);
|
||||
|
||||
/* Initialize an already allocated EventDispatcher. owner will be passed to event callbacks as the
|
||||
sender parameter. */
|
||||
void EventDispatcher_init(EventDispatcher * self, void * owner);
|
||||
|
||||
/* Free all memory allocated by EventDispatcher and remove all registered listeners. Does NOT free
|
||||
the EventDispatcher itself. */
|
||||
void EventDispatcher_dispose(void * selfPtr);
|
||||
|
||||
/* Register for notification of events of type eventID */
|
||||
void EventDispatcher_registerForEvent(void * selfPtr, const char * eventID, EventDispatcherCallback callback, void * context);
|
||||
|
||||
/* Remove a previous registration for events of type eventID */
|
||||
void EventDispatcher_unregisterForEvent(void * selfPtr, const char * eventID, EventDispatcherCallback callback);
|
||||
|
||||
/* Dispatch an event to all registered listeners for that event ID. Returns true if any listener is
|
||||
registered and returns true from its handler callback. */
|
||||
bool EventDispatcher_dispatchEvent(void * selfPtr, const char * eventID, void * eventData);
|
||||
|
||||
#endif
|
|
@ -51,7 +51,6 @@ END IF
|
|||
|
||||
DIM SHARED Include_GDB_Debugging_Info 'set using "options.bin"
|
||||
|
||||
|
||||
DIM SHARED DEPENDENCY_LAST
|
||||
CONST DEPENDENCY_LOADFONT = 1: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
|
||||
CONST DEPENDENCY_AUDIO_CONVERSION = 2: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
|
||||
|
@ -65,14 +64,16 @@ CONST DEPENDENCY_SOCKETS = 9: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
|
|||
CONST DEPENDENCY_PRINTER = 10: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
|
||||
CONST DEPENDENCY_ICON = 11: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
|
||||
CONST DEPENDENCY_SCREENIMAGE = 12: DEPENDENCY_LAST = DEPENDENCY_LAST + 1
|
||||
CONST DEPENDENCY_DEVICEINPUT = 13: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 'removes support for gamepad input if not present
|
||||
|
||||
|
||||
|
||||
|
||||
DIM SHARED DEPENDENCY(1 TO DEPENDENCY_LAST)
|
||||
|
||||
DIM SHARED UseGL 'declared SUB _GL (no params)
|
||||
|
||||
|
||||
|
||||
|
||||
DIM SHARED OS_BITS AS LONG
|
||||
OS_BITS = 64: IF INSTR(_OS$, "[32BIT]") THEN OS_BITS = 32
|
||||
|
||||
|
@ -944,12 +945,12 @@ sendc$ = "" 'no initial message
|
|||
IF CMDLineFile <> "" THEN sendc$ = CHR$(1) + CMDLineFile
|
||||
sendcommand:
|
||||
idecommand$ = sendc$
|
||||
c = ide(0)
|
||||
C = ide(0)
|
||||
ideerror = 0
|
||||
IF c = 0 THEN idemode = 0: GOTO noide
|
||||
IF C = 0 THEN idemode = 0: GOTO noide
|
||||
c$ = idereturn$
|
||||
|
||||
IF c = 2 THEN 'begin
|
||||
IF C = 2 THEN 'begin
|
||||
ideerrorline = 0 'addresses invalid prepass error line numbers being reported
|
||||
idepass = 1
|
||||
GOTO fullrecompile
|
||||
|
@ -961,7 +962,7 @@ IF c = 2 THEN 'begin
|
|||
GOTO sendcommand
|
||||
END IF
|
||||
|
||||
IF c = 4 THEN 'next line
|
||||
IF C = 4 THEN 'next line
|
||||
IF idepass = 1 THEN
|
||||
wholeline$ = c$
|
||||
GOTO ideprepass
|
||||
|
@ -976,7 +977,7 @@ IF c = 4 THEN 'next line
|
|||
GOTO sendcommand
|
||||
END IF
|
||||
|
||||
IF c = 5 THEN 'end of program reached
|
||||
IF C = 5 THEN 'end of program reached
|
||||
IF idepass = 1 THEN
|
||||
'prepass complete
|
||||
idepass = 2
|
||||
|
@ -994,7 +995,7 @@ IF c = 5 THEN 'end of program reached
|
|||
GOTO sendcommand
|
||||
END IF
|
||||
|
||||
IF c = 9 THEN 'run
|
||||
IF C = 9 THEN 'run
|
||||
|
||||
IF idecompiled = 0 THEN 'exe needs to be compiled
|
||||
file$ = c$
|
||||
|
@ -5862,6 +5863,7 @@ DO
|
|||
|
||||
IF n >= 2 THEN
|
||||
IF firstelement$ = "ON" AND secondelement$ = "STRIG" THEN
|
||||
DEPENDENCY(DEPENDENCY_DEVICEINPUT) = 1
|
||||
i = 3
|
||||
IF i > n THEN a$ = "Expected (": GOTO errmes
|
||||
a2$ = getelement$(ca$, i): i = i + 1
|
||||
|
@ -10769,6 +10771,10 @@ IF DEPENDENCY(DEPENDENCY_GL) THEN
|
|||
defines$ = defines$ + defines_header$ + "DEPENDENCY_GL"
|
||||
END IF
|
||||
|
||||
IF DEPENDENCY(DEPENDENCY_SCREENIMAGE) THEN
|
||||
DEPENDENCY(DEPENDENCY_IMAGE_CODEC) = 1 'used by OSX to read in screen capture files
|
||||
END IF
|
||||
|
||||
IF DEPENDENCY(DEPENDENCY_IMAGE_CODEC) THEN
|
||||
defines$ = defines$ + defines_header$ + "DEPENDENCY_IMAGE_CODEC"
|
||||
END IF
|
||||
|
@ -10789,7 +10795,6 @@ ELSE
|
|||
defines$ = defines$ + defines_header$ + "DEPENDENCY_NO_PRINTER"
|
||||
END IF
|
||||
|
||||
|
||||
IF DEPENDENCY(DEPENDENCY_ICON) THEN
|
||||
defines$ = defines$ + defines_header$ + "DEPENDENCY_ICON"
|
||||
ELSE
|
||||
|
@ -10812,6 +10817,17 @@ IF DEPENDENCY(DEPENDENCY_LOADFONT) THEN
|
|||
libs$ = libs$ + " " + "parts\video\font\ttf\os\" + o$ + "\src.o"
|
||||
END IF
|
||||
|
||||
localpath$ = "internal\c\"
|
||||
|
||||
IF DEPENDENCY(DEPENDENCY_DEVICEINPUT) THEN
|
||||
defines$ = defines$ + defines_header$ + "DEPENDENCY_DEVICEINPUT"
|
||||
libname$ = "input\game_controller"
|
||||
libpath$ = "parts\" + libname$ + "\os\" + o$
|
||||
libfile$ = libpath$ + "\src.a"
|
||||
IF _FILEEXISTS(localpath$ + libfile$) = 0 THEN Build localpath$ + libpath$ 'rebuild?
|
||||
libs$ = libs$ + " " + libfile$
|
||||
END IF
|
||||
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_DECODE) THEN DEPENDENCY(DEPENDENCY_AUDIO_CONVERSION) = 1
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_CONVERSION) THEN DEPENDENCY(DEPENDENCY_AUDIO_OUT) = 1
|
||||
IF DEPENDENCY(DEPENDENCY_AUDIO_DECODE) THEN DEPENDENCY(DEPENDENCY_AUDIO_OUT) = 1
|
||||
|
@ -11630,7 +11646,7 @@ tpos = 1
|
|||
DO
|
||||
token$ = MID$(cmdline$, tpos, 2) '))
|
||||
SELECT CASE token$
|
||||
CASE "-g" 'non-GUI environment ($CONSOLE:ONLY in effect)
|
||||
CASE "-g" 'non-GUI environment (uses $CONSOLE:ONLY)
|
||||
DEPENDENCY(DEPENDENCY_CONSOLE_ONLY) = DEPENDENCY(DEPENDENCY_CONSOLE_ONLY) OR 2
|
||||
NoIDEMode = 1 'Implies -c
|
||||
Console = 1
|
||||
|
|
|
@ -289,7 +289,7 @@ regid
|
|||
'QB64 DEVICE interface
|
||||
|
||||
clearid
|
||||
id.n = "STICK"
|
||||
id.n = "STICK": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func_stick"
|
||||
id.args = 2
|
||||
|
@ -299,7 +299,7 @@ id.specialformat = "?[,?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "STRIG"
|
||||
id.n = "STRIG": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func_strig"
|
||||
id.args = 2
|
||||
|
@ -309,7 +309,7 @@ id.specialformat = "?[,?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "STRIG"
|
||||
id.n = "STRIG": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 2
|
||||
id.callname = "sub_strig"
|
||||
id.args = 3
|
||||
|
@ -321,14 +321,14 @@ regid
|
|||
|
||||
|
||||
clearid
|
||||
id.n = "_DEVICES"
|
||||
id.n = "_DEVICES": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__devices"
|
||||
id.ret = LONGTYPE - ISPOINTER
|
||||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_DEVICE"
|
||||
id.n = "_DEVICE": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.musthave = "$"
|
||||
id.subfunc = 1
|
||||
id.callname = "func__device"
|
||||
|
@ -339,7 +339,7 @@ id.specialformat = "[?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_DEVICEINPUT"
|
||||
id.n = "_DEVICEINPUT": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__deviceinput"
|
||||
id.args = 1
|
||||
|
@ -349,7 +349,7 @@ id.specialformat = "[?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_LASTBUTTON"
|
||||
id.n = "_LASTBUTTON": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__lastbutton"
|
||||
id.args = 1
|
||||
|
@ -359,7 +359,7 @@ id.specialformat = "[?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_LASTAXIS"
|
||||
id.n = "_LASTAXIS": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__lastaxis"
|
||||
id.args = 1
|
||||
|
@ -369,7 +369,7 @@ id.specialformat = "[?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_LASTWHEEL"
|
||||
id.n = "_LASTWHEEL": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__lastwheel"
|
||||
id.args = 1
|
||||
|
@ -379,7 +379,7 @@ id.specialformat = "[?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_BUTTON"
|
||||
id.n = "_BUTTON": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__button"
|
||||
id.args = 1
|
||||
|
@ -389,7 +389,7 @@ id.specialformat = "[?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_BUTTONCHANGE"
|
||||
id.n = "_BUTTONCHANGE": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__buttonchange"
|
||||
id.args = 1
|
||||
|
@ -399,7 +399,7 @@ id.specialformat = "[?]"
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_AXIS"
|
||||
id.n = "_AXIS": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__axis"
|
||||
id.args = 1
|
||||
|
@ -410,7 +410,7 @@ regid
|
|||
|
||||
|
||||
clearid
|
||||
id.n = "_WHEEL"
|
||||
id.n = "_WHEEL": id.Dependency=DEPENDENCY_DEVICEINPUT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__wheel"
|
||||
id.args = 1
|
||||
|
@ -559,7 +559,6 @@ id.args = 4
|
|||
id.arg = MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER)
|
||||
id.specialformat = "[?,?,?,?]"
|
||||
id.ret = LONGTYPE - ISPOINTER
|
||||
id.Dependency = DEPENDENCY_IMAGE_CODEC 'used by OSX to read in screen capture files
|
||||
id.NoCloud = 1
|
||||
regid
|
||||
|
||||
|
@ -735,7 +734,6 @@ id.subfunc = 2
|
|||
id.callname = "sub__autodisplay"
|
||||
regid
|
||||
|
||||
|
||||
clearid
|
||||
id.n = "_LIMIT"
|
||||
id.subfunc = 2
|
||||
|
@ -744,6 +742,15 @@ id.args = 1
|
|||
id.arg = MKL$(DOUBLETYPE - ISPOINTER)
|
||||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_FPS"
|
||||
id.subfunc = 2
|
||||
id.callname = "sub__fps"
|
||||
id.args = 1
|
||||
id.arg = MKL$(DOUBLETYPE - ISPOINTER)
|
||||
id.specialformat = "[{_AUTO}][?]"
|
||||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_DELAY"
|
||||
id.subfunc = 2
|
||||
|
@ -793,14 +800,13 @@ id.ret = LONGTYPE - ISPOINTER
|
|||
regid
|
||||
|
||||
clearid
|
||||
id.n = "_LOADIMAGE"
|
||||
id.n = "_LOADIMAGE": id.Dependency = DEPENDENCY_IMAGE_CODEC
|
||||
id.subfunc = 1
|
||||
id.callname = "func__loadimage"
|
||||
id.args = 2
|
||||
id.arg = MKL$(STRINGTYPE - ISPOINTER) + MKL$(LONGTYPE - ISPOINTER)
|
||||
id.specialformat = "?[,?]"
|
||||
id.ret = LONGTYPE - ISPOINTER
|
||||
id.Dependency = DEPENDENCY_IMAGE_CODEC
|
||||
regid
|
||||
|
||||
clearid
|
||||
|
@ -1035,14 +1041,13 @@ regid
|
|||
'FONT SUPPORT
|
||||
|
||||
clearid
|
||||
id.n = "_LOADFONT"
|
||||
id.n = "_LOADFONT": id.Dependency = DEPENDENCY_LOADFONT
|
||||
id.subfunc = 1
|
||||
id.callname = "func__loadfont"
|
||||
id.args = 3
|
||||
id.arg = MKL$(STRINGTYPE - ISPOINTER) + MKL$(DOUBLETYPE - ISPOINTER) + MKL$(STRINGTYPE - ISPOINTER)
|
||||
id.specialformat = "?,?[,?]"
|
||||
id.ret = LONGTYPE - ISPOINTER
|
||||
id.Dependency = DEPENDENCY_LOADFONT
|
||||
regid
|
||||
|
||||
clearid
|
||||
|
|
Loading…
Reference in a new issue