--- /dev/null
+#include <fcntl.h>
+#include <linux/joystick.h>
+#include <msp/core/systemerror.h>
+#include <msp/io/handle_private.h>
+#include <msp/strings/format.h>
+#include "gamecontroller.h"
+#include "gamecontroller_platform.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Input {
+
+GameController::GameController(unsigned index):
+ priv(new Private)
+{
+ priv->dev = new JsDevice(format("/dev/input/js%d", index));
+ name = priv->dev->get_name();
+ tick();
+}
+
+GameController::~GameController()
+{
+ delete priv->dev;
+ delete priv;
+}
+
+void GameController::tick()
+{
+ js_event events[16];
+ while(1)
+ {
+ unsigned len = priv->dev->read(reinterpret_cast<char *>(events), sizeof(events));
+
+ unsigned count = len/sizeof(js_event);
+ for(unsigned i=0; i<count; ++i)
+ {
+ unsigned type = events[i].type&0x7F;
+ bool init = events[i].type&JS_EVENT_INIT;
+ if(type==JS_EVENT_AXIS)
+ set_axis_value(events[i].number, events[i].value/32768.0f, !init);
+ else if(type==JS_EVENT_BUTTON)
+ set_button_state(events[i].number, events[i].value, !init);
+ }
+
+ if(len<sizeof(events))
+ break;
+ }
+}
+
+
+JsDevice::JsDevice(const string &fn)
+{
+ mode = IO::M_READ;
+ *handle = open(fn.c_str(), O_RDONLY|O_NONBLOCK);
+ if(!handle)
+ throw system_error(format("open(%s)", fn));
+}
+
+string JsDevice::get_name() const
+{
+ char buf[128];
+ int ret = ioctl(*handle, JSIOCGNAME(sizeof(buf)), buf);
+ if(ret<0)
+ throw system_error("ioctl(JSIOCGNAME)");
+ return buf;
+}
+
+unsigned JsDevice::do_read(char *buf, unsigned size)
+{
+ return IO::sys_read(handle, buf, size);
+}
+
+unsigned JsDevice::do_write(const char *, unsigned)
+{
+ throw IO::invalid_access(IO::M_WRITE);
+}
+
+} // namespace Input
+} // namespace Msp
--- /dev/null
+#ifndef GAMECONTROLLER_PRIVATE_H_
+#define GAMECONTROLLER_PRIVATE_H_
+
+#include <msp/io/eventobject.h>
+#include <msp/io/handle.h>
+
+namespace Msp {
+namespace Input {
+
+class JsDevice: public IO::EventObject
+{
+private:
+ IO::Handle handle;
+
+public:
+ JsDevice(const std::string &);
+
+ std::string get_name() const;
+
+protected:
+ virtual unsigned do_read(char *, unsigned);
+ virtual unsigned do_write(const char *, unsigned);
+
+public:
+ virtual const IO::Handle &get_event_handle() { return handle; }
+};
+
+
+struct GameController::Private
+{
+ JsDevice *dev;
+};
+
+} // namespace Input
+} // namespace Msp
+
+#endif