]> git.mxchange.org Git - flightgear.git/commitdiff
Olaf Flebbe: incorporate plib js code to fix problems with MS joysticks under Vista...
authorFrederic Bouvier <fredfgfs01@free.fr>
Fri, 14 Jan 2011 20:30:51 +0000 (21:30 +0100)
committerFrederic Bouvier <fredfgfs01@free.fr>
Fri, 14 Jan 2011 20:32:59 +0000 (21:32 +0100)
19 files changed:
CMakeLists.txt
CMakeModules/FindPLIB.cmake
src/Input/CMakeLists.txt
src/Input/FGJoystickInput.cxx
src/Input/FGJoystickInput.hxx
src/Input/FGjs.hxx [new file with mode: 0644]
src/Input/Makefile.am
src/Input/js.cxx [new file with mode: 0644]
src/Input/jsBSD.cxx [new file with mode: 0644]
src/Input/jsLinux.cxx [new file with mode: 0644]
src/Input/jsMacOSX.cxx [new file with mode: 0644]
src/Input/jsNone.cxx [new file with mode: 0644]
src/Input/jsWindows.cxx [new file with mode: 0644]
src/Input/js_demo.cxx
src/Input/jsinput.cxx
src/Input/jssuper.h
src/Main/CMakeLists.txt
src/Main/Makefile.am
utils/fgviewer/CMakeLists.txt

index 08b2cdd1ee4ca68eabc39bceda385a695c3a988d..c01dce65559ffc900f6fa49c4b1e41847dc0b9fe 100644 (file)
@@ -80,6 +80,25 @@ if(EVENT_INPUT)
        endif()
 else(EVENT_INPUT)
        set(ENABLE_PLIB_JOYSTICK 1)
+
+    message(STATUS "adding runtime JS dependencies")
+    if(APPLE)
+    # resolve frameworks to full paths
+        find_library(IOKIT_LIBRARY IOKit)
+        find_library(CF_LIBRARY CoreFoundation)
+        set(JS_LIBS ${IOKIT_LIBRARY} ${CF_LIBRARY})
+    elseif(WIN32)
+        find_library(WINMM_LIBRARY winmm)
+        set(JS_LIBS ${WINMM_LIBRARY})
+    elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
+        # anything needed here?
+    elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+        find_library(USBHID_LIBRARY usbhid)
+        # check_function_exists(hidinit)
+        set(JS_LIBS ${USBHID_LIBRARY})
+    else()
+        message(WARNING "Unsupported platform for JS libs")
+    endif()
 endif(EVENT_INPUT)
 
 if (MSVC_3RDPARTY_DIR)
@@ -116,7 +135,7 @@ if(ENABLE_LIBSVN)
        endif(LIBSVN_FOUND)
 endif(ENABLE_LIBSVN)
 
-find_package(PLIB REQUIRED puaux pu js fnt)
+find_package(PLIB REQUIRED puaux pu fnt)
 find_package(SimGear 2.2.0 REQUIRED)
 
 check_include_file(unistd.h HAVE_UNISTD_H)
index 987943eb103872e0ed2c504e5beb7db6e9c68360..c92f139b07118aeb47b3f362cd8271fea6e47dd1 100644 (file)
@@ -152,30 +152,6 @@ if(${PLIB_LIBRARIES} STREQUAL "PLIB_LIBRARIES-NOTFOUND")
     endforeach()
 endif()
 
-list(FIND outDeps "js" haveJs)
-if(${haveJs} GREATER -1)
-    message(STATUS "adding runtime JS dependencies")
-    if(APPLE)
-    # resolve frameworks to full paths
-        find_library(IOKIT_LIBRARY IOKit)
-        find_library(CF_LIBRARY CoreFoundation)
-        set(JS_LIBS ${IOKIT_LIBRARY} ${CF_LIBRARY})
-    elseif(WIN32)
-        find_library(WINMM_LIBRARY winmm)
-        set(JS_LIBS ${WINMM_LIBRARY})
-    elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
-        # anything needed here?
-    elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
-        find_library(USBHID_LIBRARY usbhid)
-        # check_function_exists(hidinit)
-        set(JS_LIBS ${USBHID_LIBRARY})
-    else()
-        message(WARNING "Unsupported platform for PLIB JS libs")
-    endif()
-    
-    list(APPEND PLIB_LIBRARIES ${JS_LIBS})
-endif()
-
 include(FindPackageHandleStandardArgs)
 FIND_PACKAGE_HANDLE_STANDARD_ARGS(PLIB DEFAULT_MSG PLIB_LIBRARIES PLIB_INCLUDE_DIR)
 
index e0d6abd30ca1065516d7ad69bec3f301bab9c545..1f8458fa2734e9d94f143ff42de41813afd2abe8 100644 (file)
@@ -5,6 +5,15 @@ set(EVENT_INPUT_SOURCES
        FGMacOSXEventInput.cxx
        )
 
+set (JS_INPUT_SOURCES
+       js.cxx
+       jsBSD.cxx
+       jsLinux.cxx
+       jsMacOSX.cxx
+       jsWindows.cxx
+       jsNone.cxx
+       )
+
 set(SOURCES
        FGButton.cxx
        FGCommonInput.cxx
@@ -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}")
 
index 349782d5b5e3c890abfb46e89a7c45c3e79cd59a..df992cf303c73680c831bed019547cc71c7d740e 100644 (file)
@@ -89,7 +89,7 @@ void FGJoystickInput::init()
       continue;
     }
 
