1
0
Fork 0

Olaf Flebbe: incorporate plib js code to fix problems with MS joysticks under Vista and 7

This commit is contained in:
Frederic Bouvier 2011-01-14 21:30:51 +01:00
parent 664817b0a7
commit 4d0a6f5668
19 changed files with 1694 additions and 55 deletions

View file

@ -80,6 +80,25 @@ if(EVENT_INPUT)
endif()
else(EVENT_INPUT)
set(ENABLE_PLIB_JOYSTICK 1)
message(STATUS "adding runtime JS dependencies")
if(APPLE)
# resolve frameworks to full paths
find_library(IOKIT_LIBRARY IOKit)
find_library(CF_LIBRARY CoreFoundation)
set(JS_LIBS ${IOKIT_LIBRARY} ${CF_LIBRARY})
elseif(WIN32)
find_library(WINMM_LIBRARY winmm)
set(JS_LIBS ${WINMM_LIBRARY})
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
# anything needed here?
elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
find_library(USBHID_LIBRARY usbhid)
# check_function_exists(hidinit)
set(JS_LIBS ${USBHID_LIBRARY})
else()
message(WARNING "Unsupported platform for JS libs")
endif()
endif(EVENT_INPUT)
if (MSVC_3RDPARTY_DIR)
@ -116,7 +135,7 @@ if(ENABLE_LIBSVN)
endif(LIBSVN_FOUND)
endif(ENABLE_LIBSVN)
find_package(PLIB REQUIRED puaux pu js fnt)
find_package(PLIB REQUIRED puaux pu fnt)
find_package(SimGear 2.2.0 REQUIRED)
check_include_file(unistd.h HAVE_UNISTD_H)

View file

@ -152,30 +152,6 @@ if(${PLIB_LIBRARIES} STREQUAL "PLIB_LIBRARIES-NOTFOUND")
endforeach()
endif()
list(FIND outDeps "js" haveJs)
if(${haveJs} GREATER -1)
message(STATUS "adding runtime JS dependencies")
if(APPLE)
# resolve frameworks to full paths
find_library(IOKIT_LIBRARY IOKit)
find_library(CF_LIBRARY CoreFoundation)
set(JS_LIBS ${IOKIT_LIBRARY} ${CF_LIBRARY})
elseif(WIN32)
find_library(WINMM_LIBRARY winmm)
set(JS_LIBS ${WINMM_LIBRARY})
elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
# anything needed here?
elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
find_library(USBHID_LIBRARY usbhid)
# check_function_exists(hidinit)
set(JS_LIBS ${USBHID_LIBRARY})
else()
message(WARNING "Unsupported platform for PLIB JS libs")
endif()
list(APPEND PLIB_LIBRARIES ${JS_LIBS})
endif()
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PLIB DEFAULT_MSG PLIB_LIBRARIES PLIB_INCLUDE_DIR)

View file

