1/*
2 * Copyright (C) 2012 Zan Dobersek <zandobersek@gmail.com>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
23 * DAMAGE.
24 */
25
26#include "config.h"
27#include "GamepadDeviceLinux.h"
28
29#if ENABLE(GAMEPAD_DEPRECATED)
30
31#include <fcntl.h>
32#include <sys/ioctl.h>
33#include <unistd.h>
34#include <wtf/text/CString.h>
35
36namespace WebCore {
37
38GamepadDeviceLinux::GamepadDeviceLinux(String deviceFile)
39    : m_fileDescriptor(-1)
40    , m_connected(false)
41    , m_lastTimestamp(0)
42{
43    // FIXME: Log errors when returning early.
44    m_fileDescriptor = open(deviceFile.utf8().data(), O_RDONLY | O_NONBLOCK);
45    if (m_fileDescriptor == -1)
46        return;
47
48    char deviceName[1024];
49    if (ioctl(m_fileDescriptor, JSIOCGNAME(sizeof(deviceName)), deviceName) < 0)
50        return;
51    m_deviceName = String(deviceName).simplifyWhiteSpace();
52
53    uint8_t numberOfAxes;
54    uint8_t numberOfButtons;
55    if (ioctl(m_fileDescriptor, JSIOCGAXES, &numberOfAxes) < 0 || ioctl(m_fileDescriptor, JSIOCGBUTTONS, &numberOfButtons) < 0)
56        return;
57    m_axes.fill(0.0, numberOfAxes);
58    m_buttons.fill(0.0, numberOfButtons);
59}
60
61GamepadDeviceLinux::~GamepadDeviceLinux()
62{
63    if (m_fileDescriptor != -1)
64        close(m_fileDescriptor);
65}
66
67void GamepadDeviceLinux::updateForEvent(struct js_event event)
68{
69    if (!(event.type & JS_EVENT_AXIS || event.type & JS_EVENT_BUTTON))
70        return;
71
72    // Mark the device as connected only if it is not yet connected, the event is not an initialization
73    // and the value is not 0 (indicating a genuine interaction with the device).
74    if (!m_connected && !(event.type & JS_EVENT_INIT) && event.value)
75        m_connected = true;
76
77    if (event.type & JS_EVENT_AXIS)
78        m_axes[event.number] = normalizeAxisValue(event.value);
79    else if (event.type & JS_EVENT_BUTTON)
80        m_buttons[event.number] = normalizeButtonValue(event.value);
81
82    m_lastTimestamp = event.time;
83}
84
85float GamepadDeviceLinux::normalizeAxisValue(short value)
86{
87    // Normalize from range [-32767, 32767] into range [-1.0, 1.0]
88    return value / 32767.0f;
89}
90
91float GamepadDeviceLinux::normalizeButtonValue(short value)
92{
93    // Normalize from range [0, 1] into range [0.0, 1.0]
94    return value / 1.0f;
95}
96
97} // namespace WebCore
98
99#endif // ENABLE(GAMEPAD_DEPRECATED)
100