aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/joystickinputs/android/androidjoystickinput.cpp
blob: 861c1d8d465a05c2f1e3a79eb5cf7761dde8813a (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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only

/*
  Originally based on code from "platform/android/java_godot_lib_jni.cpp" from Godot Engine v4.0
  Copyright (c) 2014-present Godot Engine contributors
  Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
*/

#include "androidjoystickinput.h"
#include <QtCore/qnativeinterface.h>
#include <QtUniversalInput/QUniversalInput>



using namespace QtJniTypes;

Q_DECLARE_JNI_CLASS(KeyEvent, "android/view/KeyEvent")
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")

static void joyConnectionChanged(JNIEnv *, jclass, int deviceId, bool connected, jstring name)
{
    QUniversalInput::instance()->updateJoyConnection(deviceId, connected, QJniObject(name).toString());
}
Q_DECLARE_JNI_NATIVE_METHOD(joyConnectionChanged)

static void joyButton(JNIEnv *, jclass, int deviceId, int button, bool pressed)
{
    qDebug() << "joyButton" << deviceId << button << pressed;
    QUniversalInput::instance()->joyButton(deviceId, JoyButton(button), pressed);
}
Q_DECLARE_JNI_NATIVE_METHOD(joyButton)

static void joyAxis(JNIEnv *, jclass, int deviceId, int axis, float value)
{
    QUniversalInput::instance()->joyAxis(deviceId, JoyAxis(axis), value);
}
Q_DECLARE_JNI_NATIVE_METHOD(joyAxis)

static void joyHat(JNIEnv *, jclass, int deviceId, int hatX, int hatY)
{
    HatMask hat = HatMask::Center;
    if (hatX != 0) {
        if (hatX < 0)
            hat |= HatMask::Left;
        else
            hat |= HatMask::Right;
    }
    if (hatY != 0) {
        if (hatY < 0)
            hat |= HatMask::Up;
        else
            hat |= HatMask::Down;
    }

    QUniversalInput::instance()->joyHat(deviceId, hat);
}
Q_DECLARE_JNI_NATIVE_METHOD(joyHat)

QT_BEGIN_NAMESPACE

const char keyEventClass[] = "android/view/KeyEvent";
inline int keyField(const char *field)
{
    return QJniObject::getStaticField<jint>(keyEventClass, field);
}


static void initJNI()
{
    static bool initialized = false;
    if (initialized)
        return;
    initialized = true;

    qWarning() << "initJNI called in Qt Joystick Input Handler";

    if (!QtJoystickInputHandler::registerNativeMethods({
                                                        Q_JNI_NATIVE_METHOD(joyConnectionChanged),
                                                        Q_JNI_NATIVE_METHOD(joyButton),
                                                        Q_JNI_NATIVE_METHOD(joyAxis),
                                                        Q_JNI_NATIVE_METHOD(joyHat)}))
        qCritical("Failed to register native methods for QtJoystickInputHandler");
}

AndroidJoystickInput::AndroidJoystickInput()
{
    initJNI();
    m_qtJoystickInputHandler = QtJoystickInputHandler(QtAndroidPrivate::activity());
    QtAndroidPrivate::registerGenericMotionEventListener(this);
    QtAndroidPrivate::registerKeyEventListener(this);
    start();
}

AndroidJoystickInput::~AndroidJoystickInput()
{
    stop();
    QtAndroidPrivate::unregisterGenericMotionEventListener(this);
    QtAndroidPrivate::unregisterKeyEventListener(this);
}

bool AndroidJoystickInput::handleKeyEvent(jobject event)
{
    static int ACTION_DOWN = keyField("ACTION_DOWN");
    static int ACTION_UP = keyField("ACTION_UP");
    QJniObject ev(event);

    // Pass the event to the QtJoystickInputHandler Java class.
    if (m_qtJoystickInputHandler.isValid()) {
        const int keyCode = ev.callMethod<jint>("getKeyCode", "()I");
        const int action = ev.callMethod<jint>("getAction", "()I");

        if (action == ACTION_UP)
            return m_qtJoystickInputHandler.callMethod<bool>("onKeyUp", keyCode, KeyEvent(event));
        else if (action == ACTION_DOWN)
            return m_qtJoystickInputHandler.callMethod<bool>("onKeyDown", keyCode, KeyEvent(event));
    }

    return false;
}

bool AndroidJoystickInput::handleGenericMotionEvent(jobject event)
{
    if (m_qtJoystickInputHandler.isValid())
        return m_qtJoystickInputHandler.callMethod<bool>("onGenericMotionEvent", MotionEvent(event));

    return false;
}

void AndroidJoystickInput::start()
{
    if (QtAndroidPrivate::androidSdkVersion() >= 16)
        m_qtJoystickInputHandler.callMethod<void>("register", jlong(this));
}

void AndroidJoystickInput::stop()
{
    if (QtAndroidPrivate::androidSdkVersion() >= 16)
        m_qtJoystickInputHandler.callMethod<void>("unregister");
}

QT_END_NAMESPACE