@ -5,6 +5,15 @@ set(EVENT_INPUT_SOURCES
FGMacOSXEventInput.cxx
)
set (JS_INPUT_SOURCES
js.cxx
jsBSD.cxx
jsLinux.cxx
jsMacOSX.cxx
jsWindows.cxx
jsNone.cxx
)
set(SOURCES
FGButton.cxx
FGCommonInput.cxx
@ -16,8 +25,13 @@ set(SOURCES
input.cxx
)
#
# we still have a dependency on ul from plib!
if(EVENT_INPUT)
list(APPEND SOURCES ${EVENT_INPUT_SOURCES})
else()
list(APPEND SOURCES ${JS_INPUT_SOURCES})
endif()
set(FGJS_SOURCES
@ -33,17 +47,20 @@ if(WIN32)
endif(WIN32)
target_link_libraries(fgjs
fgInput
${SOCKETS_LIBRARY}
${SIMGEAR_LIBRARIES}
${PLIB_LIBRARIES}
${JS_LIBS}
${ZLIB_LIBRARY})
add_executable(js_demo js_demo.cxx )
target_link_libraries(js_demo
${SIMGEAR_LIBRARIES}
fgInput
${JS_LIBS}
${PLIB_LIBRARIES}
${ZLIB_LIBRARY})
)
flightgear_component(Input "${SOURCES}")

View file

@ -89,7 +89,7 @@ void FGJoystickInput::init()
continue;
}
const char * name = js->getName();
std::string name = js->getName();
SGPropertyNode_ptr js_node = js_nodes->getChild("js", i);
if (js_node) {
@ -130,14 +130,8 @@ void FGJoystickInput::postinit()
if (!js_node || js->notWorking())
continue;
#ifdef WIN32
JOYCAPS jsCaps ;
joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
unsigned int nbuttons = jsCaps.wNumButtons;
int nbuttons = js->getNumButtons();
if (nbuttons > MAX_JOYSTICK_BUTTONS) nbuttons = MAX_JOYSTICK_BUTTONS;
#else
unsigned int nbuttons = MAX_JOYSTICK_BUTTONS;
#endif
int naxes = js->getNumAxes();
if (naxes > MAX_JOYSTICK_AXES) naxes = MAX_JOYSTICK_AXES;

View file

@ -31,8 +31,9 @@
#include "FGCommonInput.hxx"
#include "FGButton.hxx"
#include "FGjs.hxx"
#include <simgear/structure/subsystem_mgr.hxx>
#include <plib/js.h>
////////////////////////////////////////////////////////////////////////
// The Joystick Input Class

92
src/Input/FGjs.hxx Normal file
View file

@ -0,0 +1,92 @@
/*
PLIB - A Suite of Portable Game Libraries
Copyright (C) 1998,2002 Steve Baker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information visit http://plib.sourceforge.net
$Id: js.h 2067 2006-01-30 07:36:01Z bram $
*/
#ifndef __INCLUDED_JS_H__
#define __INCLUDED_JS_H__ 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // -dw- for memcpy
#include <string>
#define _JS_MAX_AXES 16
#define _JS_MAX_BUTTONS 32
#define _JS_MAX_HATS 4
class jsJoystick
{
int id ;
protected:
struct os_specific_s *os ;
friend struct os_specific_s ;
bool error ;
std::string name;
int num_axes ;
int num_buttons ;
float dead_band [ _JS_MAX_AXES ] ;
float saturate [ _JS_MAX_AXES ] ;
float center [ _JS_MAX_AXES ] ;
float max [ _JS_MAX_AXES ] ;
float min [ _JS_MAX_AXES ] ;
void open () ;
void close () ;
float fudge_axis ( float value, int axis ) const ;
void rawRead ( int *buttons, float *axes ) ;
public:
jsJoystick ( int ident = 0 ) ;
~jsJoystick () { close () ; }
std::string getName () const { return name ; }
int getNumAxes () const { return num_axes ; }
int getNumButtons () const { return num_buttons; }
bool notWorking () const { return error ; }
void setError () { error = true ; }
float getDeadBand ( int axis ) const { return dead_band [ axis ] ; }
void setDeadBand ( int axis, float db ) { dead_band [ axis ] = db ; }
float getSaturation ( int axis ) const { return saturate [ axis ] ; }
void setSaturation ( int axis, float st ) { saturate [ axis ] = st ; }
void setMinRange ( float *axes ) { memcpy ( min , axes, num_axes * sizeof(float) ) ; }
void setMaxRange ( float *axes ) { memcpy ( max , axes, num_axes * sizeof(float) ) ; }
void setCenter ( float *axes ) { memcpy ( center, axes, num_axes * sizeof(float) ) ; }
void getMinRange ( float *axes ) const { memcpy ( axes, min , num_axes * sizeof(float) ) ; }
void getMaxRange ( float *axes ) const { memcpy ( axes, max , num_axes * sizeof(float) ) ; }
void getCenter ( float *axes ) const { memcpy ( axes, center, num_axes * sizeof(float) ) ; }
void read ( int *buttons, float *axes ) ;
// bool SetForceFeedBack ( int axe, float force );
} ;
extern void jsInit () ;
#endif

View file

@ -18,8 +18,6 @@ if HAVE_FRAMEWORK_PLIB
js_demo_LDFLAGS = $(plib_FRAMEWORK)
fgjs_LDFLAGS = $(plib_FRAMEWORK)
else
js_demo_PLIB_LIBS = -lplibjs -lplibul
fgjs_PLIB_LIBS = -lplibjs -lplibul
js_demo_LDFLAGS =
fgjs_LDFLAGS=
endif
@ -36,17 +34,18 @@ libInput_a_SOURCES = input.cxx input.hxx FGCommonInput.cxx FGCommonInput.hxx \
FGMouseInput.cxx FGMouseInput.hxx \
FGKeyboardInput.cxx FGKeyboardInput.hxx \
FGJoystickInput.cxx FGJoystickInput.hxx \
js.cxx jsBSD.cxx jsLinux.cxx jsMacOSX.cxx jsNone.cxx FGjs.hxx \
$(libInput_Event_SOURCES)
bin_PROGRAMS = js_demo fgjs
js_demo_SOURCES = js_demo.cxx
js_demo_LDADD = $(js_demo_PLIB_LIBS) $(base_LIBS) $(joystick_LIBS)
js_demo_LDADD = $(base_LIBS) -L. -lInput -lplibul
fgjs_SOURCES = fgjs.cxx jsinput.cxx jsinput.h jssuper.cxx jssuper.h
fgjs_LDADD = $(js_demo_PLIB_LIBS) $(base_LIBS) $(joystick_LIBS) \
fgjs_LDADD = $(base_LIBS) $(joystick_LIBS) -L. -lInput -lplibul \
-lsgprops -lsgmisc -lsgio -lsgdebug -lsgstructure -lsgxml -lz $(network_LIBS)
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/src/Main \

87
src/Input/js.cxx Normal file
View file

@ -0,0 +1,87 @@
/*
PLIB - A Suite of Portable Game Libraries
Copyright (C) 1998,2002 Steve Baker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information visit http://plib.sourceforge.net
*/
#include "FGjs.hxx"
float jsJoystick::fudge_axis ( float value, int axis ) const
{
if ( value < center[axis] )
{
float xx = ( value - center[ axis ] ) /
( center [ axis ] - min [ axis ] ) ;
if ( xx < -saturate [ axis ] )
return -1.0f ;
if ( xx > -dead_band [ axis ] )
return 0.0f ;
xx = ( xx + dead_band [ axis ] ) /
( saturate [ axis ] - dead_band [ axis ] ) ;
return ( xx < -1.0f ) ? -1.0f : xx ;
}
else
{
float xx = ( value - center [ axis ] ) /
( max [ axis ] - center [ axis ] ) ;
if ( xx > saturate [ axis ] )
return 1.0f ;
if ( xx < dead_band [ axis ] )
return 0.0f ;
xx = ( xx - dead_band [ axis ] ) /
( saturate [ axis ] - dead_band [ axis ] ) ;
return ( xx > 1.0f ) ? 1.0f : xx ;
}
}
void jsJoystick::read ( int *buttons, float *axes )
{
if ( error )
{
if ( buttons )
*buttons = 0 ;
if ( axes )
for ( int i = 0 ; i < num_axes ; i++ )
axes[i] = 0.0f ;
return ;
}
float raw_axes [ _JS_MAX_AXES ] ;
rawRead ( buttons, raw_axes ) ;
if ( axes )
for ( int i = 0 ; i < num_axes ; i++ )
axes[i] = fudge_axis ( raw_axes[i], i ) ;
}

497
src/Input/jsBSD.cxx Normal file
View file

@ -0,0 +1,497 @@
/*
PLIB - A Suite of Portable Game Libraries
Copyright (C) 1998,2002 Steve Baker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information visit http://plib.sourceforge.net
$Id: jsBSD.cxx 2063 2006-01-05 21:21:55Z fayjf $
*/
/*
* Inspired by the X-Mame USB HID joystick driver for NetBSD and
* FreeBSD by Krister Walfridsson <cato@df.lth.se>.
* Incorporates the original analog joystick driver for BSD by
* Stephen Montgomery-Smith <stephen@math.missouri.edu>, with
* NetBSD mods courtesy of Rene Hexel.
*
* Bert Driehuis <driehuis@playbeing.org>
*
* Notes:
* Hats are mapped to two axes for now. A cleaner implementation requires
* an API extension, and to be useful for my devious purposes, FlightGear
* would need to understand that.
*/
#ifdef __FreeBSD__
#include "FGjs.h"
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/joystick.h>
#ifdef HAVE_USB_JS
extern "C" {
# if __FreeBSD_version < 500000
# include <libusbhid.h>
# else
# define HAVE_USBHID_H 1
# include <usbhid.h>
# endif
}
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
/* Compatibility with older usb.h revisions */
#if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
#define USB_MAX_DEVNAMES MAXDEVNAMES
#endif
#endif
static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
struct os_specific_s {
char fname [128 ];
int fd;
int is_analog;
// The following structure members are specific to analog joysticks
struct joystick ajs;
#ifdef HAVE_USB_JS
// The following structure members are specific to USB joysticks
struct hid_item *hids;
int hid_dlen;
int hid_offset;
char *hid_data_buf;
int axes_usage [ _JS_MAX_AXES ] ;
#endif
// We keep button and axes state ourselves, as they might not be updated
// on every read of a USB device
int cache_buttons ;
float cache_axes [ _JS_MAX_AXES ] ;
};
// Idents lower than USB_IDENT_OFFSET are for analog joysticks.
#define USB_IDENT_OFFSET 2
#define USBDEV "/dev/usb"
#define UHIDDEV "/dev/uhid"
#define AJSDEV "/dev/joy"
/*
* findusbdev (and its helper, walkusbdev) try to locate the full name
* of a USB device. If /dev/usbN isn't readable, we punt and return the
* uhidN device name. We warn the user of this situation once.
*/
static char *
walkusbdev(int f, char *dev, char *out, int outlen)
{
struct usb_device_info di;
int i, a;
char *cp;
for (a = 1; a < USB_MAX_DEVICES; a++) {
di.udi_addr = a;
if (ioctl(f, USB_DEVICEINFO, &di) != 0)
return NULL;
for (i = 0; i < USB_MAX_DEVNAMES; i++)
if (di.udi_devnames[i][0] &&
strcmp(di.udi_devnames[i], dev) == 0) {
cp = new char[strlen(di.udi_vendor) + strlen(di.udi_product) + 2];
strcpy(cp, di.udi_vendor);
strcat(cp, " ");
strcat(cp, di.udi_product);
strncpy(out, cp, outlen - 1);
out[outlen - 1] = 0;
delete cp;
return out;
}
}
return NULL;
}
static int
findusbdev(char *name, char *out, int outlen)
{
int i, f;
char buf[50];
char *cp;
static int protection_warned = 0;
for (i = 0; i < 16; i++) {
sprintf(buf, "%s%d", USBDEV, i);
f = open(buf, O_RDONLY);
if (f >= 0) {
cp = walkusbdev(f, name, out, outlen);
close(f);
if (cp)
return 1;
} else if (errno == EACCES) {
if (!protection_warned) {
fprintf(stderr, "Can't open %s for read!\n",
buf);
protection_warned = 1;
}
}
}
return 0;
}
static int joy_initialize_hid(struct os_specific_s *os,
int *num_axes, int *num_buttons)
{
int size, is_joystick;
#ifdef HAVE_USBHID_H
int report_id = 0;
#endif
struct hid_data *d;
struct hid_item h;
report_desc_t rd;
if ((rd = hid_get_report_desc(os->fd)) == 0)
{
fprintf(stderr, "error: %s: %s", os->fname, strerror(errno));
return FALSE;
}
os->hids = NULL;
#ifdef HAVE_USBHID_H
if (ioctl(os->fd, USB_GET_REPORT_ID, &report_id) < 0)
{
fprintf(stderr, "error: %s: %s", os->fname, strerror(errno));
return FALSE;
}
size = hid_report_size(rd, hid_input, report_id);
#else
size = hid_report_size(rd, 0, hid_input);
#endif
os->hid_data_buf = new char[size];
os->hid_dlen = size;
is_joystick = 0;
#ifdef HAVE_USBHID_H
d = hid_start_parse(rd, 1 << hid_input, report_id);
#else
d = hid_start_parse(rd, 1 << hid_input);
#endif
while (hid_get_item(d, &h))
{
int usage, page, interesting_hid;
page = HID_PAGE(h.usage);
usage = HID_USAGE(h.usage);
/* This test is somewhat too simplistic, but this is how MicroSoft
* does, so I guess it works for all joysticks/game pads. */
is_joystick = is_joystick ||
(h.kind == hid_collection &&
page == HUP_GENERIC_DESKTOP &&
(usage == HUG_JOYSTICK || usage == HUG_GAME_PAD));
if (h.kind != hid_input)
continue;
if (!is_joystick)
continue;
interesting_hid = TRUE;
if (page == HUP_GENERIC_DESKTOP)
{
switch(usage) {
case HUG_X:
case HUG_RX:
case HUG_Y:
case HUG_RY:
case HUG_Z:
case HUG_RZ:
case HUG_SLIDER:
if (*num_axes < _JS_MAX_AXES)
{
os->axes_usage[*num_axes] = usage;
(*num_axes)++;
}
break;
case HUG_HAT_SWITCH:
if (*num_axes + 1 < _JS_MAX_AXES) // Allocate two axes for a hat
{
os->axes_usage[*num_axes] = usage;
(*num_axes)++;
os->axes_usage[*num_axes] = usage;
(*num_axes)++;
}
break;
default:
interesting_hid = FALSE;
}
}
else if (page == HUP_BUTTON)
{
interesting_hid = (usage > 0) && (usage <= _JS_MAX_BUTTONS);
if (interesting_hid && usage - 1 > *num_buttons)
{
*num_buttons = usage - 1;
}
}
if (interesting_hid)
{
h.next = os->hids;
os->hids = new struct hid_item;
*os->hids = h;
}
}
hid_end_parse(d);
return (os->hids != NULL);
}
void jsJoystick::open ()
{
char *cp;
for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
os->cache_axes [ i ] = 0.0f ;
os->cache_buttons = 0 ;
os->fd = ::open ( os->fname, O_RDONLY | O_NONBLOCK) ;
if (os->fd < 0 && errno == EACCES)
fprintf(stderr, "%s exists but is not readable by you\n", os->fname);
error = ( os->fd < 0 ) ;
if ( error )
return ;
num_axes = 0;
num_buttons = 0;
if ( os->is_analog )
{
num_axes = 2 ;
num_buttons = 32 ;
FILE *joyfile ;
char joyfname [ 1024 ] ;
int noargs, in_no_axes ;
float axes [ _JS_MAX_AXES ] ;
int buttons [ _JS_MAX_AXES ] ;
rawRead ( buttons, axes ) ;
error = axes[0] < -1000000000.0f && axes[1] < -1000000000.0f ;
if ( error )
return ;
sprintf( joyfname, "%s/.joy%drc", ::getenv ( "HOME" ), id ) ;
joyfile = fopen ( joyfname, "r" ) ;
error = ( joyfile == NULL ) ;
if ( error )
{
ulSetError ( UL_WARNING, "unable to open calibration file %s (%s), joystick %i disabled (you can generate the calibration file with the plib-jscal utility)",
joyfname, strerror ( errno ), id + 1 );
return ;
}
noargs = fscanf ( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
&min [ 0 ], &center [ 0 ], &max [ 0 ],
&min [ 1 ], &center [ 1 ], &max [ 1 ] ) ;
error = noargs != 7 || in_no_axes != _JS_MAX_AXES ;
fclose ( joyfile ) ;
if ( error )
return ;
for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
{
dead_band [ i ] = 0.0f ;
saturate [ i ] = 1.0f ;
}
return; // End of analog code
}
if ( !joy_initialize_hid(os, &num_axes, &num_buttons ) )
{
::close(os->fd);
error = 1;
return;
}
cp = strrchr(os->fname, '/');
char tmpname[128];
if (cp) {
if (findusbdev(&cp[1], tmpname, sizeof(tmpname)) == 0)
strcpy(name, &cp[1]);
}
name = tmpname;
if ( num_axes > _JS_MAX_AXES )
num_axes = _JS_MAX_AXES ;
for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
{
// We really should get this from the HID, but that data seems
// to be quite unreliable for analog-to-USB converters. Punt for
// now.
if ( os->axes_usage [ i ] == HUG_HAT_SWITCH )
{
max [ i ] = 1.0f ;
center [ i ] = 0.0f ;
min [ i ] = -1.0f ;
}
else
{
max [ i ] = 255.0f ;
center [ i ] = 127.0f ;
min [ i ] = 0.0f ;
}
dead_band [ i ] = 0.0f ;
saturate [ i ] = 1.0f ;
}
}
void jsJoystick::close ()
{
if (os) {
if ( ! error )
::close ( os->fd ) ;
if (os->hids)
delete os->hids;
if (os->hid_data_buf)
delete os->hid_data_buf;
delete os;
}
}
jsJoystick::jsJoystick ( int ident )
{
id = ident ;
error = 0;
os = new struct os_specific_s;
memset(os, 0, sizeof(struct os_specific_s));
if (ident < USB_IDENT_OFFSET)
os->is_analog = 1;
if (os->is_analog)
sprintf(os->fname, "%s%d", AJSDEV, ident);
else
sprintf(os->fname, "%s%d", UHIDDEV, ident - USB_IDENT_OFFSET);
open () ;
}
void jsJoystick::rawRead ( int *buttons, float *axes )
{
int len, usage, page, d;
struct hid_item *h;
if ( error )
{
if ( buttons )
*buttons = 0 ;
if ( axes )
for ( int i = 0 ; i < num_axes ; i++ )
axes[i] = 1500.0f ;
return ;
}
if ( os->is_analog )
{
int status = ::read ( os->fd, &os->ajs, sizeof(os->ajs) );
if ( status != sizeof(os->ajs) ) {
perror ( os->fname ) ;
setError () ;
return ;
}
if ( buttons != NULL )
*buttons = ( os->ajs.b1 ? 1 : 0 ) | ( os->ajs.b2 ? 2 : 0 ) ;
if ( axes != NULL )
{
if ( os->ajs.x >= -1000000000 )
os->cache_axes[0] = os->ajs.x;
if ( os->ajs.y >= -1000000000 )
os->cache_axes[1] = os->ajs.y;
axes[0] = os->cache_axes[0];
axes[1] = os->cache_axes[1];
}
return;
}
while ((len = ::read(os->fd, os->hid_data_buf, os->hid_dlen)) == os->hid_dlen)
{
for (h = os->hids; h; h = h->next)
{
d = hid_get_data(os->hid_data_buf, h);
page = HID_PAGE(h->usage);
usage = HID_USAGE(h->usage);
if (page == HUP_GENERIC_DESKTOP)
{
for (int i = 0; i < num_axes; i++)
if (os->axes_usage[i] == usage)
{
if (usage == HUG_HAT_SWITCH)
{
if (d < 0 || d > 8)
d = 0; // safety
os->cache_axes[i] = (float)hatmap_x[d];
os->cache_axes[i + 1] = (float)hatmap_y[d];
}
else
{
os->cache_axes[i] = (float)d;
}
break;
}
}
else if (page == HUP_BUTTON)
{
if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
{
if (d)
os->cache_buttons |= (1 << usage - 1) ;
else
os->cache_buttons &= ~(1 << usage - 1) ;
}
}
}
}
if (len < 0 && errno != EAGAIN)
{
perror( os->fname ) ;
setError () ;
error = 1;
}
if ( buttons != NULL ) *buttons = os->cache_buttons ;
if ( axes != NULL )
memcpy ( axes, os->cache_axes, sizeof(float) * num_axes ) ;
}
void jsInit () {}
#endif

203
src/Input/jsLinux.cxx Normal file
View file

@ -0,0 +1,203 @@
/*
PLIB - A Suite of Portable Game Libraries
Copyright (C) 1998,2002 Steve Baker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information visit http://plib.sourceforge.net
$Id: jsLinux.cxx 2017 2005-02-21 07:37:25Z bram $
*/
#ifdef linux
#include "FGjs.hxx"
#include <linux/joystick.h>
#if defined(JS_VERSION) && JS_VERSION >= 0x010000
#include <sys/param.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <plib/ul.h>
struct os_specific_s {
js_event js ;
int tmp_buttons ;
float tmp_axes [ _JS_MAX_AXES ] ;
char fname [ 128 ] ;
int fd ;
};
void jsInit () {}
void jsJoystick::open ()
{
name [0] = '\0' ;
for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
os->tmp_axes [ i ] = 0.0f ;
os->tmp_buttons = 0 ;
os->fd = ::open ( os->fname, O_RDONLY ) ;
error = ( os->fd < 0 ) ;
if ( error )
return ;
/*
Set the correct number of axes for the linux driver
*/
/* Melchior Franz's fixes for big-endian Linuxes since writing
* to the upper byte of an uninitialized word doesn't work.
* 9 April 2003
*/
unsigned char u ;
ioctl ( os->fd, JSIOCGAXES , &u ) ;
num_axes = u ;
ioctl ( os->fd, JSIOCGBUTTONS, &u ) ;
num_buttons = u ;
char tmpname[256];
ioctl ( os->fd, JSIOCGNAME ( sizeof(tmpname) ), tmpname ) ;
fcntl ( os->fd, F_SETFL , O_NONBLOCK ) ;
name = tmpname;
int all_axes = num_axes;
if ( num_axes > _JS_MAX_AXES )
num_axes = _JS_MAX_AXES ;
// Remove any deadband value already done in the kernel.
// Since we have our own deadband management this is save to do so.
struct js_corr* corr = new js_corr[ all_axes ] ;
ioctl ( os->fd, JSIOCGCORR, corr );
for ( int i = 0; i < num_axes ; ++i ) {
if ( corr[ i ] . type == JS_CORR_BROKEN ) {
int nodeadband = ( corr[ i ] . coef[ 0 ] + corr[ i ] . coef[ 1 ] ) / 2 ;
corr[ i ] . coef[ 0 ] = nodeadband ;
corr[ i ] . coef[ 1 ] = nodeadband ;
}
}
ioctl ( os->fd, JSIOCSCORR, corr );
delete [] corr;
for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
{
max [ i ] = 32767.0f ;
center [ i ] = 0.0f ;
min [ i ] = -32767.0f ;
dead_band [ i ] = 0.0f ;
saturate [ i ] = 1.0f ;
}
}
void jsJoystick::close ()
{
if ( ! error )
::close ( os->fd ) ;
delete os;
}
jsJoystick::jsJoystick ( int ident )
{
id = ident ;
os = new struct os_specific_s;
sprintf ( os->fname, "/dev/input/js%d", ident ) ;
if ( access ( os->fname, F_OK ) != 0 )
sprintf ( os->fname, "/dev/js%d", ident ) ;
open () ;
}
void jsJoystick::rawRead ( int *buttons, float *axes )
{
if ( error )
{
if ( buttons )
*buttons = 0 ;
if ( axes )
for ( int i = 0 ; i < num_axes ; i++ )
axes[i] = 1500.0f ;
return ;
}
while (1)
{
int status = ::read ( os->fd, &(os->js), sizeof(js_event) ) ;
if ( status != sizeof(js_event) )
{
/* use the old values */
if ( buttons != NULL ) *buttons = os->tmp_buttons ;
if ( axes != NULL )
memcpy ( axes, os->tmp_axes, sizeof(float) * num_axes ) ;
if ( errno == EAGAIN )
return ;
perror( os->fname ) ;
setError () ;
return ;
}
switch ( os->js.type & ~JS_EVENT_INIT )
{
case JS_EVENT_BUTTON :
if ( os->js.value == 0 ) /* clear the flag */
os->tmp_buttons &= ~(1 << os->js.number) ;
else
os->tmp_buttons |= (1 << os->js.number) ;
break ;
case JS_EVENT_AXIS:
if ( os->js.number < num_axes )
{
os->tmp_axes [ os->js.number ] = (float) os->js.value ;
if ( axes )
memcpy ( axes, os->tmp_axes, sizeof(float) * num_axes ) ;
}
break ;
default:
ulSetError ( UL_WARNING, "PLIB_JS: Unrecognised /dev/js return!?!" ) ;
/* use the old values */
if ( buttons != NULL ) *buttons = os->tmp_buttons ;
if ( axes != NULL )
memcpy ( axes, os->tmp_axes, sizeof(float) * num_axes ) ;
return ;
}
if ( buttons != NULL )
*buttons = os->tmp_buttons ;
}
}
#endif
#endif

422
src/Input/jsMacOSX.cxx Normal file
View file

@ -0,0 +1,422 @@
/*
PLIB - A Suite of Portable Game Libraries
Copyright (C) 1998,2002 Steve Baker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information visit http://plib.sourceforge.net
$Id: jsMacOSX.cxx 2118 2007-09-14 22:23:32Z fayjf $
*/
#ifdef __APPLE__
#include "FGjs.h"
#include <mach/mach.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/hid/IOHIDLib.h>
#include <mach/mach_error.h>
#include <IOKit/hid/IOHIDKeys.h>
#include <IOKit/IOCFPlugIn.h>
#include <CoreFoundation/CoreFoundation.h>
#ifdef MACOS_10_0_4
# include <IOKit/hidsystem/IOHIDUsageTables.h>
#else
/* The header was moved here in MacOS X 10.1 */
# include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
#endif
static const int kNumDevices = 32;
static int numDevices = -1;
static io_object_t ioDevices[kNumDevices];
static int NS_hat[8] = {1, 1, 0, -1, -1, -1, 0, 1};
static int WE_hat[8] = {0, 1, 1, 1, 0, -1, -1, -1};
struct os_specific_s {
IOHIDDeviceInterface ** hidDev;
IOHIDElementCookie buttonCookies[41];
IOHIDElementCookie axisCookies[_JS_MAX_AXES];
IOHIDElementCookie hatCookies[_JS_MAX_HATS];
int num_hats;
long hat_min[_JS_MAX_HATS];
long hat_max[_JS_MAX_HATS];
void enumerateElements(jsJoystick* joy, CFTypeRef element);
static void elementEnumerator( const void *element, void* vjs);
/// callback for CFArrayApply
void parseElement(jsJoystick* joy, CFDictionaryRef element);
void addAxisElement(jsJoystick* joy, CFDictionaryRef axis);
void addButtonElement(jsJoystick* joy, CFDictionaryRef button);
void addHatElement(jsJoystick* joy, CFDictionaryRef hat);
};
static void findDevices(mach_port_t);
static CFDictionaryRef getCFProperties(io_object_t);
void jsInit()
{
if (numDevices < 0) {
numDevices = 0;
mach_port_t masterPort;
IOReturn rv = IOMasterPort(bootstrap_port, &masterPort);
if (rv != kIOReturnSuccess) {
ulSetError(UL_WARNING, "error getting master Mach port");
return;
}
findDevices(masterPort);
}
}
/** open the IOKit connection, enumerate all the HID devices, add their
interface references to the static array. We then use the array index
as the device number when we come to open() the joystick. */
static void findDevices(mach_port_t masterPort)
{
CFMutableDictionaryRef hidMatch = NULL;
IOReturn rv = kIOReturnSuccess;
io_iterator_t hidIterator;
// build a dictionary matching HID devices
hidMatch = IOServiceMatching(kIOHIDDeviceKey);
rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
if (rv != kIOReturnSuccess || !hidIterator) {
ulSetError(UL_WARNING, "no joystick (HID) devices found");
return;
}
// iterate
io_object_t ioDev;
while ((ioDev = IOIteratorNext(hidIterator))) {
// filter out keyboard and mouse devices
CFDictionaryRef properties = getCFProperties(ioDev);
long usage, page;
CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
// keep only joystick devices
if ( (page == kHIDPage_GenericDesktop) &&
((usage == kHIDUsage_GD_Joystick) ||
(usage == kHIDUsage_GD_GamePad)
// || (usage == kHIDUsage_GD_MultiAxisController)
// || (usage == kHIDUsage_GD_Hatswitch)
)
)
{
// add it to the array
ioDevices[numDevices++] = ioDev;
}
}
IOObjectRelease(hidIterator);
}
jsJoystick::jsJoystick(int ident) :
id(ident),
os(NULL),
error(false),
num_axes(0),
num_buttons(0)
{
if (ident >= numDevices) {
setError();
return;
}
os = new struct os_specific_s;
os->num_hats = 0;
// get the name now too
CFDictionaryRef properties = getCFProperties(ioDevices[id]);
CFTypeRef ref = CFDictionaryGetValue (properties, CFSTR(kIOHIDProductKey));
if (!ref)
ref = CFDictionaryGetValue (properties, CFSTR("USB Product Name"));
char tmpname[128];
if (!ref || !CFStringGetCString ((CFStringRef) ref, tmpname, sizeof(tmpname), CFStringGetSystemEncoding ())) {
ulSetError(UL_WARNING, "error getting device name");
tmpname[0] = '\0';
}
name = tmpname;
//printf("Joystick name: %s \n", name);
open();
}
void jsJoystick::open()
{
// create device interface
IOReturn rv;
SInt32 score;
IOCFPlugInInterface **plugin;
rv = IOCreatePlugInInterfaceForService(ioDevices[id],
kIOHIDDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
&plugin, &score);
if (rv != kIOReturnSuccess) {
ulSetError(UL_WARNING, "error creting plugin for io device");
return;
}
HRESULT pluginResult = (*plugin)->QueryInterface(plugin,
CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID*)&(os->hidDev) );
if (pluginResult != S_OK)
ulSetError(UL_WARNING, "QI-ing IO plugin to HID Device interface failed");
(*plugin)->Release(plugin); // don't leak a ref
if (os->hidDev == NULL) return;
// store the interface in this instance
rv = (*(os->hidDev))->open(os->hidDev, 0);
if (rv != kIOReturnSuccess) {
ulSetError(UL_WARNING, "error opening device interface");
return;
}
CFDictionaryRef props = getCFProperties(ioDevices[id]);
// recursively enumerate all the bits (buttons, axes, hats, ...)
CFTypeRef topLevelElement =
CFDictionaryGetValue (props, CFSTR(kIOHIDElementKey));
os->enumerateElements(this, topLevelElement);
CFRelease(props);
// for hats to be implemented as axes: must be the last axes:
for (int h = 0; h<2*os->num_hats; h++)
{
int index = num_axes++;
dead_band [ index ] = 0.0f ;
saturate [ index ] = 1.0f ;
center [ index ] = 0.0f;
max [ index ] = 1.0f;
min [ index ] = -1.0f;
}
}
CFDictionaryRef getCFProperties(io_object_t ioDev)
{
IOReturn rv;
CFMutableDictionaryRef cfProperties;
rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/,
&cfProperties, kCFAllocatorDefault, kNilOptions);
if (rv != kIOReturnSuccess || !cfProperties) {
ulSetError(UL_WARNING, "error getting device properties");
return NULL;
}
return cfProperties;
}
void jsJoystick::close()
{
if (os->hidDev != NULL) (*(os->hidDev))->close(os->hidDev);
if (os) delete os;
}
/** element enumerator function : pass NULL for top-level*/
void os_specific_s::enumerateElements(jsJoystick* joy, CFTypeRef element)
{
assert(CFGetTypeID(element) == CFArrayGetTypeID());
CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
CFArrayApplyFunction((CFArrayRef) element, range,
&elementEnumerator, joy);
}
void os_specific_s::elementEnumerator( const void *element, void* vjs)
{
if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
ulSetError(UL_WARNING, "element enumerator passed non-dictionary value");
return;
}
static_cast<jsJoystick*>(vjs)->
os->parseElement( static_cast<jsJoystick*>(vjs), (CFDictionaryRef) element);
}
void os_specific_s::parseElement(jsJoystick* joy, CFDictionaryRef element)
{
CFTypeRef refPage = CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementUsagePageKey));
CFTypeRef refUsage = CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementUsageKey));
long type, page, usage;
CFNumberGetValue((CFNumberRef)
CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementTypeKey)),
kCFNumberLongType, &type);
switch (type) {
case kIOHIDElementTypeInput_Misc:
case kIOHIDElementTypeInput_Axis:
case kIOHIDElementTypeInput_Button:
//printf("got input element...");
CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
if (page == kHIDPage_GenericDesktop) {
switch (usage) /* look at usage to determine function */
{
case kHIDUsage_GD_X:
case kHIDUsage_GD_Y:
case kHIDUsage_GD_Z:
case kHIDUsage_GD_Rx:
case kHIDUsage_GD_Ry:
case kHIDUsage_GD_Rz:
case kHIDUsage_GD_Slider: // for throttle / trim controls
case kHIDUsage_GD_Dial:
//printf(" axis\n");
/*joy->os->*/addAxisElement(joy, (CFDictionaryRef) element);
break;
case kHIDUsage_GD_Hatswitch:
//printf(" hat\n");
/*joy->os->*/addHatElement(joy, (CFDictionaryRef) element);
break;
default:
ulSetError(UL_WARNING, "input type element has weird usage (%lx)\n", usage);
break;
}
} else if (page == kHIDPage_Button) {
//printf(" button\n");
/*joy->os->*/addButtonElement(joy, (CFDictionaryRef) element);
} else
ulSetError(UL_WARNING, "input type element has weird usage (%lx)\n", usage);
break;
case kIOHIDElementTypeCollection:
/*joy->os->*/enumerateElements(joy,
CFDictionaryGetValue(element, CFSTR(kIOHIDElementKey))
);
break;
default:
break;
}
}
void os_specific_s::addAxisElement(jsJoystick* joy, CFDictionaryRef axis)
{
long cookie, lmin, lmax;
CFNumberGetValue ((CFNumberRef)
CFDictionaryGetValue (axis, CFSTR(kIOHIDElementCookieKey)),
kCFNumberLongType, &cookie);
int index = joy->num_axes++;
/*joy->os->*/axisCookies[index] = (IOHIDElementCookie) cookie;
CFNumberGetValue ((CFNumberRef)
CFDictionaryGetValue (axis, CFSTR(kIOHIDElementMinKey)),
kCFNumberLongType, &lmin);
CFNumberGetValue ((CFNumberRef)
CFDictionaryGetValue (axis, CFSTR(kIOHIDElementMaxKey)),
kCFNumberLongType, &lmax);
joy->min[index] = lmin;
joy->max[index] = lmax;
joy->dead_band[index] = 0.0;
joy->saturate[index] = 1.0;
joy->center[index] = (lmax - lmin) * 0.5 + lmin;
}
void os_specific_s::addButtonElement(jsJoystick* joy, CFDictionaryRef button)
{
long cookie;
CFNumberGetValue ((CFNumberRef)
CFDictionaryGetValue (button, CFSTR(kIOHIDElementCookieKey)),
kCFNumberLongType, &cookie);
/*joy->os->*/buttonCookies[joy->num_buttons++] = (IOHIDElementCookie) cookie;
// anything else for buttons?
}
void os_specific_s::addHatElement(jsJoystick* joy, CFDictionaryRef hat)
{
long cookie, lmin, lmax;
CFNumberGetValue ((CFNumberRef)
CFDictionaryGetValue (hat, CFSTR(kIOHIDElementCookieKey)),
kCFNumberLongType, &cookie);
int index = /*joy->*/num_hats++;
/*joy->os->*/hatCookies[index] = (IOHIDElementCookie) cookie;
CFNumberGetValue ((CFNumberRef)
CFDictionaryGetValue (hat, CFSTR(kIOHIDElementMinKey)),
kCFNumberLongType, &lmin);
CFNumberGetValue ((CFNumberRef)
CFDictionaryGetValue (hat, CFSTR(kIOHIDElementMaxKey)),
kCFNumberLongType, &lmax);
hat_min[index] = lmin;
hat_max[index] = lmax;
// do we map hats to axes or buttons?
// axes; there is room for that: Buttons are limited to 32.
// (a joystick with 2 hats will use 16 buttons!)
}
void jsJoystick::rawRead(int *buttons, float *axes)
{
*buttons = 0;
IOHIDEventStruct hidEvent;
for (int b=0; b<num_buttons; ++b) {
(*(os->hidDev))->getElementValue(os->hidDev, os->buttonCookies[b], &hidEvent);
if (hidEvent.value)
*buttons |= 1 << b;
}
// real axes:
int real_num_axes = num_axes - 2*os->num_hats;
for (int a=0; a<real_num_axes; ++a) {
(*(os->hidDev))->getElementValue(os->hidDev, os->axisCookies[a], &hidEvent);
axes[a] = hidEvent.value;
}
// hats:
for (int h=0; h < os->num_hats; ++h) {
(*(os->hidDev))->getElementValue(os->hidDev, os->hatCookies[h], &hidEvent);
long result = ( hidEvent.value - os->hat_min[h] ) * 8;
result /= ( os->hat_max[h] - os->hat_min[h] + 1 );
if ( (result>=0) && (result<8) )
{
axes[h+real_num_axes+1] = NS_hat[result];
axes[h+real_num_axes] = WE_hat[result];
}
else
{
axes[h+real_num_axes] = 0;
axes[h+real_num_axes+1] = 0;
}
}
}
#endif

