? src/platform/usbjoy.cxx
Index: include/BzfWindow.h
===================================================================
RCS file: /cvsroot/bzflag/bzflag/include/BzfWindow.h,v
retrieving revision 1.5
diff -u -r1.5 BzfWindow.h
--- include/BzfWindow.h	2001/03/04 16:35:56	1.5
+++ include/BzfWindow.h	2001/04/08 17:08:32
@@ -67,6 +67,7 @@
     virtual void	initJoystick(const char* joystickName);
     virtual boolean	joystick() const { return False; }
     virtual void	getJoy(int& x, int& y) const { x = 0; y = 0; }
+    virtual unsigned long getJoyButtons() const { return 0; }
 
     void		callExposeCallbacks() const;
     void		addExposeCallback(void (*cb)(void*), void* data);
Index: src/bzflag/MainWindow.cxx
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzflag/MainWindow.cxx,v
retrieving revision 1.6
diff -u -r1.6 MainWindow.cxx
--- src/bzflag/MainWindow.cxx	2001/04/03 02:38:13	1.6
+++ src/bzflag/MainWindow.cxx	2001/04/08 17:08:33
@@ -241,3 +241,8 @@
   my = ((viewHeight >> 1)*my)/(900);
 }
 
+unsigned long                  MainWindow::getJoyButtonSet() const
+{
+  return window->getJoyButtons();
+}
+
Index: src/bzflag/MainWindow.h
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzflag/MainWindow.h,v
retrieving revision 1.6
diff -u -r1.6 MainWindow.h
--- src/bzflag/MainWindow.h	2001/03/04 16:35:56	1.6
+++ src/bzflag/MainWindow.h	2001/04/08 17:08:33
@@ -76,6 +76,8 @@
     // for these values that we need every frame.
     void		getMousePosition(int& mx, int& my) const;
     void		getJoyPosition(int& mx, int& my) const;
+    unsigned long       getJoyButtonSet() const;
+
 
   private:
     // no copying
Index: src/bzflag/playing.cxx
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/bzflag/playing.cxx,v
retrieving revision 1.31
diff -u -r1.31 playing.cxx
--- src/bzflag/playing.cxx	2001/04/03 02:38:13	1.31
+++ src/bzflag/playing.cxx	2001/04/08 17:08:36
@@ -401,6 +401,8 @@
 static float		roamZoom = 60.0f, roamDZoom;
 #endif
 