-    const char * name = js->getName();
+    std::string name = js->getName();
     SGPropertyNode_ptr js_node = js_nodes->getChild("js", i);
 
     if (js_node) {
@@ -130,14 +130,8 @@ void FGJoystickInput::postinit()
     if (!js_node || js->notWorking())
       continue;
 
-#ifdef WIN32
-    JOYCAPS jsCaps ;
-    joyGetDevCaps( i, &jsCaps, sizeof(jsCaps) );
-    unsigned int nbuttons = jsCaps.wNumButtons;
+    int nbuttons = js->getNumButtons();
     if (nbuttons > MAX_JOYSTICK_BUTTONS) nbuttons = MAX_JOYSTICK_BUTTONS;
-#else
-    unsigned int nbuttons = MAX_JOYSTICK_BUTTONS;
-#endif
 
     int naxes = js->getNumAxes();
     if (naxes > MAX_JOYSTICK_AXES) naxes = MAX_JOYSTICK_AXES;
index ef1530ec025497194ce8559381abc70efe8bde27..a59f9bbe20dc4142e889bc23640b1bc9773a3dec 100644 (file)
@@ -31,8 +31,9 @@
 
 #include "FGCommonInput.hxx"
 #include "FGButton.hxx"
+#include "FGjs.hxx"
 #include <simgear/structure/subsystem_mgr.hxx>
-#include <plib/js.h>
+
 
 ////////////////////////////////////////////////////////////////////////
 // The Joystick Input Class
diff --git a/src/Input/FGjs.hxx b/src/Input/FGjs.hxx
new file mode 100644 (file)
index 0000000..0dca92d
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+     PLIB - A Suite of Portable Game Libraries
+     Copyright (C) 1998,2002  Steve Baker
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Library General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Library General Public License for more details.
+
+     You should have received a copy of the GNU Library General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+     For further information visit http://plib.sourceforge.net
+
+     $Id: js.h 2067 2006-01-30 07:36:01Z bram $
+*/
+
+#ifndef __INCLUDED_JS_H__
+#define __INCLUDED_JS_H__ 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // -dw- for memcpy
+#include <string>
+
+#define _JS_MAX_AXES 16
+#define _JS_MAX_BUTTONS 32
+#define _JS_MAX_HATS 4
+
+class jsJoystick
+{
+  int          id ;
+protected:
+  struct os_specific_s *os ;
+  friend struct os_specific_s ;
+  bool          error        ;
+  std::string  name;
+  int          num_axes     ;
+  int          num_buttons  ;
+
+  float dead_band [ _JS_MAX_AXES ] ;
+  float saturate  [ _JS_MAX_AXES ] ;
+  float center    [ _JS_MAX_AXES ] ;
+  float max       [ _JS_MAX_AXES ] ;
+  float min       [ _JS_MAX_AXES ] ;
+
+  void open () ;
+  void close () ;
+
+  float fudge_axis ( float value, int axis ) const ;
+  void rawRead ( int *buttons, float *axes ) ;
+
+public:
+
+  jsJoystick ( int ident = 0 ) ;
+  ~jsJoystick () { close () ; }
+
+  std::string getName () const { return name ;     }
+  int   getNumAxes    () const { return num_axes ; }
+  int   getNumButtons () const { return num_buttons; }
+  bool   notWorking    () const { return error ;    }
+  void  setError      () { error = true ; }
+
+  float getDeadBand ( int axis ) const       { return dead_band [ axis ] ; }
+  void  setDeadBand ( int axis, float db )   { dead_band [ axis ] = db   ; }
+
+  float getSaturation ( int axis ) const     { return saturate [ axis ]  ; }
+  void  setSaturation ( int axis, float st ) { saturate [ axis ] = st    ; }
+
+  void setMinRange ( float *axes ) { memcpy ( min   , axes, num_axes * sizeof(float) ) ; }
+  void setMaxRange ( float *axes ) { memcpy ( max   , axes, num_axes * sizeof(float) ) ; }
+  void setCenter   ( float *axes ) { memcpy ( center, axes, num_axes * sizeof(float) ) ; }
+
+  void getMinRange ( float *axes ) const { memcpy ( axes, min   , num_axes * sizeof(float) ) ; }
+  void getMaxRange ( float *axes ) const { memcpy ( axes, max   , num_axes * sizeof(float) ) ; }
+  void getCenter   ( float *axes ) const { memcpy ( axes, center, num_axes * sizeof(float) ) ; }
+
+  void read    ( int *buttons, float *axes ) ;
+  // bool SetForceFeedBack ( int axe, float force );
+} ;
+
+extern void jsInit () ;
+
+#endif
+
+
index 4436e28b5aa6c5dfe34f9a1a12f574b39f65be0a..4cdb2fee1b7f96877badd0fc9c18f823547fb219 100644 (file)
@@ -18,8 +18,6 @@ if HAVE_FRAMEWORK_PLIB
 js_demo_LDFLAGS = $(plib_FRAMEWORK)
 fgjs_LDFLAGS = $(plib_FRAMEWORK) 
 else
-js_demo_PLIB_LIBS = -lplibjs -lplibul
-fgjs_PLIB_LIBS = -lplibjs -lplibul
 js_demo_LDFLAGS =
 fgjs_LDFLAGS=
 endif
@@ -36,17 +34,18 @@ libInput_a_SOURCES = input.cxx input.hxx FGCommonInput.cxx FGCommonInput.hxx \
        FGMouseInput.cxx FGMouseInput.hxx \
        FGKeyboardInput.cxx FGKeyboardInput.hxx \
        FGJoystickInput.cxx FGJoystickInput.hxx \
+       js.cxx jsBSD.cxx jsLinux.cxx jsMacOSX.cxx jsNone.cxx FGjs.hxx \
         $(libInput_Event_SOURCES)
 
 bin_PROGRAMS = js_demo fgjs
 
-js_demo_SOURCES = js_demo.cxx
+js_demo_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 (file)
index 0000000..055e27f
--- /dev/null
@@ -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 (file)
index 0000000..8111067
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+     PLIB - A Suite of Portable Game Libraries
+     Copyright (C) 1998,2002  Steve Baker
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Library General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Library General Public License for more details.
+
+     You should have received a copy of the GNU Library General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+     For further information visit http://plib.sourceforge.net
+
+     $Id: jsBSD.cxx 2063 2006-01-05 21:21:55Z fayjf $
+*/
+
+/*
+ * Inspired by the X-Mame USB HID joystick driver for NetBSD and
+ * FreeBSD by Krister Walfridsson <cato@df.lth.se>.
+ * Incorporates the original analog joystick driver for BSD by
+ * Stephen Montgomery-Smith <stephen@math.missouri.edu>, with
+ * NetBSD mods courtesy of Rene Hexel.
+ *
+ * Bert Driehuis <driehuis@playbeing.org>
+ *
+ * Notes:
+ * Hats are mapped to two axes for now. A cleaner implementation requires
+ * an API extension, and to be useful for my devious purposes, FlightGear
+ * would need to understand that.
+ */
+
+
+#ifdef __FreeBSD__
+
+#include "FGjs.h"
+
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/joystick.h>
+#ifdef HAVE_USB_JS
+
+extern "C" {
+#  if __FreeBSD_version < 500000
+#    include <libusbhid.h>
+#  else
+#    define HAVE_USBHID_H 1
+#    include <usbhid.h>
+#  endif
+}
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+/* Compatibility with older usb.h revisions */
+#if !defined(USB_MAX_DEVNAMES) && defined(MAXDEVNAMES)
+#define USB_MAX_DEVNAMES MAXDEVNAMES
+#endif
+#endif
+
+static int hatmap_x[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
+static int hatmap_y[9] = { 0, 1, 1, 0, -1, -1, -1, 0, 1 };
+struct os_specific_s {
+  char             fname [128 ];
+  int              fd;
+  int              is_analog;
+  // The following structure members are specific to analog joysticks
+  struct joystick  ajs;
+#ifdef HAVE_USB_JS
+  // The following structure members are specific to USB joysticks
+  struct hid_item *hids;
+  int              hid_dlen;
+  int              hid_offset;
+  char            *hid_data_buf;
+  int              axes_usage [ _JS_MAX_AXES ] ;
+#endif
+  // We keep button and axes state ourselves, as they might not be updated
+  // on every read of a USB device
+  int              cache_buttons ;
+  float            cache_axes [ _JS_MAX_AXES ] ;
+};
+
+// Idents lower than USB_IDENT_OFFSET are for analog joysticks.
+#define USB_IDENT_OFFSET       2
+
+#define USBDEV "/dev/usb"
+#define UHIDDEV "/dev/uhid"
+#define AJSDEV "/dev/joy"
+
+/*
+ * findusbdev (and its helper, walkusbdev) try to locate the full name
+ * of a USB device. If /dev/usbN isn't readable, we punt and return the
+ * uhidN device name. We warn the user of this situation once.
+ */
+static char *
+walkusbdev(int f, char *dev, char *out, int outlen)
+{
+  struct usb_device_info di;
+  int i, a;
+  char *cp;
+
+  for (a = 1; a < USB_MAX_DEVICES; a++) {
+    di.udi_addr = a;
+    if (ioctl(f, USB_DEVICEINFO, &di) != 0)
+      return NULL;
+    for (i = 0; i < USB_MAX_DEVNAMES; i++)
+      if (di.udi_devnames[i][0] &&
+          strcmp(di.udi_devnames[i], dev) == 0) {
+        cp = new char[strlen(di.udi_vendor) + strlen(di.udi_product) + 2];
+        strcpy(cp, di.udi_vendor);
+        strcat(cp, " ");
+        strcat(cp, di.udi_product);
+        strncpy(out, cp, outlen - 1);
+       out[outlen - 1] = 0;
+       delete cp;
+        return out;
+      }
+  }
+  return NULL;
+}
+
+static int
+findusbdev(char *name, char *out, int outlen)
+{
+  int i, f;
+  char buf[50];
+  char *cp;
+  static int protection_warned = 0;
+
+  for (i = 0; i < 16; i++) {
+    sprintf(buf, "%s%d", USBDEV, i);
+    f = open(buf, O_RDONLY);
+    if (f >= 0) {
+      cp = walkusbdev(f, name, out, outlen);
+      close(f);
+      if (cp)
+        return 1;
+    } else if (errno == EACCES) {
+      if (!protection_warned) {
+        fprintf(stderr, "Can't open %s for read!\n",
+          buf);
+        protection_warned = 1;
+      }
+    }
+  }
+  return 0;
+}
+
+static int joy_initialize_hid(struct os_specific_s *os,
+       int *num_axes, int *num_buttons)
+{
+  int size, is_joystick;
+#ifdef HAVE_USBHID_H
+  int report_id = 0;
+#endif
+  struct hid_data *d;
+  struct hid_item h;
+  report_desc_t rd;
+
+  if ((rd = hid_get_report_desc(os->fd)) == 0)
+    {
+      fprintf(stderr, "error: %s: %s", os->fname, strerror(errno));
+      return FALSE;
+    }
+
+  os->hids = NULL;
+
+#ifdef HAVE_USBHID_H
+  if (ioctl(os->fd, USB_GET_REPORT_ID, &report_id) < 0)
+    {
+      fprintf(stderr, "error: %s: %s", os->fname, strerror(errno));
+      return FALSE;
+    }
+
+  size = hid_report_size(rd, hid_input, report_id);
+#else
+  size = hid_report_size(rd, 0, hid_input);
+#endif
+  os->hid_data_buf = new char[size];
+  os->hid_dlen = size;
+
+  is_joystick = 0;
+#ifdef HAVE_USBHID_H
+  d = hid_start_parse(rd, 1 << hid_input, report_id);
+#else
+  d = hid_start_parse(rd, 1 << hid_input);
+#endif
+  while (hid_get_item(d, &h))
+  {
+    int usage, page, interesting_hid;
+
+    page = HID_PAGE(h.usage);
+    usage = HID_USAGE(h.usage);
+
+    /* This test is somewhat too simplistic, but this is how MicroSoft
+     * does, so I guess it works for all joysticks/game pads. */
+    is_joystick = is_joystick ||
+      (h.kind == hid_collection &&
+       page == HUP_GENERIC_DESKTOP &&
+       (usage == HUG_JOYSTICK || usage == HUG_GAME_PAD));
+
+    if (h.kind != hid_input)
+      continue;
+
+    if (!is_joystick)
+      continue;
+
+    interesting_hid = TRUE;
+    if (page == HUP_GENERIC_DESKTOP)
+    {
+       switch(usage) {
+         case HUG_X:
+         case HUG_RX:
+         case HUG_Y:
+         case HUG_RY:
+         case HUG_Z:
+         case HUG_RZ:
+         case HUG_SLIDER:
+           if (*num_axes < _JS_MAX_AXES)
+           {
+             os->axes_usage[*num_axes] = usage;
+             (*num_axes)++;
+           }
+           break;
+         case HUG_HAT_SWITCH:
+           if (*num_axes + 1 < _JS_MAX_AXES)   // Allocate two axes for a hat
+           {
+             os->axes_usage[*num_axes] = usage;
+             (*num_axes)++;
+             os->axes_usage[*num_axes] = usage;
+             (*num_axes)++;
+           }
+           break;
+         default:
+           interesting_hid = FALSE;
+      }
+    }
+    else if (page == HUP_BUTTON)
+    {
+      interesting_hid = (usage > 0) && (usage <= _JS_MAX_BUTTONS);
+
+      if (interesting_hid && usage - 1 > *num_buttons)
+      {
+        *num_buttons = usage - 1;
+      }
+    }
+
+    if (interesting_hid)
+      {
+        h.next = os->hids;
+        os->hids = new struct hid_item;
+        *os->hids = h;
+      }
+  }
+  hid_end_parse(d);
+
+  return (os->hids != NULL);
+}
+
+void jsJoystick::open ()
+{
+  char *cp;
+
+  for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
+    os->cache_axes [ i ] = 0.0f ;
+
+  os->cache_buttons = 0 ;
+
+  os->fd = ::open ( os->fname, O_RDONLY | O_NONBLOCK) ;
+
+  if (os->fd < 0 && errno == EACCES)
+    fprintf(stderr, "%s exists but is not readable by you\n", os->fname);
+
+  error = ( os->fd < 0 ) ;
+
+  if ( error )
+    return ;
+
+  num_axes = 0;
+  num_buttons = 0;
+  if ( os->is_analog )
+  {
+    num_axes    =  2 ;
+    num_buttons = 32 ;
+    FILE *joyfile ;
+    char joyfname [ 1024 ] ;
+    int noargs, in_no_axes ;
+  
+    float axes  [ _JS_MAX_AXES ] ;
+    int buttons [ _JS_MAX_AXES ] ;
+  
+    rawRead ( buttons, axes ) ;
+    error = axes[0] < -1000000000.0f && axes[1] < -1000000000.0f ;
+    if ( error )
+      return ;
+  
+    sprintf( joyfname, "%s/.joy%drc", ::getenv ( "HOME" ), id ) ;
+  
+    joyfile = fopen ( joyfname, "r" ) ;
+    error = ( joyfile == NULL ) ;
+    if ( error )
+    {
+      ulSetError ( UL_WARNING, "unable to open calibration file %s (%s), joystick %i disabled (you can generate the calibration file with the plib-jscal utility)",
+                  joyfname, strerror ( errno ), id + 1 );
+      return ;
+    }
+
+    noargs = fscanf ( joyfile, "%d%f%f%f%f%f%f", &in_no_axes,
+                      &min [ 0 ], &center [ 0 ], &max [ 0 ],
+                      &min [ 1 ], &center [ 1 ], &max [ 1 ] ) ;
+    error = noargs != 7 || in_no_axes != _JS_MAX_AXES ;
+    fclose ( joyfile ) ;
+    if ( error )
+      return ;
+  
+    for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
+    {
+      dead_band [ i ] = 0.0f ;
+      saturate  [ i ] = 1.0f ;
+    }
+
+    return;    // End of analog code
+  }
+
+  if ( !joy_initialize_hid(os, &num_axes, &num_buttons ) )
+  {
+     ::close(os->fd);
+     error = 1;
+     return;
+  }
+
+  cp = strrchr(os->fname, '/');
+  char tmpname[128];
+  if (cp) {
+    if (findusbdev(&cp[1], tmpname, sizeof(tmpname)) == 0)
+      strcpy(name, &cp[1]);
+  }
+  name = tmpname;
+
+  if ( num_axes > _JS_MAX_AXES )
+    num_axes = _JS_MAX_AXES ;
+
+  for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
+  {
+       // We really should get this from the HID, but that data seems
+       // to be quite unreliable for analog-to-USB converters. Punt for
+       // now.
+    if ( os->axes_usage [ i ] == HUG_HAT_SWITCH )
+    {
+      max       [ i ] = 1.0f ;
+      center    [ i ] = 0.0f ;
+      min       [ i ] = -1.0f ;
+    }
+    else
+    {
+      max       [ i ] = 255.0f ;
+      center    [ i ] = 127.0f ;
+      min       [ i ] = 0.0f ;
+    }
+    dead_band [ i ] = 0.0f ;
+    saturate  [ i ] = 1.0f ;
+  }
+}
+
+void jsJoystick::close ()
+{
+  if (os) {
+    if ( ! error )
+      ::close ( os->fd ) ;
+    if (os->hids)
+      delete os->hids;
+    if (os->hid_data_buf)
+      delete os->hid_data_buf;
+    delete os;
+  }
+}
+
+jsJoystick::jsJoystick ( int ident )
+{
+  id = ident ;
+  error = 0;
+
+  os = new struct os_specific_s;
+  memset(os, 0, sizeof(struct os_specific_s));
+  if (ident < USB_IDENT_OFFSET)
+    os->is_analog = 1;
+  if (os->is_analog)
+    sprintf(os->fname, "%s%d", AJSDEV, ident);
+  else
+    sprintf(os->fname, "%s%d", UHIDDEV, ident - USB_IDENT_OFFSET);
+  open () ;
+}
+
+
+void jsJoystick::rawRead ( int *buttons, float *axes )
+{
+  int len, usage, page, d;
+  struct hid_item *h;
+
+  if ( error )
+  {
+    if ( buttons )
+      *buttons = 0 ;
+
+    if ( axes )
+      for ( int i = 0 ; i < num_axes ; i++ )
+        axes[i] = 1500.0f ;
+
+    return ;
+  }
+
+  if ( os->is_analog )
+  {
+    int status = ::read ( os->fd, &os->ajs, sizeof(os->ajs) );
+    if ( status != sizeof(os->ajs) ) {
+      perror ( os->fname ) ;
+      setError () ;
+      return ;
+    }
+    if ( buttons != NULL )
+      *buttons = ( os->ajs.b1 ? 1 : 0 ) | ( os->ajs.b2 ? 2 : 0 ) ;
+
+    if ( axes != NULL )
+    {
+      if ( os->ajs.x >= -1000000000 )
+        os->cache_axes[0] = os->ajs.x;
+      if ( os->ajs.y >= -1000000000 )
+        os->cache_axes[1] = os->ajs.y;
+
+      axes[0] = os->cache_axes[0];
+      axes[1] = os->cache_axes[1];
+    }
+
+    return;
+  }
+
+  while ((len = ::read(os->fd, os->hid_data_buf, os->hid_dlen)) == os->hid_dlen)
+  {
+    for (h = os->hids; h; h = h->next)
+    {
+      d = hid_get_data(os->hid_data_buf, h);
+  
+      page = HID_PAGE(h->usage);
+      usage = HID_USAGE(h->usage);
+  
+      if (page == HUP_GENERIC_DESKTOP)
+      {
+        for (int i = 0; i < num_axes; i++)
+          if (os->axes_usage[i] == usage)
+          {
+            if (usage == HUG_HAT_SWITCH)
+            {
+              if (d < 0 || d > 8)
+                d = 0; // safety
+              os->cache_axes[i] = (float)hatmap_x[d];
+              os->cache_axes[i + 1] = (float)hatmap_y[d];
+            }
+            else
+            {
+              os->cache_axes[i] = (float)d;
+            }
+            break;
+          }
+      }
+      else if (page == HUP_BUTTON)
+      {
+         if (usage > 0 && usage < _JS_MAX_BUTTONS + 1)
+         {
+           if (d)
+             os->cache_buttons |= (1 << usage - 1) ;
+           else
+             os->cache_buttons &= ~(1 << usage - 1) ;
+         }
+      }
+    }
+  }
+  if (len < 0 && errno != EAGAIN)
+  {
+    perror( os->fname ) ;
+    setError () ;
+    error = 1;
+  }
+  if ( buttons != NULL ) *buttons = os->cache_buttons ;
+  if ( axes    != NULL )
+    memcpy ( axes, os->cache_axes, sizeof(float) * num_axes ) ;
+}
+
+void jsInit () {}
+
+#endif
diff --git a/src/Input/jsLinux.cxx b/src/Input/jsLinux.cxx
new file mode 100644 (file)
index 0000000..5c56368
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+     PLIB - A Suite of Portable Game Libraries
+     Copyright (C) 1998,2002  Steve Baker
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Library General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Library General Public License for more details.
+
+     You should have received a copy of the GNU Library General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+     For further information visit http://plib.sourceforge.net
+
+     $Id: jsLinux.cxx 2017 2005-02-21 07:37:25Z bram $
+*/
+
+
+#ifdef linux
+
+#include "FGjs.hxx"
+
+#include <linux/joystick.h>
+
+#if defined(JS_VERSION) && JS_VERSION >= 0x010000
+
+#include <sys/param.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <plib/ul.h>
+
+struct os_specific_s {
+  js_event     js          ;
+  int          tmp_buttons ;
+  float        tmp_axes [ _JS_MAX_AXES ] ;
+  char         fname [ 128 ] ;
+  int          fd ;
+};
+
+void jsInit () {}
+
+void jsJoystick::open ()
+{
+  name [0] = '\0' ;
+
+  for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
+    os->tmp_axes [ i ] = 0.0f ;
+
+  os->tmp_buttons = 0 ;
+
+  os->fd = ::open ( os->fname, O_RDONLY ) ;
+
+  error = ( os->fd < 0 ) ;
+
+  if ( error )
+    return ;
+
+  /*
+    Set the correct number of axes for the linux driver
+  */
+
+  /* Melchior Franz's fixes for big-endian Linuxes since writing 
+   *  to the upper byte of an uninitialized word doesn't work. 
+   *  9 April 2003 
+   */
+  unsigned char u ;
+  ioctl ( os->fd, JSIOCGAXES   , &u ) ; 
+  num_axes = u ;
+  ioctl ( os->fd, JSIOCGBUTTONS, &u ) ;
+  num_buttons = u ;
+  char tmpname[256];
+  ioctl ( os->fd, JSIOCGNAME ( sizeof(tmpname) ), tmpname ) ;
+  fcntl ( os->fd, F_SETFL      , O_NONBLOCK   ) ;
+  name = tmpname;
+  int all_axes = num_axes;
+  if ( num_axes > _JS_MAX_AXES )
+    num_axes = _JS_MAX_AXES ;
+
+  // Remove any deadband value already done in the kernel.
+  // Since we have our own deadband management this is save to do so.
+  struct js_corr* corr = new js_corr[ all_axes ] ;
+  ioctl ( os->fd, JSIOCGCORR, corr );
+  for ( int i = 0; i < num_axes ; ++i ) {
+    if ( corr[ i ] . type == JS_CORR_BROKEN ) {
+      int nodeadband = ( corr[ i ] . coef[ 0 ] + corr[ i ] . coef[ 1 ] ) / 2 ;
+      corr[ i ] . coef[ 0 ] = nodeadband ;
+      corr[ i ] . coef[ 1 ] = nodeadband ;
+    }
+  }
+  ioctl ( os->fd, JSIOCSCORR, corr );
+  delete [] corr;
+
+  for ( int i = 0 ; i < _JS_MAX_AXES ; i++ )
+  {
+    max       [ i ] = 32767.0f ;
+    center    [ i ] = 0.0f ;
+    min       [ i ] = -32767.0f ;
+    dead_band [ i ] = 0.0f ;
+    saturate  [ i ] = 1.0f ;
+  }
+}
+
+void jsJoystick::close ()
+{
+  if ( ! error )
+    ::close ( os->fd ) ;
+  delete os;
+}
+
+
+jsJoystick::jsJoystick ( int ident )
+{
+  id = ident ;
+  os = new struct os_specific_s;
+
+  sprintf ( os->fname, "/dev/input/js%d", ident ) ;
+
+  if ( access ( os->fname, F_OK ) != 0 )
+    sprintf ( os->fname, "/dev/js%d", ident ) ;
+
+  open () ;
+}
+
+
+void jsJoystick::rawRead ( int *buttons, float *axes )
+{
+  if ( error )
+  {
+    if ( buttons )
+      *buttons = 0 ;
+
+    if ( axes )
+      for ( int i = 0 ; i < num_axes ; i++ )
+        axes[i] = 1500.0f ;
+
+    return ;
+  }
+
+  while (1)
+  {
+    int status = ::read ( os->fd, &(os->js), sizeof(js_event) ) ;
+
+    if ( status != sizeof(js_event) )
+    {
+      /* use the old values */
+
+      if ( buttons != NULL ) *buttons = os->tmp_buttons ;
+      if ( axes    != NULL )
+        memcpy ( axes, os->tmp_axes, sizeof(float) * num_axes ) ;
+
+      if ( errno == EAGAIN )
+        return ;
+
+      perror( os->fname ) ;
+      setError () ;
+      return ;
+    }
+
+    switch ( os->js.type & ~JS_EVENT_INIT )
+    {
+      case JS_EVENT_BUTTON :
+        if ( os->js.value == 0 ) /* clear the flag */
+          os->tmp_buttons &= ~(1 << os->js.number) ;
+        else
+          os->tmp_buttons |=  (1 << os->js.number) ;
+        break ;
+
+      case JS_EVENT_AXIS:
+        if ( os->js.number < num_axes )
+        {
+          os->tmp_axes [ os->js.number ] = (float) os->js.value ;
+
+          if ( axes )
+            memcpy ( axes, os->tmp_axes, sizeof(float) * num_axes ) ;
+        }
+        break ;
+
+      default:
+        ulSetError ( UL_WARNING, "PLIB_JS: Unrecognised /dev/js return!?!" ) ;
+
+        /* use the old values */
+
+        if ( buttons != NULL ) *buttons = os->tmp_buttons ;
+        if ( axes    != NULL )
+          memcpy ( axes, os->tmp_axes, sizeof(float) * num_axes ) ;
+
+        return ;
+    }
+
+    if ( buttons != NULL )
+      *buttons = os->tmp_buttons ;
+  }
+}
+
+#endif
+#endif
diff --git a/src/Input/jsMacOSX.cxx b/src/Input/jsMacOSX.cxx
new file mode 100644 (file)
index 0000000..1e9c3ab
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+     PLIB - A Suite of Portable Game Libraries
+     Copyright (C) 1998,2002  Steve Baker
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Library General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Library General Public License for more details.
+
+     You should have received a copy of the GNU Library General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+     For further information visit http://plib.sourceforge.net
+
+     $Id: jsMacOSX.cxx 2118 2007-09-14 22:23:32Z fayjf $
+*/
+
+#ifdef __APPLE__
+
+#include "FGjs.h"
+
+#include <mach/mach.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/hid/IOHIDLib.h>
+#include <mach/mach_error.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#ifdef MACOS_10_0_4
+#      include <IOKit/hidsystem/IOHIDUsageTables.h>
+#else
+/* The header was moved here in MacOS X 10.1 */
+#      include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
+#endif
+
+static const int kNumDevices = 32;
+static int numDevices = -1;
+static io_object_t ioDevices[kNumDevices];
+
+static int NS_hat[8] = {1, 1, 0, -1, -1, -1, 0, 1};
+static int WE_hat[8] = {0, 1, 1, 1, 0, -1, -1, -1};
+
+struct os_specific_s {
+  IOHIDDeviceInterface ** hidDev;
+  IOHIDElementCookie buttonCookies[41];
+  IOHIDElementCookie axisCookies[_JS_MAX_AXES];
+  IOHIDElementCookie hatCookies[_JS_MAX_HATS];
+  int num_hats;
+  long hat_min[_JS_MAX_HATS];
+  long hat_max[_JS_MAX_HATS];
+  
+  void enumerateElements(jsJoystick* joy, CFTypeRef element);
+  static void elementEnumerator( const void *element, void* vjs);
+  /// callback for CFArrayApply
+  void parseElement(jsJoystick* joy, CFDictionaryRef element);
+  void addAxisElement(jsJoystick* joy, CFDictionaryRef axis);
+  void addButtonElement(jsJoystick* joy, CFDictionaryRef button);
+  void addHatElement(jsJoystick* joy, CFDictionaryRef hat);
+};
+
+static void findDevices(mach_port_t);
+static CFDictionaryRef getCFProperties(io_object_t);
+
+
+void jsInit()
+{
+       if (numDevices < 0) {
+               numDevices = 0;
+               
+               mach_port_t masterPort;
+               IOReturn rv = IOMasterPort(bootstrap_port, &masterPort);
+               if (rv != kIOReturnSuccess) {
+                       ulSetError(UL_WARNING, "error getting master Mach port");
+                       return;
+               }
+               
+               findDevices(masterPort);
+       }
+}
+
+/** open the IOKit connection, enumerate all the HID devices, add their
+interface references to the static array. We then use the array index
+as the device number when we come to open() the joystick. */
+static void findDevices(mach_port_t masterPort)
+{
+       CFMutableDictionaryRef hidMatch = NULL;
+       IOReturn rv = kIOReturnSuccess;
+       io_iterator_t hidIterator;
+       
+       // build a dictionary matching HID devices
+       hidMatch = IOServiceMatching(kIOHIDDeviceKey);
+       
+       rv = IOServiceGetMatchingServices(masterPort, hidMatch, &hidIterator);
+       if (rv != kIOReturnSuccess || !hidIterator) {
+               ulSetError(UL_WARNING, "no joystick (HID) devices found");
+               return;
+       }
+       
+       // iterate
+       io_object_t ioDev;
+       
+       while ((ioDev = IOIteratorNext(hidIterator))) {
+               // filter out keyboard and mouse devices
+               CFDictionaryRef properties = getCFProperties(ioDev);
+               long usage, page;
+               
+               CFTypeRef refPage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsagePageKey));
+               CFTypeRef refUsage = CFDictionaryGetValue (properties, CFSTR(kIOHIDPrimaryUsageKey));
+               CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
+               CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
+               
+               // keep only joystick devices
+               if  ( (page == kHIDPage_GenericDesktop) &&
+         ((usage == kHIDUsage_GD_Joystick) ||
+          (usage == kHIDUsage_GD_GamePad)
+    // || (usage == kHIDUsage_GD_MultiAxisController)
+    // || (usage == kHIDUsage_GD_Hatswitch)
+          )
+        )
+    {
+                       // add it to the array
+                       ioDevices[numDevices++] = ioDev;
+    }
+       }
+       
+       IOObjectRelease(hidIterator);
+}
+
+
+jsJoystick::jsJoystick(int ident) :
+       id(ident),
+       os(NULL), 
+       error(false),
+       num_axes(0),
+       num_buttons(0)
+{      
+       if (ident >= numDevices) {
+               setError();
+               return;
+       }
+       
+       os = new struct os_specific_s;
+       os->num_hats = 0;
+       
+       // get the name now too
+       CFDictionaryRef properties = getCFProperties(ioDevices[id]);
+       CFTypeRef ref = CFDictionaryGetValue (properties, CFSTR(kIOHIDProductKey));
+       if (!ref)
+               ref = CFDictionaryGetValue (properties, CFSTR("USB Product Name"));
+       char tmpname[128];
+       if (!ref || !CFStringGetCString ((CFStringRef) ref, tmpname, sizeof(tmpname), CFStringGetSystemEncoding ())) {
+               ulSetError(UL_WARNING, "error getting device name");
+               tmpname[0] = '\0';
+       }
+       name = tmpname;
+       //printf("Joystick name: %s \n", name);
+       open();
+}
+
+void jsJoystick::open()
+{
+       // create device interface
+       IOReturn rv;
+       SInt32 score;
+       IOCFPlugInInterface **plugin;
+
+       rv = IOCreatePlugInInterfaceForService(ioDevices[id], 
+               kIOHIDDeviceUserClientTypeID,
+               kIOCFPlugInInterfaceID,
+               &plugin, &score);
+               
+       if (rv != kIOReturnSuccess) {
+               ulSetError(UL_WARNING, "error creting plugin for io device");
+               return;
+       }
+       
+       HRESULT pluginResult = (*plugin)->QueryInterface(plugin, 
+               CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID*)&(os->hidDev) );
+               
+       if (pluginResult != S_OK)
+               ulSetError(UL_WARNING, "QI-ing IO plugin to HID Device interface failed");
+
+       (*plugin)->Release(plugin); // don't leak a ref
+       if (os->hidDev == NULL) return;
+               
+       // store the interface in this instance
+       rv = (*(os->hidDev))->open(os->hidDev, 0);
+       if (rv != kIOReturnSuccess) {
+               ulSetError(UL_WARNING, "error opening device interface");
+               return;
+       }
+       
+       CFDictionaryRef props = getCFProperties(ioDevices[id]);
+                       
+       // recursively enumerate all the bits (buttons, axes, hats, ...)
+       CFTypeRef topLevelElement = 
+               CFDictionaryGetValue (props, CFSTR(kIOHIDElementKey));
+       os->enumerateElements(this, topLevelElement);
+       CFRelease(props);
+       
+       // for hats to be implemented as axes: must be the last axes:
+       for (int h = 0; h<2*os->num_hats; h++)
+       {
+               int index = num_axes++;
+               dead_band [ index ] = 0.0f ;
+               saturate  [ index ] = 1.0f ;
+               center    [ index ] = 0.0f;
+               max       [ index ] = 1.0f;
+               min       [ index ] = -1.0f;
+       }
+}
+
+CFDictionaryRef getCFProperties(io_object_t ioDev)
+{
+       IOReturn rv;
+       CFMutableDictionaryRef cfProperties;
+
+       rv = IORegistryEntryCreateCFProperties( ioDev /*parent2*/, 
+               &cfProperties, kCFAllocatorDefault, kNilOptions);
+       if (rv != kIOReturnSuccess || !cfProperties) {
+               ulSetError(UL_WARNING, "error getting device properties");
+               return NULL;
+       }
+       
+       return cfProperties;
+}
+
+void jsJoystick::close()
+{
+       if (os->hidDev != NULL)  (*(os->hidDev))->close(os->hidDev);
+       if (os) delete os;
+}
+
+/** element enumerator function : pass NULL for top-level*/
+void os_specific_s::enumerateElements(jsJoystick* joy, CFTypeRef element)
+{
+       assert(CFGetTypeID(element) == CFArrayGetTypeID());
+       
+       CFRange range = {0, CFArrayGetCount ((CFArrayRef)element)};
+       CFArrayApplyFunction((CFArrayRef) element, range, 
+               &elementEnumerator, joy);
+}
+
+void os_specific_s::elementEnumerator( const void *element, void* vjs)
+{
+       if (CFGetTypeID((CFTypeRef) element) != CFDictionaryGetTypeID()) {
+               ulSetError(UL_WARNING, "element enumerator passed non-dictionary value");
+               return;
+       }
+       
+       static_cast<jsJoystick*>(vjs)->
+               os->parseElement( static_cast<jsJoystick*>(vjs), (CFDictionaryRef) element);            
+}
+
+void os_specific_s::parseElement(jsJoystick* joy, CFDictionaryRef element)
+{
+       CFTypeRef refPage = CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementUsagePageKey));
+       CFTypeRef refUsage = CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementUsageKey));
+
+       long type, page, usage;
+       
+       CFNumberGetValue((CFNumberRef)
+               CFDictionaryGetValue ((CFDictionaryRef) element, CFSTR(kIOHIDElementTypeKey)), 
+               kCFNumberLongType, &type);
+               
+       switch (type) {
+       case kIOHIDElementTypeInput_Misc:
+       case kIOHIDElementTypeInput_Axis:
+       case kIOHIDElementTypeInput_Button:
+               //printf("got input element...");
+               CFNumberGetValue((CFNumberRef) refUsage, kCFNumberLongType, &usage);
+               CFNumberGetValue((CFNumberRef) refPage, kCFNumberLongType, &page);
+               
+               if (page == kHIDPage_GenericDesktop) {          
+                       switch (usage) /* look at usage to determine function */
+                       {
+                               case kHIDUsage_GD_X:
+                               case kHIDUsage_GD_Y:
+                               case kHIDUsage_GD_Z:
+                               case kHIDUsage_GD_Rx:
+                               case kHIDUsage_GD_Ry:
+                               case kHIDUsage_GD_Rz:
+                               case kHIDUsage_GD_Slider: // for throttle / trim controls
+        case kHIDUsage_GD_Dial:
+                                       //printf(" axis\n");
+                                       /*joy->os->*/addAxisElement(joy, (CFDictionaryRef) element);
+                                       break;
+
+        case kHIDUsage_GD_Hatswitch:
+                                       //printf(" hat\n");
+                                       /*joy->os->*/addHatElement(joy, (CFDictionaryRef) element);
+                                       break;
+                                       
+                               default:
+                                       ulSetError(UL_WARNING, "input type element has weird usage (%lx)\n", usage);
+               break;
+                       }                                       
+               } else if (page == kHIDPage_Button) {
+                       //printf(" button\n");
+                       /*joy->os->*/addButtonElement(joy, (CFDictionaryRef) element);
+               } else
+                       ulSetError(UL_WARNING, "input type element has weird usage (%lx)\n", usage);
+               break;
+
+       case kIOHIDElementTypeCollection:
+               /*joy->os->*/enumerateElements(joy,
+                       CFDictionaryGetValue(element, CFSTR(kIOHIDElementKey))
+               );
+               break;
+               
+       default:
+               break;
+       }       
+}
+
+void os_specific_s::addAxisElement(jsJoystick* joy, CFDictionaryRef axis)
+{
+       long cookie, lmin, lmax;
+       CFNumberGetValue ((CFNumberRef)
+               CFDictionaryGetValue (axis, CFSTR(kIOHIDElementCookieKey)), 
+               kCFNumberLongType, &cookie);
+       
+       int index = joy->num_axes++;
+       
+       /*joy->os->*/axisCookies[index] = (IOHIDElementCookie) cookie;
+       
+       CFNumberGetValue ((CFNumberRef)
+               CFDictionaryGetValue (axis, CFSTR(kIOHIDElementMinKey)), 
+               kCFNumberLongType, &lmin);
+               
+       CFNumberGetValue ((CFNumberRef)
+               CFDictionaryGetValue (axis, CFSTR(kIOHIDElementMaxKey)), 
+               kCFNumberLongType, &lmax);
+               
+       joy->min[index] = lmin;
+       joy->max[index] = lmax;
+       joy->dead_band[index] = 0.0;
+       joy->saturate[index] = 1.0;
+       joy->center[index] = (lmax - lmin) * 0.5 + lmin;
+}
+
+void os_specific_s::addButtonElement(jsJoystick* joy, CFDictionaryRef button)
+{
+       long cookie;
+       CFNumberGetValue ((CFNumberRef)
+               CFDictionaryGetValue (button, CFSTR(kIOHIDElementCookieKey)), 
+               kCFNumberLongType, &cookie);
+               
+       /*joy->os->*/buttonCookies[joy->num_buttons++] = (IOHIDElementCookie) cookie;
+       // anything else for buttons?
+}
+
+void os_specific_s::addHatElement(jsJoystick* joy, CFDictionaryRef hat)
+{
+       long cookie, lmin, lmax;
+       CFNumberGetValue ((CFNumberRef)
+               CFDictionaryGetValue (hat, CFSTR(kIOHIDElementCookieKey)), 
+               kCFNumberLongType, &cookie);
+               
+       int index = /*joy->*/num_hats++;
+
+       /*joy->os->*/hatCookies[index] = (IOHIDElementCookie) cookie;
+       
+       CFNumberGetValue ((CFNumberRef)
+               CFDictionaryGetValue (hat, CFSTR(kIOHIDElementMinKey)), 
+               kCFNumberLongType, &lmin);
+               
+       CFNumberGetValue ((CFNumberRef)
+               CFDictionaryGetValue (hat, CFSTR(kIOHIDElementMaxKey)), 
+               kCFNumberLongType, &lmax);
+       
+       hat_min[index] = lmin;
+       hat_max[index] = lmax;
+       // do we map hats to axes or buttons?
+       // axes; there is room for that: Buttons are limited to 32.
+       // (a joystick with 2 hats will use 16 buttons!)
+}
+
+void jsJoystick::rawRead(int *buttons, float *axes)
+{
+       *buttons = 0;
+        IOHIDEventStruct hidEvent;
+       
+       for (int b=0; b<num_buttons; ++b) {
+               (*(os->hidDev))->getElementValue(os->hidDev, os->buttonCookies[b], &hidEvent);
+               if (hidEvent.value)
+                       *buttons |= 1 << b; 
+       }
+       
+       // real axes:
+       int real_num_axes = num_axes - 2*os->num_hats;
+       for (int a=0; a<real_num_axes; ++a) {
+               (*(os->hidDev))->getElementValue(os->hidDev, os->axisCookies[a], &hidEvent);
+               axes[a] = hidEvent.value;
+       }
+       
+       // hats:
+       for (int h=0; h < os->num_hats; ++h) {
+               (*(os->hidDev))->getElementValue(os->hidDev, os->hatCookies[h], &hidEvent);
+                long result = ( hidEvent.value - os->hat_min[h] ) * 8;
+                result /= ( os->hat_max[h] - os->hat_min[h] + 1 );
+                if ( (result>=0) && (result<8) )
+                {
+                        axes[h+real_num_axes+1] = NS_hat[result];
+                        axes[h+real_num_axes] = WE_hat[result];
+                }
+                else
+                {
+                        axes[h+real_num_axes] = 0;
+                        axes[h+real_num_axes+1] = 0;
+                }
+       }
+}
+
+#endif
diff --git a/src/Input/jsNone.cxx b/src/Input/jsNone.cxx
new file mode 100644 (file)
index 0000000..5ce8ceb
--- /dev/null
@@ -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 (file)
index 0000000..f389082
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+     PLIB - A Suite of Portable Game Libraries
+     Copyright (C) 1998,2002  Steve Baker
+
+     This library is free software; you can redistribute it and/or
+     modify it under the terms of the GNU Library General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later version.
+
+     This library is distributed in the hope that it will be useful,
+     but WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     Library General Public License for more details.
+
+     You should have received a copy of the GNU Library General Public
+     License along with this library; if not, write to the Free Software
+     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+
+     For further information visit http://plib.sourceforge.net
+
+     $Id: jsWindows.cxx 2114 2006-12-21 20:53:13Z fayjf $
+*/
+
+#include "FGjs.hxx"
+#include <windows.h>
+#include <regstr.h>
+#include <sstream>
+#include <math.h>
+
+#include <plib/ul.h>
+
+#if defined (_WIN32)
+
+#define _JS_MAX_AXES_WIN 8  /* X,Y,Z,R,U,V,POV_X,POV_Y */
+
+struct os_specific_s {
+  std::string  regKey;
+  static std::string getOEMProductName ( jsJoystick* joy);
+};
+
+
+// Inspired by
+// http://msdn.microsoft.com/archive/en-us/dnargame/html/msdn_sidewind3d.asp
+
+std::string 
+os_specific_s::getOEMProductName (jsJoystick* joy)
+{
+  if ( joy->error )  return "" ;
+
+  char charbuf [ 256 ] ;
+
+  HKEY  hKey ;
+  DWORD dwcb ;
+  LONG  lr ;
+  std::string name;
+
+  // Open .. MediaResources\CurrentJoystickSettings
+  std::string key=REGSTR_PATH_JOYCONFIG;
+  key+= "\\" + joy->os->regKey + "\\" + REGSTR_KEY_JOYCURR;
+
+  bool hkcu = false;
+
+  if ( ERROR_SUCCESS != RegOpenKeyEx ( HKEY_LOCAL_MACHINE, key.c_str(), 0, KEY_QUERY_VALUE, &hKey)) {
+       hkcu = true;
+       if ( ERROR_SUCCESS != RegOpenKeyEx ( HKEY_CURRENT_USER, key.c_str(), 0, KEY_QUERY_VALUE, &hKey)) 
+         return "" ;
+  }
+  // Get OEM Key name
+  dwcb = sizeof( charbuf) ;
+
+  std::ostringstream value;
+  value << "Joystick" << joy->id+1 << REGSTR_VAL_JOYOEMNAME;
+  // JOYSTICKID1-16 is zero-based; registry entries for VJOYD are 1-based.
+   
+  lr = RegQueryValueEx ( hKey, value.str().c_str(), 0, 0, (LPBYTE) charbuf, &dwcb);
+  RegCloseKey ( hKey ) ;
+
+  if ( lr != ERROR_SUCCESS ) return "" ;
+
+  // Open OEM Key from ...MediaProperties
+  value.str("");
+  value << REGSTR_PATH_JOYOEM << "\\" << charbuf;
+
+  if (hkcu) {
+         lr = RegOpenKeyEx ( HKEY_CURRENT_USER, value.str().c_str(), 0, KEY_QUERY_VALUE, &hKey ) ;
+  } else {
+         lr = RegOpenKeyEx ( HKEY_LOCAL_MACHINE, value.str().c_str(), 0, KEY_QUERY_VALUE, &hKey ) ;
+  }
+  if ( lr != ERROR_SUCCESS ) 
+    return "" ;
+  
+  dwcb = sizeof( charbuf) ;
+  lr = RegQueryValueEx ( hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) charbuf, &dwcb ) ;
+  RegCloseKey ( hKey ) ;
+  
+  if ( lr != ERROR_SUCCESS ) return "" ;
+  name = std::string( charbuf, dwcb-1);
+  return name;
+}
+
+
+void jsJoystick::open ()
+{
+  JOYCAPS      jsCaps ;
+
+  name [0] = '\0' ;
+
+  
+
+  memset ( &jsCaps, 0, sizeof(jsCaps)) ;
+
+  error = ( joyGetDevCaps( id, &jsCaps, sizeof(jsCaps) )
+                 != JOYERR_NOERROR ) ;
+  
+  os->regKey = jsCaps.szRegKey;
+
+  num_buttons = jsCaps.wNumButtons ;
+  if ( jsCaps.wNumAxes == 0 )
+  {
+    num_axes = 0 ;
+    setError () ;
+  }
+  else
+  {
+    // Device name from jsCaps is often "Microsoft PC-joystick driver",
+    // at least for USB.  Try to get the real name from the registry.
+    name = os->getOEMProductName ( this);
+    
+       if (name == "") {
+      ulSetError ( UL_WARNING,
+                   "JS: Failed to read joystick name from registry" ) ;
+
+         name = jsCaps.szPname;
+    }
+
+    // Windows joystick drivers may provide any combination of
+    // X,Y,Z,R,U,V,POV - not necessarily the first n of these.
+    if ( jsCaps.wCaps & JOYCAPS_HASPOV )
+    {
+      num_axes = _JS_MAX_AXES_WIN ;
+      min [ 7 ] = -1.0 ; max [ 7 ] = 1.0 ;  // POV Y
+      min [ 6 ] = -1.0 ; max [ 6 ] = 1.0 ;  // POV X
+    }
+    else
+      num_axes = 6 ;
+
+    min [ 5 ] = (float) jsCaps.wVmin ; max [ 5 ] = (float) jsCaps.wVmax ;
+    min [ 4 ] = (float) jsCaps.wUmin ; max [ 4 ] = (float) jsCaps.wUmax ;
+    min [ 3 ] = (float) jsCaps.wRmin ; max [ 3 ] = (float) jsCaps.wRmax ;
+    min [ 2 ] = (float) jsCaps.wZmin ; max [ 2 ] = (float) jsCaps.wZmax ;
+    min [ 1 ] = (float) jsCaps.wYmin ; max [ 1 ] = (float) jsCaps.wYmax ;
+    min [ 0 ] = (float) jsCaps.wXmin ; max [ 0 ] = (float) jsCaps.wXmax ;
+  }
+
+  for ( int i = 0 ; i < num_axes ; i++ )
+  {
+    center    [ i ] = ( max[i] + min[i] ) / 2.0f ;
+    dead_band [ i ] = 0.0f ;
+    saturate  [ i ] = 1.0f ;
+  }
+}
+
+
+void jsJoystick::close ()
+{
+       delete os;
+}
+
+jsJoystick::jsJoystick ( int ident )
+{
+  id = ident ;
+  os = new struct os_specific_s;
+
+  if (ident >= 0 && ident < (int)joyGetNumDevs()) {
+        open();
+  }
+  else {
+        num_axes = 0;
+        setError();
+  }
+}
+
+
+void jsJoystick::rawRead ( int *buttons, float *axes )
+{
+  JOYINFOEX    js;
+
+  js.dwFlags = JOY_RETURNALL ;
+  js.dwSize  = sizeof ( JOYINFOEX) ;
+
+  if ( error )
+  {
+    if ( buttons )
+      *buttons = 0 ;
+
+    if ( axes )
+      for ( int i = 0 ; i < num_axes ; i++ )
+        axes[i] = 1500.0f ;
+
+    return ;
+  }
+
+
+  MMRESULT status = joyGetPosEx ( id, &js ) ;
+
+  if ( status != JOYERR_NOERROR )
+  {
+    setError() ;
+    return ;
+  }
+
+  if ( buttons != NULL )
+    *buttons = (int) js.dwButtons ;
+
+  if ( axes != NULL )
+  {
+    /* WARNING - Fall through case clauses!! */
+
+    switch ( num_axes )
+    {
+      case 8:
+        // Generate two POV axes from the POV hat angle.
+        // Low 16 bits of js.dwPOV gives heading (clockwise from ahead) in
+        //   hundredths of a degree, or 0xFFFF when idle.
+
+        if ( ( js.dwPOV & 0xFFFF ) == 0xFFFF )
+        {
+          axes [ 6 ] = 0.0 ;
+          axes [ 7 ] = 0.0 ;
+        }
+        else
+        {
+          // This is the contentious bit: how to convert angle to X/Y.
+          //    wk: I know of no define for PI that we could use here:
+          //    SG_PI would pull in sg, M_PI is undefined for MSVC
+          // But the accuracy of the value of PI is very unimportant at
+          // this point.
+
+          float s = (float) sin ( ( js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180 ) ) ;
+          float c = (float) cos ( ( js.dwPOV & 0xFFFF ) * ( 0.01 * 3.1415926535f / 180 ) ) ;
+
+          // Convert to coordinates on a square so that North-East
+          // is (1,1) not (.7,.7), etc.
+          // s and c cannot both be zero so we won't divide by zero.
+          if ( fabs ( s ) < fabs ( c ) )
+          {
+            axes [ 6 ] = ( c < 0.0 ) ? -s/c  : s/c  ;
+            axes [ 7 ] = ( c < 0.0 ) ? -1.0f : 1.0f ;
+          }
+          else
+          {
+            axes [ 6 ] = ( s < 0.0 ) ? -1.0f : 1.0f ;
+            axes [ 7 ] = ( s < 0.0 ) ? -c/s  : c/s  ;
+          }
+        }
+
+      case 6: axes[5] = (float) js . dwVpos ;
+      case 5: axes[4] = (float) js . dwUpos ;
+      case 4: axes[3] = (float) js . dwRpos ;
+      case 3: axes[2] = (float) js . dwZpos ;
+      case 2: axes[1] = (float) js . dwYpos ;
+      case 1: axes[0] = (float) js . dwXpos ;
+              break;
+
+      default:
+        ulSetError ( UL_WARNING, "PLIB_JS: Wrong num_axes. Joystick input is now invalid" ) ;
+    }
+  }
+}
+
+void jsInit() {}
+
+#endif
index ee2b32e3011548a7dacbbd081f7df33ac08ceda8..448cecc2c3652034e615204cbb5fe3ab872225bf 100644 (file)
@@ -2,12 +2,12 @@
 #  include <config.h>
 #endif
 
