summaryrefslogtreecommitdiffhomepage
path: root/proto-libevdev/ftnoir_protocol_libevdev.cpp
blob: 40ce1b809802e23eaec598a2a3e915bc15f6df52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "ftnoir_protocol_libevdev.h"
#include "api/plugin-api.hpp"

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <errno.h>
#include <string.h>

#include "compat/util.hpp"

#include <algorithm>

#define CHECK_LIBEVDEV(expr) if ((error = (expr)) != 0) goto error;

static const int max_input = 65535;
static const int mid_input = 32767;
static const int min_input = 0;

evdev::evdev() : dev(NULL), uidev(NULL)
{
    int error = 0;

    dev = libevdev_new();

    if (!dev)
        goto error;

    CHECK_LIBEVDEV(libevdev_enable_property(dev, INPUT_PROP_BUTTONPAD));

    libevdev_set_name(dev, "opentrack headpose");

    struct input_absinfo absinfo;

    absinfo.minimum = min_input;
    absinfo.maximum = max_input;
    absinfo.resolution = 1;
    absinfo.value = mid_input;
    absinfo.flat = 1;
    absinfo.fuzz = 0;

    CHECK_LIBEVDEV(libevdev_enable_event_type(dev, EV_ABS));
    CHECK_LIBEVDEV(libevdev_enable_event_code(dev, EV_ABS, ABS_X, &absinfo));
    CHECK_LIBEVDEV(libevdev_enable_event_code(dev, EV_ABS, ABS_Y, &absinfo));
    CHECK_LIBEVDEV(libevdev_enable_event_code(dev, EV_ABS, ABS_Z, &absinfo));
    CHECK_LIBEVDEV(libevdev_enable_event_code(dev, EV_ABS, ABS_RX, &absinfo));
    CHECK_LIBEVDEV(libevdev_enable_event_code(dev, EV_ABS, ABS_RY, &absinfo));
    CHECK_LIBEVDEV(libevdev_enable_event_code(dev, EV_ABS, ABS_RZ, &absinfo));

    /* do not remove next 3 lines or udev scripts won't assign 0664 permissions -sh */
    CHECK_LIBEVDEV(libevdev_enable_event_type(dev, EV_KEY));
    CHECK_LIBEVDEV(libevdev_enable_event_code(dev, EV_KEY, BTN_JOYSTICK, NULL));
    CHECK_LIBEVDEV(libevdev_enable_event_code(dev, EV_KEY, BTN_TRIGGER, NULL));

    CHECK_LIBEVDEV(libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev));

    return;
error:
    if (uidev)
        libevdev_uinput_destroy(uidev);
    if (dev)
        libevdev_free(dev);
    if (error)
        fprintf(stderr, "libevdev error: %d\n", error);
    uidev = NULL;
    dev = NULL;
}

evdev::~evdev()
{
    if (uidev)
        libevdev_uinput_destroy(uidev);
    if (dev)
        libevdev_free(dev);
}

void evdev::pose(const double* headpose) {
    static const int axes[] = {
        /* translation goes first */
        ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ
    };

    static const int max_value[] = {
        100,
        100,
        100,
        180,
        90,
        180
    };

    for (int i = 0; i < 6; i++)
    {
        int value = headpose[i] * mid_input / max_value[i] + mid_input;
        int normalized = clamp(value, min_input, max_input);
        (void) libevdev_uinput_write_event(uidev, EV_ABS, axes[i], normalized);
    }

    (void) libevdev_uinput_write_event(uidev, EV_SYN, SYN_REPORT, 0);
}

module_status evdev::initialize()
{
    if (access("/dev/uinput", R_OK | W_OK))
    {
        char buf[128] {};
        (void) strerror_r(errno, buf, sizeof(buf));
        return error(tr("Can't open /dev/uinput: %1").arg(buf));
    }

    return status_ok();
}

OPENTRACK_DECLARE_PROTOCOL(evdev, LibevdevControls, evdevDll)