56
src/Input/jsNone.cxx Normal file
View file

@ -0,0 +1,56 @@
/*
Copyright (C) 1998,2002 Steve Baker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information visit http://plib.sourceforge.net
$Id: jsNone.cxx 1960 2004-09-21 11:45:55Z smokydiamond $
*/
#if !defined(linux) && !defined(_WIN32) && !defined(__APPLE__) && !defined(__FreeBSD__)
#include "FGjs.hxx"
struct os_specific_s ;
void jsJoystick::open ()
{
error = TRUE ;
num_axes = num_buttons = 0 ;
}
void jsJoystick::close ()
{
error = TRUE ;
}
jsJoystick::jsJoystick ( int ident )
{
error = TRUE ;
num_axes = num_buttons = 0 ;
os = NULL;
}
void jsJoystick::rawRead ( int *buttons, float *axes )
{ if ( buttons != NULL ) *buttons = 0 ;
}
void jsInit () {}
#endif

274
src/Input/jsWindows.cxx Normal file
View file

@ -0,0 +1,274 @@
/*
PLIB - A Suite of Portable Game Libraries
Copyright (C) 1998,2002 Steve Baker
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For further information visit http://plib.sourceforge.net
$Id: jsWindows.cxx 2114 2006-12-21 20:53:13Z fayjf $
*/
#include "FGjs.hxx"
#include <windows.h>
#include <regstr.h>
#include <sstream>
#include <math.h>
#include <plib/ul.h>
#if defined (_WIN32)
#define _JS_MAX_AXES_WIN 8 /* X,Y,Z,R,U,V,POV_X,POV_Y */
struct os_specific_s {
std::string regKey;
static std::string getOEMProductName ( jsJoystick* joy);
};
// Inspired by
// http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
std::string
os_specific_s::getOEMProductName (jsJoystick* joy)
{
if ( joy->error ) return "" ;
char charbuf [ 256 ] ;
HKEY hKey ;
DWORD dwcb ;
LONG lr ;
std::string name;
// Open .. MediaResources\CurrentJoystickSettings
std::string key=REGSTR_PATH_JOYCONFIG;
key+= "\\" + joy->os->regKey + "\\" + REGSTR_KEY_JOYCURR;
bool hkcu = false;
if ( ERROR_SUCCESS != RegOpenKeyEx ( HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_QUERY_VALUE, &hKey)) {
hkcu = true;
if ( ERROR_SUCCESS != RegOpenKeyEx ( HKEY_CURRENT_USER, key.c_str(), 0, KEY_QUERY_VALUE, &hKey))
return "" ;
}
// Get OEM Key name
dwcb = sizeof( charbuf) ;
std::ostringstream value;
value << "Joystick" << joy->id+1 << REGSTR_VAL_JOYOEMNAME;
// JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based.
lr = RegQueryValueEx ( hKey, value.str().c_str(), 0, 0, (LPBYTE) charbuf, &dwcb);
RegCloseKey ( hKey ) ;
if ( lr != ERROR_SUCCESS ) return "" ;
// Open OEM Key from ...MediaProperties
value.str("");
value << REGSTR_PATH_JOYOEM << "\\" << charbuf;
if (hkcu) {
lr = RegOpenKeyEx ( HKEY_CURRENT_USER, value.str().c_str(), 0, KEY_QUERY_VALUE, &hKey ) ;
} else {
lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, value.str().c_str(), 0, KEY_QUERY_VALUE, &hKey ) ;
}
if ( lr != ERROR_SUCCESS )
return "" ;
dwcb = sizeof( charbuf) ;
lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) charbuf, &dwcb ) ;
RegCloseKey ( hKey ) ;
if ( lr != ERROR_SUCCESS ) return "" ;
name = std::string( charbuf, dwcb-1);
return name;
}
void jsJoystick::open ()
{
JOYCAPS jsCaps ;
name [0] = '\0' ;
memset ( &jsCaps, 0, sizeof(jsCaps)) ;
error = ( joyGetDevCaps( id, &jsCaps, sizeof(jsCaps) )
!= JOYERR_NOERROR ) ;
os->regKey = jsCaps.szRegKey;
num_buttons = jsCaps.wNumButtons ;
if ( jsCaps.wNumAxes == 0 )
{
num_axes = 0 ;
setError () ;
}
else
{
// Device name from jsCaps is often "Microsoft PC-joystick driver",
// at least for USB. Try to get the real name from the registry.
name = os->getOEMProductName ( this);
if (name == "") {
ulSetError ( UL_WARNING,
"JS: Failed to read joystick name from registry" ) ;
name = jsCaps.szPname;
}
// Windows joystick drivers may provide any combination of
// X,Y,Z,R,U,V,POV - not necessarily the first n of these.
if ( jsCaps.wCaps & JOYCAPS_HASPOV )
{
num_axes = _JS_MAX_AXES_WIN ;
min [ 7 ] = -1.0 ; max [ 7 ] = 1.0 ; // POV Y
min [ 6 ] = -1.0 ; max [ 6 ] = 1.0 ; // POV X
}
else
num_axes = 6 ;
min [ 5 ] = (float) jsCaps.wVmin ; max [ 5 ] = (float) jsCaps.wVmax ;
min [ 4 ] = (float) jsCaps.wUmin ; max [ 4 ] = (float) jsCaps.wUmax ;
min [ 3 ] = (float) jsCaps.wRmin ; max [ 3 ] = (float) jsCaps.wRmax ;
min [ 2 ] = (float) jsCaps.wZmin ; max [ 2 ] = (float) jsCaps.wZmax ;
min [ 1 ] = (float) jsCaps.wYmin ; max [ 1 ] = (float) jsCaps.wYmax ;
min [ 0 ] = (float) jsCaps.wXmin ; max [ 0 ] = (float) jsCaps.wXmax ;
}
for ( int i = 0 ; i < num_axes ; i++ )
{
center [ i ] = ( max[i] + min[i] ) / 2.0f ;
dead_band [ i ] = 0.0f ;
saturate [ i ] = 1.0f ;
}
}
void jsJoystick::close ()
{
delete os;
}
jsJoystick::jsJoystick ( int ident )
{
id = ident ;
os = new struct os_specific_s;
if (ident >= 0 && ident < (int)joyGetNumDevs()) {
open();
}
else {
num_axes = 0;
setError();
}
}
void jsJoystick::rawRead ( int *buttons, float *axes )
{
JOYINFOEX js;
js.dwFlags = JOY_RETURNALL ;
js.dwSize = sizeof ( JOYINFOEX) ;
if ( error )
{
if ( buttons )
*buttons = 0 ;
if ( axes )
for ( int i = 0 ; i < num_axes ; i++ )
axes[i] = 1500.0f ;
return ;
}
MMRESULT status = joyGetPosEx ( id, &js ) ;
if ( status != JOYERR_NOERROR )
{
setError() ;
return ;
}
if ( buttons != NULL )
*buttons = (int) js.dwButtons ;
if ( axes != NULL )
{
/* WARNING - Fall through case clauses!! */
switch ( num_axes )
{
case 8:
// Generate two POV axes from the POV hat angle.
// Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
// hundredths of a degree, or 0xFFFF when idle.
if ( ( js.dwPOV & 0xFFFF ) == 0xFFFF )
{
axes [ 6 ] = 0.0 ;
axes [ 7 ] = 0.0 ;
}
else
{
// This is the contentious bit: how to convert angle to X/Y.
// wk: I know of no define for PI that we could use here:
// SG_PI would pull in sg, M_PI is undefined for MSVC
// But the accuracy of the value of PI is very unimportant at
// this point.
float s = (float) sin ( ( js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180 ) ) ;
float c = (float) cos ( ( js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180 ) ) ;
// Convert to coordinates on a square so that North-East
// is (1,1) not (.7,.7), etc.
// s and c cannot both be zero so we won't divide by zero.
if ( fabs ( s ) < fabs ( c ) )
{
axes [ 6 ] = ( c < 0.0 ) ? -s/c : s/c ;
axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f ;
}
else
{
axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f ;
axes [ 7 ] = ( s < 0.0 ) ? -c/s : c/s ;
}
}
case 6: axes[5] = (float) js . dwVpos ;
case 5: axes[4] = (float) js . dwUpos ;
case 4: axes[3] = (float) js . dwRpos ;
case 3: axes[2] = (float) js . dwZpos ;
case 2: axes[1] = (float) js . dwYpos ;
case 1: axes[0] = (float) js . dwXpos ;
break;
default:
ulSetError ( UL_WARNING, "PLIB_JS: Wrong num_axes. Joystick input is now invalid" ) ;
}
}
}
void jsInit() {}
#endif

