]> git.tdb.fi Git - libs/gui.git/blobdiff - source/input/linux/gamecontroller.cpp
Streamline iterators and loop constructs
[libs/gui.git] / source / input / linux / gamecontroller.cpp
index bf690494a91c76d08d71f10d2ad8a425cf56a2a8..58e4ef17325d2aa8d3b0a22447ccae4b30ac86da 100644 (file)
@@ -1,6 +1,8 @@
 #include <fcntl.h>
 #include <linux/joystick.h>
+#include <msp/core/algorithm.h>
 #include <msp/core/systemerror.h>
+#include <msp/fs/dir.h>
 #include <msp/io/handle_private.h>
 #include <msp/strings/format.h>
 #include "gamecontroller.h"
@@ -11,12 +13,24 @@ using namespace std;
 namespace Msp {
 namespace Input {
 
+vector<string> GameController::Private::detected_controllers;
+
 GameController::GameController(unsigned index):
-       priv(new Private)
+       Device(GAME_CONTROLLER),
+       event_disp(0)
 {
-       priv->dev = new JsDevice(format("/dev/input/js%d", index));
+       if(!detect_done)
+               detect();
+       if(index>=Private::detected_controllers.size())
+               throw device_not_available(format("GameController(%d)", index));
+
+       JsDevice *device = new JsDevice(Private::detected_controllers[index]);
+
+       priv = new Private;
+       priv->dev = device;
+       priv->dev->signal_data_available.connect(sigc::mem_fun(this, static_cast<void (GameController::*)()>(&GameController::tick)));
        name = priv->dev->get_name();
-       tick();
+       tick(Time::zero);
 }
 
 GameController::~GameController()
@@ -25,21 +39,52 @@ GameController::~GameController()
        delete priv;
 }
 
+unsigned GameController::detect()
+{
+       Private::detected_controllers.clear();
+
+       FS::Path dev_input = "/dev/input";
+       vector<string> devices = FS::list_filtered(dev_input, "^js[0-9]+");
+       sort(devices);
+       for(const string &f: devices)
+               // TODO check permissions
+               Private::detected_controllers.push_back((dev_input/f).str());
+
+       detect_done = true;
+       n_detected_controllers = Private::detected_controllers.size();
+
+       return Private::detected_controllers.size();
+}
+
+void GameController::use_event_dispatcher(IO::EventDispatcher *ed)
+{
+       if(event_disp)
+               event_disp->remove(*priv->dev);
+       event_disp = ed;
+       if(event_disp)
+               event_disp->add(*priv->dev);
+}
+
 void GameController::tick()
 {
        js_event events[16];
+       bool first = true;
        while(1)
        {
+               if(!first && !IO::poll(*priv->dev, IO::P_INPUT, Time::zero))
+                       break;
+
+               first = false;
                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;
+                       unsigned etype = events[i].type&0x7F;
                        bool init = events[i].type&JS_EVENT_INIT;
-                       if(type==JS_EVENT_AXIS)
+                       if(etype==JS_EVENT_AXIS)
                                set_axis_value(events[i].number, events[i].value/32768.0f, !init);
-                       else if(type==JS_EVENT_BUTTON)
+                       else if(etype==JS_EVENT_BUTTON)
                                set_button_state(events[i].number, events[i].value, !init);
                }
 
@@ -49,29 +94,42 @@ void GameController::tick()
 }
 
 
+void GameController::tick(const Time::TimeDelta &timeout)
+{
+       if(IO::poll(*priv->dev, IO::P_INPUT, timeout))
+               tick();
+}
+
+
 JsDevice::JsDevice(const string &fn)
 {
        mode = IO::M_READ;
-       *handle = open(fn.c_str(), O_RDONLY|O_NONBLOCK);
+       *handle = open(fn.c_str(), O_RDONLY);
        if(!handle)
                throw system_error(format("open(%s)", fn));
+       set_events(IO::P_INPUT);
+}
+
+JsDevice::~JsDevice()
+{
+       sys_close(handle);
 }
 
 string JsDevice::get_name() const
 {
-       char buf[128];
+       char buf[128] = { 0 };
        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)
+size_t JsDevice::do_read(char *buf, size_t size)
 {
        return IO::sys_read(handle, buf, size);
 }
 
-unsigned JsDevice::do_write(const char *, unsigned)
+size_t JsDevice::do_write(const char *, size_t)
 {
        throw IO::invalid_access(IO::M_WRITE);
 }