diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 0c8b87f2a..4eedfae52 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -30,6 +30,10 @@ if (ENABLE_HID_INPUT) add_subdirectory(hidapi) endif() +if (ENABLE_PLIB_JOYSTICK) + add_subdirectory(joystick) +endif() + if (NOT SYSTEM_CPPUNIT) add_subdirectory(cppunit) endif() diff --git a/3rdparty/joystick/CMakeLists.txt b/3rdparty/joystick/CMakeLists.txt new file mode 100644 index 000000000..a92bf0095 --- /dev/null +++ b/3rdparty/joystick/CMakeLists.txt @@ -0,0 +1,44 @@ +message(STATUS "Enabling legacy joystick code (from PLIB)") + +if(APPLE) + # resolve frameworks to full paths + find_library(IOKIT_LIBRARY IOKit) + find_library(CF_LIBRARY CoreFoundation) + set(JS_LIBS ${IOKIT_LIBRARY} ${CF_LIBRARY}) + set(JS_SOURCES js.cxx jsMacOSX.cxx) +elseif(WIN32) + set(WINMM_LIBRARY winmm) + set(JS_LIBS ${WINMM_LIBRARY}) + set(JS_SOURCES js.cxx jsWindows.cxx) +elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") + set(JS_SOURCES js.cxx jsLinux.cxx) +elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + find_library(USBHID_LIBRARY usbhid) + # check_function_exists(hidinit) + set(JS_LIBS ${USBHID_LIBRARY}) + set(JS_SOURCES js.cxx jsBSD.cxx) +else() + message(WARNING "Unsupported platform for Joystick") + set(JS_SOURCES js.cxx jsNone.cxx) +endif() + +add_library(PLIBJoystick STATIC ${JS_SOURCES}) + +# for logging code at least, more in the future +target_link_libraries(PLIBJoystick SimGearCore) + +if(APPLE) + target_link_libraries(PLIBJoystick ${IOKIT_LIBRARY} ${CF_LIBRARY} ) +elseif(WIN32) + target_link_libraries(PLIBJoystick ${WINMM_LIBRARY}) +elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") + # no libs here? +elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + target_link_libraries(PLIBJoystick ${USBHID_LIBRARY}) +else() + # other / none platform +endif() + +target_include_directories(PLIBJoystick PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +# eof diff --git a/3rdparty/joystick/js.cxx b/3rdparty/joystick/js.cxx new file mode 100644 index 000000000..15d584e68 --- /dev/null +++ b/3rdparty/joystick/js.cxx @@ -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 + +*/ + +#include "config.h" + +#include "js.h" + +#include + +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 ) ; +} + +void jsSetError(int level, const std::string& msg) +{ + SG_LOG(SG_INPUT, static_cast(level), msg); +} diff --git a/3rdparty/joystick/js.h b/3rdparty/joystick/js.h new file mode 100644 index 000000000..b22fdd337 --- /dev/null +++ b/3rdparty/joystick/js.h @@ -0,0 +1,96 @@ +/* + 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 +#define JS_NEW + +#include +#include +#include + +#define _JS_MAX_AXES 16 +#define _JS_MAX_BUTTONS 32 +#define _JS_MAX_HATS 4 + +#define JS_TRUE 1 +#define JS_FALSE 0 + + +class jsJoystick +{ + int id ; +protected: + struct os_specific_s *os ; + friend struct os_specific_s ; + int error ; + char name [ 128 ] ; + 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 ; + +public: + + jsJoystick ( int ident = 0 ) ; + ~jsJoystick () { close () ; } + + const char* getName () const { return name ; } + int getNumAxes () const { return num_axes ; } + int getNumButtons () const { return num_buttons; } + int notWorking () const { return error ; } + void setError () { error = JS_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 ) ; + void rawRead ( int *buttons, float *axes ) ; + // bool SetForceFeedBack ( int axe, float force ); +} ; + +extern void jsInit () ; + +void jsSetError(int, const std::string& msg); + +#endif diff --git a/3rdparty/joystick/jsBSD.cxx b/3rdparty/joystick/jsBSD.cxx new file mode 100644 index 000000000..b850ab910 --- /dev/null +++ b/3rdparty/joystick/jsBSD.cxx @@ -0,0 +1,518 @@ +/* + 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 2133 2008-07-18 14:32:22Z 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. + */ + +#include "js.h" + +#if defined(__NetBSD__) || defined(__FreeBSD__) +#define HAVE_USB_JS 1 +#endif + +#include +#include +#include +#if defined(__FreeBSD__) +# include +#else +# include // For analog joysticks +#endif +#ifdef HAVE_USB_JS +#if defined(__NetBSD__) +#ifdef HAVE_USBHID_H +#include +#else +#include +#endif +#elif defined(__FreeBSD__) +extern "C" { +# if __FreeBSD_version < 500000 +# include +# else +# define HAVE_USBHID_H 1 +# include +# endif +} +#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 ] ; + float axes_minimum [ _JS_MAX_AXES ] ; + float axes_maximum [ _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" + +#ifdef HAVE_USB_JS +/* + * 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; + os->axes_minimum[*num_axes] = h.logical_minimum; + os->axes_maximum[*num_axes] = h.logical_maximum; + (*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); +} +#endif + +void jsJoystick::open () +{ + char *cp; + + name [0] = '\0' ; + + 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 ) + { + jsSetError ( SG_WARN, "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 + } + +#ifdef HAVE_USB_JS + if ( !joy_initialize_hid(os, &num_axes, &num_buttons ) ) + { + ::close(os->fd); + error = 1; + return; + } + + cp = strrchr(os->fname, '/'); + if (cp) { + if (findusbdev(&cp[1], name, sizeof(name)) == 0) + strcpy(name, &cp[1]); + } + + if ( num_axes > _JS_MAX_AXES ) + num_axes = _JS_MAX_AXES ; + + for ( int i = 0 ; i < _JS_MAX_AXES ; i++ ) + { + if ( os->axes_usage [ i ] == HUG_HAT_SWITCH ) + { + max [ i ] = 1.0f ; + center [ i ] = 0.0f ; + min [ i ] = -1.0f ; + } + else + { + max [ i ] = os->axes_maximum [ i ]; + min [ i ] = os->axes_minimum [ i ]; + center [ i ] = (max [ i ] + min [ i ]) / 2; + } + dead_band [ i ] = 0.0f ; + saturate [ i ] = 1.0f ; + } +#endif +} + + + +void jsJoystick::close () +{ + if (os) { + if ( ! error ) + ::close ( os->fd ) ; +#ifdef HAVE_USB_JS + if (os->hids) + delete os->hids; + if (os->hid_data_buf) + delete os->hid_data_buf; +#endif + 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; + } + +#ifdef HAVE_USB_JS + 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 ) ; +#endif +} + +void jsInit () {} diff --git a/3rdparty/joystick/jsLinux.cxx b/3rdparty/joystick/jsLinux.cxx new file mode 100644 index 000000000..ad2f89ce5 --- /dev/null +++ b/3rdparty/joystick/jsLinux.cxx @@ -0,0 +1,202 @@ +/* + 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 $ +*/ + +#include "js.h" + +#include +#include + +#include + + +#if defined(JS_VERSION) && JS_VERSION >= 0x010000 + +#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 ; + ioctl ( os->fd, JSIOCGNAME ( sizeof(name) ), name ) ; + fcntl ( os->fd, F_SETFL , O_NONBLOCK ) ; + + 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: + jsSetError ( SG_WARN, "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 diff --git a/3rdparty/joystick/jsMacOSX.cxx b/3rdparty/joystick/jsMacOSX.cxx new file mode 100644 index 000000000..18e641734 --- /dev/null +++ b/3rdparty/joystick/jsMacOSX.cxx @@ -0,0 +1,464 @@ +/* + 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 2165 2011-01-22 22:56:03Z fayjf $ +*/ + +#include "js.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 + +#include + +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) { + jsSetError(SG_WARN, "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) { + jsSetError(SG_WARN, "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(JS_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")); + + if (!ref || !CFStringGetCString ((CFStringRef) ref, name, 128, CFStringGetSystemEncoding ())) { + jsSetError(SG_WARN, "error getting device name"); + name[0] = '\0'; + } + //printf("Joystick name: %s \n", name); + open(); +} + +void jsJoystick::open() +{ +#if 0 // test already done in the constructor + if (id >= numDevices) { + jsSetError(SG_WARN, "device index out of range in jsJoystick::open"); + return; + } +#endif + + // create device interface + IOReturn rv; + SInt32 score; + IOCFPlugInInterface **plugin; + + rv = IOCreatePlugInInterfaceForService(ioDevices[id], + kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, + &plugin, &score); + + if (rv != kIOReturnSuccess) { + jsSetError(SG_WARN, "error creting plugin for io device"); + return; + } + + HRESULT pluginResult = (*plugin)->QueryInterface(plugin, + CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID*)&(os->hidDev) ); + + if (pluginResult != S_OK) + jsSetError(SG_WARN, "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) { + jsSetError(SG_WARN, "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; + +#if 0 + // comment copied from darwin/SDL_sysjoystick.c + /* Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + * get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + */ + + io_registry_entry_t parent1, parent2; + + rv = IORegistryEntryGetParentEntry (ioDev, kIOServicePlane, &parent1); + if (rv != kIOReturnSuccess) { + jsSetError(SG_WARN, "error getting device entry parent"); + return NULL; + } + + rv = IORegistryEntryGetParentEntry (parent1, kIOServicePlane, &parent2); + if (rv != kIOReturnSuccess) { + jsSetError(SG_WARN, "error getting device entry parent 2"); + return NULL; + } + +#endif + rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/, + &cfProperties, kCFAllocatorDefault, kNilOptions); + if (rv != kIOReturnSuccess || !cfProperties) { + jsSetError(SG_WARN, "error getting device properties"); + return NULL; + } + + return cfProperties; +} + +void jsJoystick::close() +{ + if (!os) + return; + 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()) { + jsSetError(SG_WARN, "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: + SG_LOG(SG_INPUT, SG_WARN, "input type element has weird usage:" << usage); + break; + } + } else if (page == kHIDPage_Simulation) { + switch (usage) /* look at usage to determine function */ + { + case kHIDUsage_Sim_Rudder: + case kHIDUsage_Sim_Throttle: + //printf(" axis\n"); + /*joy->os->*/addAxisElement(joy, (CFDictionaryRef) element); + break; + default: + SG_LOG(SG_INPUT, SG_WARN, "Simulation page input type element has weird usage:" << usage); + } + } else if (page == kHIDPage_Button) { + //printf(" button\n"); + /*joy->os->*/addButtonElement(joy, (CFDictionaryRef) element); + } else if (page == kHIDPage_PID) { + SG_LOG(SG_INPUT, SG_WARN, "Force feedback and related data ignored"); + } else + SG_LOG(SG_INPUT, SG_WARN, "input type element has weird usage:" << 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) +{ + if (buttons) + *buttons = 0; + + IOHIDEventStruct hidEvent; + + for (int b=0; bhidDev))->getElementValue(os->hidDev, os->buttonCookies[b], &hidEvent); + if (hidEvent.value && buttons) + *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; + } + } +} diff --git a/3rdparty/joystick/jsNone.cxx b/3rdparty/joystick/jsNone.cxx new file mode 100644 index 000000000..e5de5c2e0 --- /dev/null +++ b/3rdparty/joystick/jsNone.cxx @@ -0,0 +1,54 @@ +/* + 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 $ +*/ + +#include "js.h" + +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 () {} diff --git a/3rdparty/joystick/jsWindows.cxx b/3rdparty/joystick/jsWindows.cxx new file mode 100644 index 000000000..6fa162db9 --- /dev/null +++ b/3rdparty/joystick/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 2164 2011-01-22 22:47:30Z fayjf $ +*/ + +#include "js.h" + +#include + +#include +#include // for REGSTR_PATH_JOYCONFIG, etc + +#define _JS_MAX_AXES_WIN 8 /* X,Y,Z,R,U,V,POV_X,POV_Y */ + +struct os_specific_s { + JOYCAPS jsCaps ; + JOYINFOEX js ; + UINT js_id ; + static bool getOEMProductName ( jsJoystick* joy, char *buf, int buf_sz ) ; +}; + + + +// Inspired by +// http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp + +bool os_specific_s::getOEMProductName ( jsJoystick* joy, char *buf, int buf_sz ) +{ + if ( joy->error ) return false ; + + union + { + char key [ 256 ] ; + char value [ 256 ] ; + } ; + char OEMKey [ 256 ] ; + + HKEY hKey ; + DWORD dwcb ; + LONG lr ; + int hkcu = 0; + + // Open .. MediaResources\CurrentJoystickSettings + sprintf ( key, "%s\\%s\\%s", + REGSTR_PATH_JOYCONFIG, joy->os->jsCaps.szRegKey, + REGSTR_KEY_JOYCURR ) ; + + lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, &hKey) ; + + if ( lr != ERROR_SUCCESS ) + { + hkcu = 1; + // XP/Vista/7 seem to have moved it to "current user" + lr = RegOpenKeyEx ( HKEY_CURRENT_USER, key, 0, KEY_QUERY_VALUE, &hKey) ; + if ( lr != ERROR_SUCCESS ) return false ; + } + + // Get OEM Key name + dwcb = sizeof(OEMKey) ; + + // JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based. + sprintf ( value, "Joystick%d%s", joy->os->js_id + 1, REGSTR_VAL_JOYOEMNAME ) ; + + lr = RegQueryValueEx ( hKey, value, 0, 0, (LPBYTE) OEMKey, &dwcb); + RegCloseKey ( hKey ) ; + + if ( lr != ERROR_SUCCESS ) return false ; + + // Open OEM Key from ...MediaProperties + sprintf ( key, "%s\\%s", REGSTR_PATH_JOYOEM, OEMKey ) ; + + if (!hkcu) + lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, key, 0, KEY_QUERY_VALUE, &hKey) ; + else + lr = RegOpenKeyEx ( HKEY_CURRENT_USER, key, 0, KEY_QUERY_VALUE, &hKey) ; + if ( lr != ERROR_SUCCESS ) + { + return false ; + } + + // Get OEM Name + dwcb = buf_sz ; + + lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buf, + &dwcb ) ; + RegCloseKey ( hKey ) ; + + if ( lr != ERROR_SUCCESS ) return false ; + + return true ; +} + + +void jsJoystick::open () +{ + name [0] = '\0' ; + + os->js . dwFlags = JOY_RETURNALL ; + os->js . dwSize = sizeof ( os->js ) ; + + memset ( &(os->jsCaps), 0, sizeof(os->jsCaps) ) ; + + error = ( joyGetDevCaps( os->js_id, &(os->jsCaps), sizeof(os->jsCaps) ) + != JOYERR_NOERROR ) ; + num_buttons = os->jsCaps.wNumButtons ; + if ( os->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. + if ( ! os->getOEMProductName ( this, name, sizeof(name) ) ) + { + jsSetError ( SG_WARN, + "JS: Failed to read joystick name from registry" ) ; + + strncpy ( name, os->jsCaps.szPname, sizeof(name) ) ; + } + + // Windows joystick drivers may provide any combination of + // X,Y,Z,R,U,V,POV - not necessarily the first n of these. + if ( os->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) os->jsCaps.wVmin ; max [ 5 ] = (float) os->jsCaps.wVmax ; + min [ 4 ] = (float) os->jsCaps.wUmin ; max [ 4 ] = (float) os->jsCaps.wUmax ; + min [ 3 ] = (float) os->jsCaps.wRmin ; max [ 3 ] = (float) os->jsCaps.wRmax ; + min [ 2 ] = (float) os->jsCaps.wZmin ; max [ 2 ] = (float) os->jsCaps.wZmax ; + min [ 1 ] = (float) os->jsCaps.wYmin ; max [ 1 ] = (float) os->jsCaps.wYmax ; + min [ 0 ] = (float) os->jsCaps.wXmin ; max [ 0 ] = (float) os->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()) { + os->js_id = JOYSTICKID1 + ident; + open(); + } + else { + num_axes = 0; + setError(); + } +} + + + +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 ; + } + + MMRESULT status = joyGetPosEx ( os->js_id, &(os->js) ) ; + + if ( status != JOYERR_NOERROR ) + { + setError() ; + return ; + } + + if ( buttons != NULL ) + *buttons = (int) os->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 ( ( os->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 ( ( os->js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180 ) ) ; + float c = (float) cos ( ( os->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) os->js . dwVpos ; + case 5: axes[4] = (float) os->js . dwUpos ; + case 4: axes[3] = (float) os->js . dwRpos ; + case 3: axes[2] = (float) os->js . dwZpos ; + case 2: axes[1] = (float) os->js . dwYpos ; + case 1: axes[0] = (float) os->js . dwXpos ; + break; + + default: + jsSetError ( SG_WARN, "PLIB_JS: Wrong num_axes. Joystick input is now invalid" ) ; + } + } +} + +void jsInit() {} diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c36c208c..c7243db02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -222,7 +222,10 @@ option(ENABLE_QT "Set to ON to build the internal Qt launcher" ON) option(ENABLE_TRAFFIC "Set to ON to build the external traffic generator modules" ON) option(ENABLE_FGQCANVAS "Set to ON to build the Qt-based remote canvas application" OFF) option(ENABLE_DEMCONVERT "Set to ON to build the dem conversion tool (default)" ON) -option(ENABLE_HID_INPUT "Set to ON to build HID-based input code (default)" OFF) +option(ENABLE_HID_INPUT "Set to ON to build HID-based input code" OFF) +option(ENABLE_PLIB_JOYSTICK "Set to ON to enable legacy joystick code (default)" ON) + + # Test-suite options. option(ENABLE_AUTOTESTING "Set to ON to execute the test suite after building the test_suite target (default)" ON) @@ -281,12 +284,6 @@ if(EVENT_INPUT) message(STATUS "Enabling HID-API input") list(APPEND EVENT_INPUT_LIBRARIES hidapi) endif() - - # Keep PLIB INPUT enabled as long as EventInput does not replace current joystick configurations. - set(ENABLE_PLIB_JOYSTICK 1) -else(EVENT_INPUT) - message(STATUS "Event-based input disabled by config") - set(ENABLE_PLIB_JOYSTICK 1) endif(EVENT_INPUT) # check required dependencies @@ -404,7 +401,7 @@ else() endif (ENABLE_QT) ############################################################################## -find_package(PLIB REQUIRED puaux pu js fnt) +find_package(PLIB REQUIRED puaux pu fnt) # FlightGear and SimGear versions need to match major + minor # split version string into components, note CMAKE_MATCH_0 is the entire regexp match diff --git a/CMakeModules/FindPLIB.cmake b/CMakeModules/FindPLIB.cmake index b787983c1..9dd900649 100644 --- a/CMakeModules/FindPLIB.cmake +++ b/CMakeModules/FindPLIB.cmake @@ -1,7 +1,7 @@ # Locate PLIB # This module defines # PLIB_LIBRARIES -# PLIB_FOUND, if false, do not try to link to PLIB +# PLIB_FOUND, if false, do not try to link to PLIB # PLIB_INCLUDE_DIR, where to find the headers # # $PLIBDIR is an environment variable that would @@ -28,14 +28,14 @@ include(SelectLibraryConfigurations) set(save_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) set(CMAKE_FIND_FRAMEWORK ONLY) FIND_PATH(PLIB_INCLUDE_DIR ul.h - PATH_SUFFIXES include/plib include + PATH_SUFFIXES include/plib include PATHS ${ADDITIONAL_LIBRARY_PATHS} ) set(CMAKE_FIND_FRAMEWORK ${save_FIND_FRAMEWORK}) if(NOT PLIB_INCLUDE_DIR) FIND_PATH(PLIB_INCLUDE_DIR plib/ul.h - PATH_SUFFIXES include + PATH_SUFFIXES include HINTS $ENV{PLIBDIR} PATHS ${ADDITIONAL_LIBRARY_PATHS} ) @@ -51,7 +51,7 @@ FIND_LIBRARY(PLIB_LIBRARIES PATHS ${ADDITIONAL_LIBRARY_PATHS} ) -if (MSVC) +if (MSVC) set (PUNAME "pui") else (MSVC) set (PUNAME "pu") @@ -65,7 +65,7 @@ macro(find_static_component comp libs) else(MSVC) set(compLib "plib${comp}") endif(MSVC) - + string(TOUPPER "PLIB_${comp}" compLibBase) set( compLibName ${compLibBase}_LIBRARY ) @@ -97,13 +97,13 @@ macro(find_static_component comp libs) endif() endmacro() -if(${PLIB_LIBRARIES} STREQUAL "PLIB_LIBRARIES-NOTFOUND") +if(${PLIB_LIBRARIES} STREQUAL "PLIB_LIBRARIES-NOTFOUND") set(PLIB_LIBRARIES "") # clear value - + # based on the contents of deps, add other required PLIB # static library dependencies. Eg PUI requires FNT set(outDeps ${PLIB_FIND_COMPONENTS}) - + foreach(c ${PLIB_FIND_COMPONENTS}) if (${c} STREQUAL "pu") # handle MSVC confusion over pu/pui naming, by removing @@ -116,7 +116,7 @@ if(${PLIB_LIBRARIES} STREQUAL "PLIB_LIBRARIES-NOTFOUND") list(APPEND outDeps "sg") endif() endforeach() - + list(APPEND outDeps "ul") # everything needs ul list(REMOVE_DUPLICATES outDeps) # clean up @@ -127,30 +127,5 @@ 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) - set(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/CMakeModules/SetupFGFSLibraries.cmake b/CMakeModules/SetupFGFSLibraries.cmake index ad1e85cbc..d0017ccf7 100644 --- a/CMakeModules/SetupFGFSLibraries.cmake +++ b/CMakeModules/SetupFGFSLibraries.cmake @@ -56,6 +56,9 @@ function(setup_fgfs_libraries target) ${SIMGEAR_LIBRARIES} ) + if (ENABLE_PLIB_JOYSTICK) + target_link_libraries(${target} PLIBJoystick) + endif() if(ENABLE_FLITE) if(SYSTEM_HTS_ENGINE) diff --git a/src/Include/config_cmake.h.in b/src/Include/config_cmake.h.in index 1a2e172ea..dae4eafed 100644 --- a/src/Include/config_cmake.h.in +++ b/src/Include/config_cmake.h.in @@ -51,6 +51,7 @@ #cmakedefine ENABLE_FLITE #cmakedefine ENABLE_HID_INPUT +#cmakedefine ENABLE_PLIB_JOYSTICK #cmakedefine HAVE_QT diff --git a/src/Input/CMakeLists.txt b/src/Input/CMakeLists.txt index f3e9cf993..606d30846 100644 --- a/src/Input/CMakeLists.txt +++ b/src/Input/CMakeLists.txt @@ -15,13 +15,11 @@ if (ENABLE_HID_INPUT) list(APPEND EVENT_INPUT_HEADERS FGHIDEventInput.hxx) endif() - set(SOURCES FGButton.cxx FGCommonInput.cxx FGDeviceConfigurationMap.cxx FGEventInput.cxx - FGJoystickInput.cxx FGKeyboardInput.cxx FGMouseInput.cxx input.cxx @@ -32,19 +30,23 @@ set(HEADERS FGCommonInput.hxx FGDeviceConfigurationMap.hxx FGEventInput.hxx - FGJoystickInput.hxx FGKeyboardInput.hxx FGMouseInput.hxx input.hxx ) +if (ENABLE_PLIB_JOYSTICK) + list(APPEND SOURCES FGJoystickInput.cxx) + list(APPEND HEADERS FGJoystickInput.hxx) +endif() + if(EVENT_INPUT) list(APPEND SOURCES ${EVENT_INPUT_SOURCES}) - list(APPEND SOURCES ${EVENT_INPUT_HEADERS}) + list(APPEND HEADERS ${EVENT_INPUT_HEADERS}) include_directories(${UDEV_INCLUDE_DIR}) endif() -if(ENABLE_FGJS) +if(ENABLE_FGJS AND ENABLE_PLIB_JOYSTICK) set(FGJS_SOURCES fgjs.cxx jsinput.cxx @@ -53,18 +55,18 @@ if(ENABLE_FGJS) add_executable(fgjs ${FGJS_SOURCES}) target_link_libraries(fgjs - SimGearCore - ${PLIB_LIBRARIES} + SimGearCore + PLIBJoystick ) install(TARGETS fgjs RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() -if(ENABLE_JS_DEMO) +if(ENABLE_JS_DEMO AND ENABLE_PLIB_JOYSTICK) add_executable(js_demo js_demo.cxx) target_link_libraries(js_demo SimGearCore - ${PLIB_LIBRARIES} + PLIBJoystick ) install(TARGETS js_demo RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/Input/input.cxx b/src/Input/input.cxx index 88f011423..3886ffbb6 100644 --- a/src/Input/input.cxx +++ b/src/Input/input.cxx @@ -31,7 +31,10 @@ #include
#include "FGMouseInput.hxx" #include "FGKeyboardInput.hxx" + +#if defined(ENABLE_PLIB_JOYSTICK) #include "FGJoystickInput.hxx" +#endif #ifdef WITH_EVENTINPUT #if defined( SG_WINDOWS ) @@ -71,11 +74,14 @@ FGInput::FGInput () set_subsystem( "input-keyboard", new FGKeyboardInput() ); } +#if defined(ENABLE_PLIB_JOYSTICK) if( fgGetBool("/sim/input/no-joystick-input",false) ) { SG_LOG(SG_INPUT,SG_ALERT,"Joystick input disabled!"); } else { set_subsystem( "input-joystick", new FGJoystickInput() ); } +#endif + #ifdef INPUTEVENT_CLASS if( fgGetBool("/sim/input/no-event-input",false) ) { SG_LOG(SG_INPUT,SG_ALERT,"Event input disabled!"); diff --git a/src/Input/jsinput.cxx b/src/Input/jsinput.cxx index b57f828d2..0fbce4b16 100644 --- a/src/Input/jsinput.cxx +++ b/src/Input/jsinput.cxx @@ -28,6 +28,8 @@ using std::endl; #include "jsinput.h" +#include + jsInput::jsInput(jsSuper *j) { jss=j; pretty_display=true; @@ -109,7 +111,7 @@ int jsInput::getInput() { fflush ( stdout ) ; } - ulMilliSecondSleep(1); + SGTimeStamp::sleepForMSec(1); } if(button_bits != 0) { for(int i=0;i<=31;i++) { @@ -138,12 +140,12 @@ void jsInput::findDeadBand() { } } while( jss->nextJoystick() ); - ulClock clock; + SGTimeStamp clock = SGTimeStamp::now(); cout << 10; cout.flush(); for (int j = 9; j >= 0; j--) { - double start_time = clock.getAbsTime(); + clock.stamp(); do { jss->firstJoystick(); do { @@ -159,9 +161,8 @@ void jsInput::findDeadBand() { } while( jss->nextJoystick()); - ulMilliSecondSleep(1); - clock.update(); - } while (clock.getAbsTime() - start_time < 1.0); + SGTimeStamp::sleepForMSec(1); + } while (clock.elapsedMSec() < 1000); cout << " - " << j; cout.flush(); diff --git a/src/Input/jsinput.h b/src/Input/jsinput.h index 73346e030..0557394a5 100644 --- a/src/Input/jsinput.h +++ b/src/Input/jsinput.h @@ -23,6 +23,8 @@ #ifndef _JSINPUT_H #define _JSINPUT_H +#include // for fabs + #include "jssuper.h" class jsInput { diff --git a/src/Input/jssuper.h b/src/Input/jssuper.h index 3b395c4cd..86eed5778 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 "js.h" #define MAX_JOYSTICKS 8 @@ -37,28 +36,28 @@ class jsSuper { int currentJoystick; int first, last; jsJoystick* js[MAX_JOYSTICKS]; - - public: + + public: jsSuper(void); ~jsSuper(void); - + inline int getNumJoysticks(void) { return activeJoysticks; } - + inline int atFirst(void) { return currentJoystick == first; } inline int atLast(void) { return currentJoystick == last; } - + inline void firstJoystick(void) { currentJoystick=first; } inline void lastJoystick(void) { currentJoystick=last; } int nextJoystick(void); int prevJoystick(void); - inline jsJoystick* getJoystick(int Joystick) + inline jsJoystick* getJoystick(int Joystick) { currentJoystick=Joystick; return js[Joystick]; } inline jsJoystick* getJoystick(void) { return js[currentJoystick]; } - + inline int getCurrentJoystickId(void) { return currentJoystick; } }; - -#endif + +#endif