View file

@ -2,12 +2,12 @@
# include <config.h>
#endif
#ifdef HAVE_WINDOWS_H
#ifdef _WIN32
#include <windows.h>
#endif
#include <string.h> // plib/js.h should really include this !!!!!!
#include <plib/js.h>
#include "Input/FGjs.hxx"
#define Z 8
@ -30,7 +30,7 @@ int main ( int, char ** )
{ useful[i] = ! ( js[i]->notWorking () );
if ( useful[i] ) {
t++;
printf ( "Joystick %i: \"%s\"\n", i, js[i]->getName() ) ;
printf ( "Joystick %i: \"%s\"\n", i, js[i]->getName().c_str() ) ;
} else printf ( "Joystick %i not detected\n", i ) ;
}
if ( t == 0 ) exit ( 1 ) ;

View file

@ -21,12 +21,13 @@
#include <simgear/compiler.h>
#include <iostream>
#include <math.h>
using std::cout;
using std::cin;
using std::endl;
#include "jsinput.h"
#include <plib/ul.h>
jsInput::jsInput(jsSuper *j) {
jss=j;

View file

@ -25,8 +25,7 @@
# include <config.h>
#endif
#include <string.h> // plib/js.h should really include this !!!!!!
#include <plib/js.h>
#include "FGjs.hxx"
#define MAX_JOYSTICKS 8

View file

@ -32,6 +32,7 @@ get_property(FG_LIBS GLOBAL PROPERTY FG_LIBS)
target_link_libraries(fgfs
${FG_LIBS}
${JS_LIBS}
${SIMGEAR_LIBRARIES}
${OPENSCENEGRAPH_LIBRARIES}
${OPENAL_LIBRARY}

View file

@ -18,7 +18,7 @@ endif
if HAVE_FRAMEWORK_PLIB
fgfs_PLIB_FW = $(plib_FRAMEWORK)
else
fgfs_PLIB_LIBS = -lplibpuaux -lplibpu -lplibfnt -lplibjs \
fgfs_PLIB_LIBS = -lplibpuaux -lplibpu -lplibfnt \
-lplibsg -lplibul
endif

View file

@ -6,6 +6,7 @@ target_link_libraries(fgviewer
${OPENSCENEGRAPH_LIBRARIES}
${OPENGL_LIBRARIES}
${ZLIB_LIBRARIES}
${PLIB_LIBRARIES})
${PLIB_LIBRARIES}
${JS_LIBS})
install(TARGETS fgviewer RUNTIME DESTINATION bin)