fix android controller (#339)

This commit is contained in:
江战 2023-03-22 14:40:31 +08:00 committed by GitHub
parent c7c9094d28
commit 2755cc5352
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 328 additions and 115 deletions

View File

@ -57,6 +57,7 @@ endif()
if(ANDROID)
set(CC_GAME_ACTIVITY_SOURCES
${CMAKE_CURRENT_LIST_DIR}/android-gamesdk/GameActivity/game-activity/include/game-activity/GameActivity.cpp
${CMAKE_CURRENT_LIST_DIR}/android-gamesdk/GameActivity/game-activity/include/game-activity/system_utils.cpp
${CMAKE_CURRENT_LIST_DIR}/android-gamesdk/GameActivity/game-activity/include/game-activity/native_app_glue/android_native_app_glue.c
${CMAKE_CURRENT_LIST_DIR}/android-gamesdk/GameActivity/game-activity/include/game-text-input/gametextinput.cpp
)

View File

@ -16,6 +16,7 @@
#define LOG_TAG "GameActivity"
#include "GameActivity.h"
#include "system_utils.h"
#include <android/api-level.h>
#include <android/asset_manager.h>
@ -870,138 +871,119 @@ static struct {
jmethodID getClassification;
jmethodID getEdgeFlags;
jmethodID getHistorySize;
jmethodID getHistoricalEventTime;
jmethodID getPointerCount;
jmethodID getPointerId;
jmethodID getToolType;
jmethodID getRawX;
jmethodID getRawY;
jmethodID getXPrecision;
jmethodID getYPrecision;
jmethodID getAxisValue;
jmethodID getHistoricalAxisValue;
} gMotionEventClassInfo;
extern "C" void GameActivityMotionEvent_destroy(
GameActivityMotionEvent *c_event) {
delete c_event->historicalAxisValues;
delete c_event->historicalEventTimesMillis;
delete c_event->historicalEventTimesNanos;
}
extern "C" void GameActivityMotionEvent_fromJava(
JNIEnv *env, jobject motionEvent, GameActivityMotionEvent *out_event) {
static bool gMotionEventClassInfoInitialized = false;
if (!gMotionEventClassInfoInitialized) {
int sdkVersion = GetSystemPropAsInt("ro.build.version.sdk");
gMotionEventClassInfo = {0};
jclass motionEventClass = env->FindClass("android/view/MotionEvent");
gMotionEventClassInfo.getDeviceId =
env->GetMethodID(motionEventClass, "getDeviceId", "()I");
gMotionEventClassInfo.getSource =
env->GetMethodID(motionEventClass, "getSource", "()I");
gMotionEventClassInfo.getAction =
env->GetMethodID(motionEventClass, "getAction", "()I");
gMotionEventClassInfo.getEventTime =
env->GetMethodID(motionEventClass, "getEventTime", "()J");
gMotionEventClassInfo.getDownTime =
env->GetMethodID(motionEventClass, "getDownTime", "()J");
gMotionEventClassInfo.getFlags =
env->GetMethodID(motionEventClass, "getFlags", "()I");
gMotionEventClassInfo.getMetaState =
env->GetMethodID(motionEventClass, "getMetaState", "()I");
if (sdkVersion >= 23) {
gMotionEventClassInfo.getActionButton =
env->GetMethodID(motionEventClass, "getActionButton", "()I");
}
if (sdkVersion >= 14) {
gMotionEventClassInfo.getButtonState =
env->GetMethodID(motionEventClass, "getButtonState", "()I");
}
if (sdkVersion >= 29) {
gMotionEventClassInfo.getClassification =
env->GetMethodID(motionEventClass, "getClassification", "()I");
}
gMotionEventClassInfo.getEdgeFlags =
env->GetMethodID(motionEventClass, "getEdgeFlags", "()I");
gMotionEventClassInfo.getPointerCount =
env->GetMethodID(motionEventClass, "getPointerCount", "()I");
gMotionEventClassInfo.getPointerId =
env->GetMethodID(motionEventClass, "getPointerId", "(I)I");
if (sdkVersion >= 29) {
gMotionEventClassInfo.getRawX =
env->GetMethodID(motionEventClass, "getRawX", "(I)F");
gMotionEventClassInfo.getRawY =
env->GetMethodID(motionEventClass, "getRawY", "(I)F");
}
gMotionEventClassInfo.getXPrecision =
env->GetMethodID(motionEventClass, "getXPrecision", "()F");
gMotionEventClassInfo.getYPrecision =
env->GetMethodID(motionEventClass, "getYPrecision", "()F");
gMotionEventClassInfo.getAxisValue =
env->GetMethodID(motionEventClass, "getAxisValue", "(II)F");
gMotionEventClassInfoInitialized = true;
}
int pointerCount =
env->CallIntMethod(motionEvent, gMotionEventClassInfo.getPointerCount);
JNIEnv *env, jobject motionEvent, GameActivityMotionEvent *out_event,
int pointerCount, int historySize, int deviceId, int source, int action,
int64_t eventTime, int64_t downTime, int flags, int metaState,
int actionButton, int buttonState, int classification, int edgeFlags,
float precisionX, float precisionY) {
pointerCount =
std::min(pointerCount, GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT);
std::min(pointerCount, GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT);
out_event->pointerCount = pointerCount;
for (int i = 0; i < pointerCount; ++i) {
for (jint i = 0; i < pointerCount; ++i) {
out_event->pointers[i] = {
/*id=*/env->CallIntMethod(motionEvent,
gMotionEventClassInfo.getPointerId, i),
/*axisValues=*/{0},
/*rawX=*/gMotionEventClassInfo.getRawX
? env->CallFloatMethod(motionEvent,
gMotionEventClassInfo.getRawX, i)
: 0,
/*rawY=*/gMotionEventClassInfo.getRawY
? env->CallFloatMethod(motionEvent,
gMotionEventClassInfo.getRawY, i)
: 0,
/*id=*/env->CallIntMethod(motionEvent,
gMotionEventClassInfo.getPointerId, i),
/*toolType=*/
env->CallIntMethod(motionEvent, gMotionEventClassInfo.getToolType,
i),
/*axisValues=*/{0.0F},
/*rawX=*/gMotionEventClassInfo.getRawX
? env->CallFloatMethod(motionEvent,
gMotionEventClassInfo.getRawX, i)
: 0.0F,
/*rawY=*/gMotionEventClassInfo.getRawY
? env->CallFloatMethod(motionEvent,
gMotionEventClassInfo.getRawY, i)
: 0.0F,
};
for (int axisIndex = 0;
axisIndex < GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT; ++axisIndex) {
if (enabledAxes[axisIndex]) {
out_event->pointers[i].axisValues[axisIndex] =
env->CallFloatMethod(motionEvent,
gMotionEventClassInfo.getAxisValue,
axisIndex, i);
env->CallFloatMethod(motionEvent,
gMotionEventClassInfo.getAxisValue,
axisIndex, i);
}
}
}
out_event->deviceId =
env->CallIntMethod(motionEvent, gMotionEventClassInfo.getDeviceId);
out_event->source =
env->CallIntMethod(motionEvent, gMotionEventClassInfo.getSource);
out_event->action =
env->CallIntMethod(motionEvent, gMotionEventClassInfo.getAction);
out_event->eventTime =
env->CallLongMethod(motionEvent, gMotionEventClassInfo.getEventTime) *
1000000;
out_event->downTime =
env->CallLongMethod(motionEvent, gMotionEventClassInfo.getDownTime) *
1000000;
out_event->flags =
env->CallIntMethod(motionEvent, gMotionEventClassInfo.getFlags);
out_event->metaState =
env->CallIntMethod(motionEvent, gMotionEventClassInfo.getMetaState);
out_event->actionButton =
gMotionEventClassInfo.getActionButton
? env->CallIntMethod(motionEvent,
gMotionEventClassInfo.getActionButton)
: 0;
out_event->buttonState =
gMotionEventClassInfo.getButtonState
? env->CallIntMethod(motionEvent,
gMotionEventClassInfo.getButtonState)
: 0;
out_event->classification =
gMotionEventClassInfo.getClassification
? env->CallIntMethod(motionEvent,
gMotionEventClassInfo.getClassification)
: 0;
out_event->edgeFlags =
env->CallIntMethod(motionEvent, gMotionEventClassInfo.getEdgeFlags);
out_event->precisionX =
env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getXPrecision);
out_event->precisionY =
env->CallFloatMethod(motionEvent, gMotionEventClassInfo.getYPrecision);
out_event->historySize = historySize;
out_event->historicalAxisValues =
new float[historySize * pointerCount *
GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT];
out_event->historicalEventTimesMillis = new long[historySize];
out_event->historicalEventTimesNanos = new long[historySize];
for (int historyIndex = 0; historyIndex < historySize; historyIndex++) {
out_event->historicalEventTimesMillis[historyIndex] =
env->CallLongMethod(motionEvent,
gMotionEventClassInfo.getHistoricalEventTime,
historyIndex);
out_event->historicalEventTimesNanos[historyIndex] =
out_event->historicalEventTimesMillis[historyIndex] * 1000000;
for (int i = 0; i < pointerCount; ++i) {
int pointerOffset = i * GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT;
int historyAxisOffset = historyIndex * pointerCount *
GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT;
float *axisValues =
&out_event
->historicalAxisValues[historyAxisOffset + pointerOffset];
for (int axisIndex = 0;
axisIndex < GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT;
++axisIndex) {
if (enabledAxes[axisIndex]) {
axisValues[axisIndex] = env->CallFloatMethod(
motionEvent,
gMotionEventClassInfo.getHistoricalAxisValue, axisIndex,
i, historyIndex);
}
}
}
}
out_event->deviceId = deviceId;
out_event->source = source;
out_event->action = action;
out_event->eventTime = eventTime;
out_event->downTime = downTime;
out_event->flags = flags;
out_event->metaState = metaState;
out_event->actionButton = actionButton;
out_event->buttonState = buttonState;
out_event->classification = classification;
out_event->edgeFlags = edgeFlags;
out_event->precisionX = precisionX;
out_event->precisionY = precisionY;
}
static struct {
@ -1018,6 +1000,8 @@ static struct {
jmethodID getModifiers;
jmethodID getRepeatCount;
jmethodID getKeyCode;
jmethodID getScanCode;
jmethodID getUnicodeChar;
} gKeyEventClassInfo;
extern "C" void GameActivityKeyEvent_fromJava(JNIEnv *env, jobject keyEvent,
@ -1077,14 +1061,25 @@ extern "C" void GameActivityKeyEvent_fromJava(JNIEnv *env, jobject keyEvent,
}
static bool onTouchEvent_native(JNIEnv *env, jobject javaGameActivity,
jlong handle, jobject motionEvent) {
jlong handle, jobject motionEvent,
int pointerCount, int historySize, int deviceId,
int source, int action, int64_t eventTime,
int64_t downTime, int flags, int metaState,
int actionButton, int buttonState,
int classification, int edgeFlags,
float precisionX, float precisionY) {
if (handle == 0) return false;
NativeCode *code = (NativeCode *)handle;
if (code->callbacks.onTouchEvent == nullptr) return false;
static GameActivityMotionEvent c_event;
GameActivityMotionEvent_fromJava(env, motionEvent, &c_event);
return code->callbacks.onTouchEvent(code, &c_event);
GameActivityMotionEvent_fromJava(
env, motionEvent, &c_event, pointerCount, historySize, deviceId, source,
action, eventTime, downTime, flags, metaState, actionButton,
buttonState, classification, edgeFlags, precisionX, precisionY);
auto result = code->callbacks.onTouchEvent(code, &c_event);
GameActivityMotionEvent_destroy(&c_event);
return result;
}
static bool onKeyUp_native(JNIEnv *env, jobject javaGameActivity, jlong handle,
@ -1184,7 +1179,7 @@ static const JNINativeMethod g_methods[] = {
{"onSurfaceRedrawNeededNative", "(JLandroid/view/Surface;)V",
(void *)onSurfaceRedrawNeeded_native},
{"onSurfaceDestroyedNative", "(J)V", (void *)onSurfaceDestroyed_native},
{"onTouchEventNative", "(JLandroid/view/MotionEvent;)Z",
{"onTouchEventNative", "(JLandroid/view/MotionEvent;IIIIIJJIIIIIIFF)Z",
(void *)onTouchEvent_native},
{"onKeyDownNative", "(JLandroid/view/KeyEvent;)Z",
(void *)onKeyDown_native},
@ -1247,6 +1242,104 @@ static int jniRegisterNativeMethods(JNIEnv *env, const char *className,
LOG_FATAL("RegisterNatives failed for '%s'; aborting...", className);
}
static void initKeyEvents(JNIEnv *env) {
int sdkVersion = gamesdk::GetSystemPropAsInt("ro.build.version.sdk");
gKeyEventClassInfo = {0};
jclass keyEventClass = env->FindClass("android/view/KeyEvent");
gKeyEventClassInfo.getDeviceId =
env->GetMethodID(keyEventClass, "getDeviceId", "()I");
gKeyEventClassInfo.getSource =
env->GetMethodID(keyEventClass, "getSource", "()I");
gKeyEventClassInfo.getAction =
env->GetMethodID(keyEventClass, "getAction", "()I");
gKeyEventClassInfo.getEventTime =
env->GetMethodID(keyEventClass, "getEventTime", "()J");
gKeyEventClassInfo.getDownTime =
env->GetMethodID(keyEventClass, "getDownTime", "()J");
gKeyEventClassInfo.getFlags =
env->GetMethodID(keyEventClass, "getFlags", "()I");
gKeyEventClassInfo.getMetaState =
env->GetMethodID(keyEventClass, "getMetaState", "()I");
if (sdkVersion >= 13) {
gKeyEventClassInfo.getModifiers =
env->GetMethodID(keyEventClass, "getModifiers", "()I");
}
gKeyEventClassInfo.getRepeatCount =
env->GetMethodID(keyEventClass, "getRepeatCount", "()I");
gKeyEventClassInfo.getKeyCode =
env->GetMethodID(keyEventClass, "getKeyCode", "()I");
gKeyEventClassInfo.getScanCode =
env->GetMethodID(keyEventClass, "getScanCode", "()I");
gKeyEventClassInfo.getUnicodeChar =
env->GetMethodID(keyEventClass, "getUnicodeChar", "()I");
}
static void initMotionEvents(JNIEnv *env) {
int sdkVersion = gamesdk::GetSystemPropAsInt("ro.build.version.sdk");
gMotionEventClassInfo = {0};
jclass motionEventClass = env->FindClass("android/view/MotionEvent");
gMotionEventClassInfo.getDeviceId =
env->GetMethodID(motionEventClass, "getDeviceId", "()I");
gMotionEventClassInfo.getSource =
env->GetMethodID(motionEventClass, "getSource", "()I");
gMotionEventClassInfo.getAction =
env->GetMethodID(motionEventClass, "getAction", "()I");
gMotionEventClassInfo.getEventTime =
env->GetMethodID(motionEventClass, "getEventTime", "()J");
gMotionEventClassInfo.getDownTime =
env->GetMethodID(motionEventClass, "getDownTime", "()J");
gMotionEventClassInfo.getFlags =
env->GetMethodID(motionEventClass, "getFlags", "()I");
gMotionEventClassInfo.getMetaState =
env->GetMethodID(motionEventClass, "getMetaState", "()I");
if (sdkVersion >= 23) {
gMotionEventClassInfo.getActionButton =
env->GetMethodID(motionEventClass, "getActionButton", "()I");
}
if (sdkVersion >= 14) {
gMotionEventClassInfo.getButtonState =
env->GetMethodID(motionEventClass, "getButtonState", "()I");
}
if (sdkVersion >= 29) {
gMotionEventClassInfo.getClassification =
env->GetMethodID(motionEventClass, "getClassification", "()I");
}
gMotionEventClassInfo.getEdgeFlags =
env->GetMethodID(motionEventClass, "getEdgeFlags", "()I");
gMotionEventClassInfo.getHistorySize =
env->GetMethodID(motionEventClass, "getHistorySize", "()I");
gMotionEventClassInfo.getHistoricalEventTime =
env->GetMethodID(motionEventClass, "getHistoricalEventTime", "(I)J");
gMotionEventClassInfo.getPointerCount =
env->GetMethodID(motionEventClass, "getPointerCount", "()I");
gMotionEventClassInfo.getPointerId =
env->GetMethodID(motionEventClass, "getPointerId", "(I)I");
gMotionEventClassInfo.getToolType =
env->GetMethodID(motionEventClass, "getToolType", "(I)I");
if (sdkVersion >= 29) {
gMotionEventClassInfo.getRawX =
env->GetMethodID(motionEventClass, "getRawX", "(I)F");
gMotionEventClassInfo.getRawY =
env->GetMethodID(motionEventClass, "getRawY", "(I)F");
}
gMotionEventClassInfo.getXPrecision =
env->GetMethodID(motionEventClass, "getXPrecision", "()F");
gMotionEventClassInfo.getYPrecision =
env->GetMethodID(motionEventClass, "getYPrecision", "()F");
gMotionEventClassInfo.getAxisValue =
env->GetMethodID(motionEventClass, "getAxisValue", "(II)F");
gMotionEventClassInfo.getHistoricalAxisValue =
env->GetMethodID(motionEventClass, "getHistoricalAxisValue", "(III)F");
}
static void GameActivityEventsInit(JNIEnv *env) {
initMotionEvents(env);
initKeyEvents(env);
}
extern "C" int GameActivity_register(JNIEnv *env) {
ALOGD("GameActivity_register");
jclass activity_class;
@ -1289,6 +1382,9 @@ extern "C" int GameActivity_register(JNIEnv *env) {
windowInsetsCompatType_class, methodNames[i],
"()I");
}*/
GameActivityEventsInit(env);
return jniRegisterNativeMethods(env, kGameActivityPathName, g_methods,
NELEM(g_methods));
}

View File

@ -137,6 +137,7 @@ typedef struct GameActivity {
*/
typedef struct GameActivityPointerAxes {
int32_t id;
int32_t toolType;
float axisValues[GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT];
float rawX;
float rawY;
@ -240,6 +241,12 @@ typedef struct GameActivityMotionEvent {
float precisionX;
float precisionY;
int historySize;
long* historicalEventTimesMillis;
long* historicalEventTimesNanos;
float* historicalAxisValues;
} GameActivityMotionEvent;
/**
@ -421,8 +428,12 @@ typedef struct GameActivityCallbacks {
* activity.
* Ownership of out_event is maintained by the caller.
*/
void GameActivityMotionEvent_fromJava(JNIEnv* env, jobject motionEvent,
GameActivityMotionEvent* out_event);
void GameActivityMotionEvent_fromJava(
JNIEnv *env, jobject motionEvent, GameActivityMotionEvent *out_event,
int pointerCount, int historySize, int deviceId, int source, int action,
int64_t eventTime, int64_t downTime, int flags, int metaState,
int actionButton, int buttonState, int classification, int edgeFlags,
float precisionX, float precisionY);
/**
* \brief Convert a Java `KeyEvent` to a `GameActivityKeyEvent`.

View File

@ -0,0 +1,72 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "system_utils.h"
#include <android/api-level.h>
#include <stdlib.h>
#include <sys/system_properties.h>
namespace gamesdk {
#if __ANDROID_API__ >= 26
std::string getSystemPropViaCallback(const char* key,
const char* default_value = "") {
const prop_info* prop = __system_property_find(key);
if (prop == nullptr) {
return default_value;
}
std::string return_value;
auto thunk = [](void* cookie, const char* /*name*/, const char* value,
uint32_t /*serial*/) {
if (value != nullptr) {
std::string* r = static_cast<std::string*>(cookie);
*r = value;
}
};
__system_property_read_callback(prop, thunk, &return_value);
return return_value;
}
#else
std::string getSystemPropViaGet(const char* key,
const char* default_value = "") {
char buffer[PROP_VALUE_MAX + 1] = ""; // +1 for terminator
int bufferLen = __system_property_get(key, buffer);
if (bufferLen > 0)
return buffer;
else
return "";
}
#endif
std::string GetSystemProp(const char* key, const char* default_value) {
#if __ANDROID_API__ >= 26
return getSystemPropViaCallback(key, default_value);
#else
return getSystemPropViaGet(key, default_value);
#endif
}
int GetSystemPropAsInt(const char* key, int default_value) {
std::string prop = GetSystemProp(key);
return prop == "" ? default_value : strtoll(prop.c_str(), nullptr, 10);
}
bool GetSystemPropAsBool(const char* key, bool default_value) {
return GetSystemPropAsInt(key, default_value) != 0;
}
} // namespace gamesdk

View File

@ -0,0 +1,32 @@
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "string"
namespace gamesdk {
// Get the value of the given system property
std::string GetSystemProp(const char* key, const char* default_value = "");
// Get the value of the given system property as an integer
int GetSystemPropAsInt(const char* key, int default_value = 0);
// Get the value of the given system property as a bool
bool GetSystemPropAsBool(const char* key, bool default_value = false);
} // namespace gamesdk

View File

@ -33,6 +33,7 @@ namespace paddleboat {
typedef struct Paddleboat_GameActivityPointerInfo {
int32_t id;
int32_t toolType; // added in newer version
float axisValues[PADDLEBOAT_GAME_ACTIVITY_POINTER_INFO_AXIS_COUNT];
float rawX;
float rawY;