class Joystick::Device

Public Class Methods

new(path) click to toggle source

Construct a new Joystick::Device object. path is the file path to the joystick's input device e.g. “/dev/input/js0”

VALUE js_dev_init(VALUE klass, VALUE dev_path)
{
        int *fd;
        VALUE dev;
        
        if((fd = malloc(sizeof(int))) != NULL) {
                if((*fd = open(RSTRING_PTR(dev_path), O_RDONLY)) >= 0) {
                        if(*fd >= MAX_JS)
                                rb_raise(rb_eException, "Error");
                        
                        dev = Data_Wrap_Struct(klass, jsdevice_mark, jsdevice_free, fd);
                        rb_ivar_set(dev, rb_intern("@axis"), rb_ary_new());
                        rb_ivar_set(dev, rb_intern("@button"), rb_ary_new());
                        return dev;
                }
        }      
        return Qnil;
}

Public Instance Methods

axes() click to toggle source

Returns the number of axes of the device.

VALUE js_dev_axes(VALUE klass)
{
        int *fd;
        unsigned char axes;

        Data_Get_Struct(klass, int, fd);
        if(ioctl(*fd, JSIOCGAXES, &axes) == -1) {
                rb_raise(rb_eException, "cannot retrieve axes");
        }
        return INT2FIX(axes);
}
axes_maps() click to toggle source

TODO figure this out

VALUE js_dev_axes_maps(VALUE klass)
{
        int *fd;

        uint8_t axes_maps[ABS_MAX + 1];
        Data_Get_Struct(klass, int, fd);
        if(ioctl(*fd, JSIOCGAXMAP, &axes_maps) == -1) {
                rb_raise(rb_eException, "cannot retrive axes");
        }
        return INT2FIX(axes_maps);
}
axis() click to toggle source

Reader for @axis which stores the latest axis values.

VALUE js_dev_axis(VALUE klass)
{
        return rb_ivar_get(klass, rb_intern("@axis"));
}
button() click to toggle source

Reader for @button which stores the latest button values.

VALUE js_dev_button(VALUE klass)
{
        return rb_ivar_get(klass, rb_intern("@button"));
}
buttons() click to toggle source

Returns the number of buttons on the device.

VALUE js_dev_buttons(VALUE klass)
{
        int *fd;
        unsigned char buttons;
        Data_Get_Struct(klass, int, fd);
        if(ioctl(*fd, JSIOCGBUTTONS, &buttons) == -1) {
                rb_raise(rb_eException, "cannot retrieve buttons");
        }

        return INT2FIX(buttons);
}
close() click to toggle source

Close the file handle for the device. This should be called for all Joystick::Devices before the script terminates.

VALUE js_dev_close(VALUE klass)
{
        int *fd;
        
        Data_Get_Struct(klass, int, fd);
        close(*fd);
        return Qnil;
}
event(+nonblocking+) click to toggle source

Get a Joystick::Event object from the device.

The optional nonblocking argument determines whether or not this is a blocking call. It is blocking by default.

VALUE js_dev_event_get(int argc, VALUE *argv, VALUE klass)
{
        struct event_arg arg;
        int *fd;
        ssize_t length;
        VALUE nonblocking;

        rb_scan_args(argc, argv, "01", &nonblocking);

        Data_Get_Struct(klass, int, fd);

        if(RTEST(nonblocking))
        {
                /* TODO I'm not sure how big of a performance hit this is */
                fcntl(*fd, F_SETFL, O_NONBLOCK); /* non-blocking mode */
                length = read(*fd, &jse[*fd], sizeof(struct js_event));
                fcntl(*fd, F_SETFL, fcntl(*fd, F_GETFL) & ~O_NONBLOCK); /* revert to blocking mode */
        } else {
                arg.fd = fd;
                rb_thread_blocking_region(js_event_func, (void *)&arg, RUBY_UBF_IO, 0);
                length = arg.l;
        }

        if(length > 0)
        {
                switch(jse[*fd].type & ~JS_EVENT_INIT) /* TODO I think it's safe to assume we have a valid event now */
                {
                        case JS_EVENT_AXIS:
                                rb_ary_store(rb_ivar_get(klass, rb_intern("@axis")), jse[*fd].number, INT2FIX(jse[*fd].value));
                                break;
                        case JS_EVENT_BUTTON:
                                rb_ary_store(rb_ivar_get(klass, rb_intern("@button")), jse[*fd].number, INT2FIX(jse[*fd].value));
                }
                return Data_Wrap_Struct(rb_cEvent, 0, 0, fd);
        }
        
        return Qnil;
}
name() click to toggle source

Returns the name of the device.

VALUE js_dev_name(VALUE klass)
{
        int *fd;
        char name[NAME_LENGTH] = "Unknown";

        Data_Get_Struct(klass, int, fd);
        if(ioctl(*fd, JSIOCGNAME(NAME_LENGTH), name) == -1) {
                rb_raise(rb_eException, "cannot retrieve name");
        }
        return rb_str_new2(name);
}
version() click to toggle source

Returns a string containing the version of the device.

VALUE js_dev_version(VALUE klass)
{
        int *fd;
        int version = 0x000800;
        char js_version[16];
        Data_Get_Struct(klass, int, fd);
        if(ioctl(*fd, JSIOCGVERSION, &version) == -1) {
                rb_raise(rb_eException, "version error");
        }
                
        sprintf(js_version, "%d.%d.%d\n",      
                version >> 16, (version >> 8) & 0xff, version & 0xff);

        return rb_str_new2(js_version);
}