-#ifdef HAVE_WINDOWS_H
-#  include <windows.h>                     
+#ifdef _WIN32
+#include <windows.h>
 #endif
 
 #include <string.h>            // plib/js.h should really include this !!!!!!
-#include <plib/js.h>
+#include "Input/FGjs.hxx"
 
 #define Z 8
 
@@ -30,7 +30,7 @@ int main ( int, char ** )
   { useful[i] = ! ( js[i]->notWorking () );
     if ( useful[i] ) {
          t++;
-         printf ( "Joystick %i: \"%s\"\n", i, js[i]->getName() ) ;
+         printf ( "Joystick %i: \"%s\"\n", i, js[i]->getName().c_str() ) ;
     } else printf ( "Joystick %i not detected\n", i ) ;
   }
   if ( t == 0 ) exit ( 1 ) ;
index b57f828d2bb99d1a41c1062684b42631f79ba645..2c288f640af73602021f2175e09d5d65da7e60bf 100644 (file)
 #include <simgear/compiler.h>
 
 #include <iostream>
-
+#include <math.h>
 using std::cout;
 using std::cin;
 using std::endl;
 
 #include "jsinput.h"
+#include <plib/ul.h>
 
 jsInput::jsInput(jsSuper *j) {
     jss=j;
index 3b395c4cd21566608f0010c7b936fff5f256db2d..398ef579d013bb2c0b645d4b24370130e4d7fb2a 100644 (file)
@@ -25,8 +25,7 @@
 #  include <config.h>
 #endif
 
-#include <string.h>            // plib/js.h should really include this !!!!!!
-#include <plib/js.h>
+#include "FGjs.hxx"
 
 #define MAX_JOYSTICKS 8
 
index ffc87c85782a03b586f2a123d17a64ea4db7023d..51dbead5a1fd52f59958b1a19f2901b43e9eb849 100644 (file)
@@ -32,6 +32,7 @@ get_property(FG_LIBS GLOBAL PROPERTY FG_LIBS)
 
 target_link_libraries(fgfs 
        ${FG_LIBS}
+       ${JS_LIBS}
        ${SIMGEAR_LIBRARIES}
        ${OPENSCENEGRAPH_LIBRARIES} 
        ${OPENAL_LIBRARY} 
index 7cfe0fd919404dd3727b591eb1e42dd13a7ce540..0b1e9bab183a4ab59d25b052dae9365b6ac43d4f 100644 (file)
@@ -18,7 +18,7 @@ endif
 if HAVE_FRAMEWORK_PLIB
 fgfs_PLIB_FW = $(plib_FRAMEWORK)
 else
-fgfs_PLIB_LIBS = -lplibpuaux -lplibpu -lplibfnt -lplibjs  \
+fgfs_PLIB_LIBS = -lplibpuaux -lplibpu -lplibfnt \
        -lplibsg -lplibul 
 endif
 
index f6654788b39b26374b858d806d6d9f8c44322038..08ff3da346412b841f1372e372dff56b27f7839d 100644 (file)
@@ -6,6 +6,7 @@ target_link_libraries(fgviewer
        ${OPENSCENEGRAPH_LIBRARIES} 
        ${OPENGL_LIBRARIES}
        ${ZLIB_LIBRARIES}
-       ${PLIB_LIBRARIES})
+       ${PLIB_LIBRARIES}
+       ${JS_LIBS})
        
 install(TARGETS fgviewer RUNTIME DESTINATION bin)