From: Frederic Bouvier Date: Fri, 14 Jan 2011 20:30:51 +0000 (+0100) Subject: Olaf Flebbe: incorporate plib js code to fix problems with MS joysticks under Vista... X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=4d0a6f5668ff2f8ca59a57a6ddd1c759c410900b;p=flightgear.git Olaf Flebbe: incorporate plib js code to fix problems with MS joysticks under Vista and 7 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 08b2cdd1e..c01dce655 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/CMakeModules/FindPLIB.cmake b/CMakeModules/FindPLIB.cmake index 987943eb1..c92f139b0 100644 --- a/CMakeModules/FindPLIB.cmake +++ b/CMakeModules/FindPLIB.cmake @@ -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) diff --git a/src/Input/CMakeLists.txt b/src/Input/CMakeLists.txt index e0d6abd30..1f8458fa2 100644 --- a/src/Input/CMakeLists.txt +++ b/src/Input/CMakeLists.txt @@ -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 @@ -13,13 +22,18 @@ set(SOURCES FGJoystickInput.cxx FGKeyboardInput.cxx FGMouseInput.cxx - input.cxx + 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 fgjs.cxx jsinput.cxx @@ -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) +add_executable(js_demo js_demo.cxx ) -target_link_libraries(js_demo - ${SIMGEAR_LIBRARIES} +target_link_libraries(js_demo + fgInput + ${JS_LIBS} ${PLIB_LIBRARIES} - ${ZLIB_LIBRARY}) + ) flightgear_component(Input "${SOURCES}") diff --git a/src/Input/FGJoystickInput.cxx b/src/Input/FGJoystickInput.cxx index 349782d5b..df992cf30 100644 --- a/src/Input/FGJoystickInput.cxx +++ b/src/Input/FGJoystickInput.cxx @@ -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; diff --git a/src/Input/FGJoystickInput.hxx b/src/Input/FGJoystickInput.hxx index ef1530ec0..a59f9bbe2 100644 --- a/src/Input/FGJoystickInput.hxx +++ b/src/Input/FGJoystickInput.hxx @@ -31,8 +31,9 @@ #include "FGCommonInput.hxx" #include "FGButton.hxx" +#include "FGjs.hxx" #include -#include + //////////////////////////////////////////////////////////////////////// // The Joystick Input Class diff --git a/src/Input/FGjs.hxx b/src/Input/FGjs.hxx new file mode 100644 index 000000000..0dca92d6e --- /dev/null +++ b/src/Input/FGjs.hxx @@ -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 +#include +#include // -dw- for memcpy +#include + +#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 + + diff --git a/src/Input/Makefile.am b/src/Input/Makefile.am index 4436e28b5..4cdb2fee1 100644 --- a/src/Input/Makefile.am +++ b/src/Input/Makefile.am @@ -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_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 \ diff --git a/src/Input/js.cxx b/src/Input/js.cxx new file mode 100644 index 000000000..055e27f6a --- /dev/null +++ b/src/Input/js.cxx @@ -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 ) ; +} + + + diff --git a/src/Input/jsBSD.cxx b/src/Input/jsBSD.cxx new file mode 100644 index 000000000..811106700 --- /dev/null +++ b/src/Input/jsBSD.cxx @@ -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 . + * Incorporates the original analog joystick driver for BSD by + * Stephen Montgomery-Smith , with + * NetBSD mods courtesy of Rene Hexel. + * + * Bert Driehuis + * + * 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 +#include +#include +#include +#ifdef HAVE_USB_JS + +extern "C" { +# if __FreeBSD_version < 500000 +# include +# else +# define HAVE_USBHID_H 1 +# include +# endif +} + +#include +#include + +/* 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 ], ¢er [ 0 ], &max [ 0 ], + &min [ 1 ], ¢er [ 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 diff --git a/src/Input/jsLinux.cxx b/src/Input/jsLinux.cxx new file mode 100644 index 000000000..5c5636885 --- /dev/null +++ b/src/Input/jsLinux.cxx @@ -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 + +#if defined(JS_VERSION) && JS_VERSION >= 0x010000 + +#include +#include +#include +#include +#include + +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 diff --git a/src/Input/jsMacOSX.cxx b/src/Input/jsMacOSX.cxx new file mode 100644 index 000000000..1e9c3ab26 --- /dev/null +++ b/src/Input/jsMacOSX.cxx @@ -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 +#include +#include +#include +#include +#include +#include + +#ifdef MACOS_10_0_4 +# include +#else +/* The header was moved here in MacOS X 10.1 */ +# include +#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(vjs)-> + os->parseElement( static_cast(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; bhidDev))->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; ahidDev))->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 diff --git a/src/Input/jsNone.cxx b/src/Input/jsNone.cxx new file mode 100644 index 000000000..5ce8cebdd --- /dev/null +++ b/src/Input/jsNone.cxx @@ -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 + diff --git a/src/Input/jsWindows.cxx b/src/Input/jsWindows.cxx new file mode 100644 index 000000000..f38908267 --- /dev/null +++ b/src/Input/jsWindows.cxx @@ -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 +#include +#include +#include + +#include + +#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 diff --git a/src/Input/js_demo.cxx b/src/Input/js_demo.cxx index ee2b32e30..448cecc2c 100644 --- a/src/Input/js_demo.cxx +++ b/src/Input/js_demo.cxx @@ -2,12 +2,12 @@ # include #endif -#ifdef HAVE_WINDOWS_H -# include +#ifdef _WIN32 +#include #endif #include // plib/js.h should really include this !!!!!! -#include +#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 ) ; diff --git a/src/Input/jsinput.cxx b/src/Input/jsinput.cxx index b57f828d2..2c288f640 100644 --- a/src/Input/jsinput.cxx +++ b/src/Input/jsinput.cxx @@ -21,12 +21,13 @@ #include #include - +#include using std::cout; using std::cin; using std::endl; #include "jsinput.h" +#include jsInput::jsInput(jsSuper *j) { jss=j; diff --git a/src/Input/jssuper.h b/src/Input/jssuper.h index 3b395c4cd..398ef579d 100644 --- a/src/Input/jssuper.h +++ b/src/Input/jssuper.h @@ -25,8 +25,7 @@ # include #endif -#include // plib/js.h should really include this !!!!!! -#include +#include "FGjs.hxx" #define MAX_JOYSTICKS 8 diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt index ffc87c857..51dbead5a 100644 --- a/src/Main/CMakeLists.txt +++ b/src/Main/CMakeLists.txt @@ -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} diff --git a/src/Main/Makefile.am b/src/Main/Makefile.am index 7cfe0fd91..0b1e9bab1 100644 --- a/src/Main/Makefile.am +++ b/src/Main/Makefile.am @@ -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 diff --git a/utils/fgviewer/CMakeLists.txt b/utils/fgviewer/CMakeLists.txt index f6654788b..08ff3da34 100644 --- a/utils/fgviewer/CMakeLists.txt +++ b/utils/fgviewer/CMakeLists.txt @@ -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)