+static void            doKeyPlaying(const BzfKeyEvent& key, boolean pressed);
+
 static void		doMotion()
 {
 #if defined(FREEZING)
@@ -409,9 +411,36 @@
 
   // get mouse position
   int mx, my;
-  if (mainWindow->joystick())
+  if (mainWindow->joystick()) {
     mainWindow->getJoyPosition(mx, my);
-  else
+
+    static const BzfKeyEvent::Button button_map[] = { BzfKeyEvent::LeftMouse,
+                                BzfKeyEvent::MiddleMouse,
+                                BzfKeyEvent::RightMouse,
+                                BzfKeyEvent::F1,
+                                BzfKeyEvent::F2,
+                                BzfKeyEvent::F3,
+                                BzfKeyEvent::F4,
+                                BzfKeyEvent::F5,
+                                BzfKeyEvent::F6,
+                                BzfKeyEvent::F7,
+                                BzfKeyEvent::F8,
+                                BzfKeyEvent::F9
+    };
+ 
+    static unsigned long old_buttons = 0;
+    unsigned long new_buttons = mainWindow->getJoyButtonSet();
+    if (old_buttons != new_buttons)
+      for (int j = 0; j<12; j++)
+        if ((old_buttons & (1<<j)) != (new_buttons & (1<<j))) {
+         BzfKeyEvent ev;
+         ev.button = button_map[j];
+          ev.ascii = 0;
+          ev.shift = 0;
+          doKeyPlaying(ev, new_buttons&(1<<j));
+       } 
+    old_buttons = new_buttons;
+  } else
     mainWindow->getMousePosition(mx, my);
 
   // calculate desired rotation
Index: src/platform/Make-linux
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/platform/Make-linux,v
retrieving revision 1.4
diff -u -r1.4 Make-linux
--- src/platform/Make-linux	2001/02/02 09:14:10	1.4
+++ src/platform/Make-linux	2001/04/08 17:08:36
@@ -16,5 +16,6 @@
 	XWindow.cxx			\
 	LinuxDisplay.cxx		\
 	LinuxMedia.cxx			\
+	usbjoy.cxx			\
         $(NULL)
 
Index: src/platform/XWindow.h
===================================================================
RCS file: /cvsroot/bzflag/bzflag/src/platform/XWindow.h,v
retrieving revision 1.6
diff -u -r1.6 XWindow.h
--- src/platform/XWindow.h	2001/03/04 16:35:56	1.6
+++ src/platform/XWindow.h	2001/04/08 17:08:36
@@ -26,6 +26,27 @@
 #include <X11/extensions/XInput.h>
 #endif
 
+#ifdef USBJOYSTICK
+#ifdef __cplusplus
+/* Argh! usb.h has a structure with a member "class". We don't use it, so
+ * let's just move it out of the way
+ */
+#define class CLASS
+extern "C" {
+#endif
+#ifdef __FreeBSD__
+#include <libusb.h>
+#else
+#include <usb.h>
+#endif
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+#ifdef __cplusplus
+#undef class
+}
+#endif
+#endif
+
 class XVisual;
 
 class XWindow : public BzfWindow {
@@ -61,6 +82,13 @@
     void		swapBuffers();
     void		makeContext();
     void		freeContext();
+
+#ifdef USBJOYSTICK
+    void               initJoystick(const char* joystickName);
+    boolean            joystick() const;
+    void               getJoy(int& x, int& y) const;
+    unsigned long      getJoyButtons() const;
+#endif
 
 #ifdef XIJOYSTICK
     void		initJoystick(char* joystickName);
--- /dev/null	Sun Apr  8 09:22:24 2001
+++ src/platform/usbjoy.cxx	Sun Apr  8 09:59:19 2001
@@ -0,0 +1,194 @@
+/*
+ * USB Joystick support for {Net,Free}BSD.
+ *
+ * Copyright 2001, Nick Sayer
+ * This package is free software;  you can redistribute it and/or
+ * modify it under the terms of the license found in the file
+ * named LICENSE that should have accompanied this file.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This file was "inspired" by the joy_usb.c file that is part of the
+ * xmame project. To the extent that code was copied from that file,
+ * it is the author's opinion that distribution under the GPL of the
+ * derivative work is allowed.
+ *
+ */
+
+#ifdef USBJOYSTICK
+#include "XWindow.h"
+#include <X11/Intrinsic.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <stdio.h>
+
+#define MAX_AXIS 3
+
+class usb_joystick {
+public:
+	usb_joystick(const char *name);
+	~usb_joystick();
+	void poll();
+	int num_axis;
+	int axis[MAX_AXIS];
+	int axis_scale[MAX_AXIS];
+	int axis_const[MAX_AXIS];
+	unsigned long buttons;
+	boolean status;
+private:
+	int fd;
+	struct hid_item *hids;
+	char *data_buf;
+	int data_buf_size;
+	int data_buf_offset;
+};
+
+usb_joystick *stick=NULL;
+
+usb_joystick::usb_joystick(const char *name)
+{
+	report_desc_t rd;
+	hid_data *d;
+	hid_item h;
+	int report_id;
+
+	status = FALSE;
+	hids = NULL;
+	num_axis = 0;
+
+	if ((fd = open(name, O_RDONLY | O_NONBLOCK))<0)
+		return;
+	
+	if ((rd = hid_get_report_desc(fd)) == 0) {
+		close(fd);
+		return;
+	}
+
+	data_buf_size = hid_report_size(rd, hid_input, &report_id);
+	if ((data_buf = (char *)malloc(data_buf_size)) == NULL) {
+		hid_dispose_report_desc(rd);
+	}
+	data_buf_offset = (report_id != 0);
+
+	int is_joystick = 0;
+	int interesting_hid = FALSE;
+	for (d = hid_start_parse(rd, 1 << hid_input); hid_get_item(d, &h); ) {
+		int page = HID_PAGE(h.usage);
+		int usage = HID_USAGE(h.usage);
+		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) {
+			int which_axis;
+			switch (usage) {
+				case HUG_X:
+				case HUG_RX: which_axis = 0; break;
+				case HUG_Y:
+				case HUG_RY: which_axis = 1; break;
+				case HUG_Z:
+				case HUG_RZ: which_axis = 2; break;
+				default: interesting_hid = FALSE;
+			}
+			if (interesting_hid) {
+				axis_const[which_axis] = 1000 + (2000*h.logical_maximum)/(h.logical_minimum-h.logical_maximum);
+				axis_scale[which_axis] = (2000*10000)/(h.logical_maximum-h.logical_minimum);
+				axis[which_axis] = (h.logical_minimum +
+					h.logical_maximum) / 2;
+				if (num_axis < (which_axis + 1))
+					num_axis = which_axis + 1;
+			}
+		}
+		if (interesting_hid) {
+			struct hid_item *newhid = new struct hid_item;
+			if (newhid == NULL) {
+				close(fd);
+				return;
+			}
+			*newhid = h;
+			newhid->next = hids;
+			hids = newhid;
+		}
+	}
+	hid_end_parse(d);
+
+	status = TRUE;
+}
+usb_joystick::~usb_joystick() {
+	close(fd);
+}
+
+void usb_joystick::poll() {
+	int len;
+
+/*
+ * The device will buffer a lot of deltas. This can lead to a lot of
+ * latency. To avoid this, we will empty the buffer every time.
+ * It's possible the device may report only changed entries, so we
+ * must process all of the frames to avoid dropping buttons (for example).
+ */
+	while ((len = read(fd, data_buf, data_buf_size)) == data_buf_size) {
+
+		struct hid_item *h;
+
+		for (h = hids ; h; h = h->next) {
+			int d = hid_get_data(data_buf + data_buf_offset, h);
+			int page = HID_PAGE(h->usage);
+			int usage = HID_USAGE(h->usage);
+
+			int which_axis;
+			if (page == HUP_GENERIC_DESKTOP) {
+				switch (usage) {
+					case HUG_X:
+					case HUG_RX: which_axis = 0; break;
+					case HUG_Y:
+					case HUG_RY: which_axis = 1; break;
+					case HUG_Z:
+					case HUG_RZ: which_axis = 2; break;
+				}
+				axis[which_axis] = d;
+			} else if (page == HUP_BUTTON) {
+				buttons &= ~ (1 << (usage - 1));
+				buttons |= (d == h->logical_maximum)?1 << (usage - 1):0;
+			}
+		}
+	}
+
+}
+
+void XWindow::initJoystick(const char *joystickName)
+{
+	stick= new usb_joystick(joystickName);
+}
+
+boolean XWindow::joystick() const
+{
+	return (stick!=NULL)?stick->status:FALSE;
+}
+
+void XWindow::getJoy(int &x, int &y) const
+{
+	stick->poll();
+	x = (stick->axis[0]*stick->axis_scale[0])/10000 + stick->axis_const[0];
+	y = (stick->axis[1]*stick->axis_scale[1])/10000 + stick->axis_const[1];
+}
+
+unsigned long XWindow::getJoyButtons() const
+{
+	stick->poll();
+	return stick->buttons;
+}
+
+#endif
+
