/* * Copyright (C) 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 * * https://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 #include #include #include "GameController.h" #include "ThreadUtil.h" namespace paddleboat { class GameControllerManager { private: // Allows construction with std::unique_ptr from a static method, but // disallows construction outside of the class since no one else can // construct a ConstructorTag struct ConstructorTag {}; static constexpr int32_t MAX_MOUSE_DEVICES = 2; static constexpr int32_t INVALID_MOUSE_ID = -1; static constexpr int32_t MAX_REMAP_TABLE_SIZE = 256; // Assuming update is getting called at 60Hz, wait one minute in between // checking battery status static constexpr int32_t BATTERY_REFRESH_WAIT = 60 * 60; public: GameControllerManager(JNIEnv *env, jobject jcontext, ConstructorTag); ~GameControllerManager(); static inline int32_t getRemapTableSize() { return MAX_REMAP_TABLE_SIZE; } static Paddleboat_ErrorCode init(JNIEnv *env, jobject jcontext); static void destroyInstance(JNIEnv *env); static bool isInitialized(); // Get/Set whether AKEYCODE_BACK is 'eaten' or allowed to pass through to // the system This can be used to block the OS backing out of the game, or // allowing it if the game is in an appropriate state (i.e. the title // screen) static bool getBackButtonConsumed(); static void setBackButtonConsumed(bool consumed); static Paddleboat_ErrorCode setControllerLight( const int32_t controllerIndex, const Paddleboat_LightType lightType, const uint32_t lightData, JNIEnv *env); static void setControllerStatusCallback( Paddleboat_ControllerStatusCallback statusCallback, void *userData); static void setMotionDataCallback( Paddleboat_MotionDataCallback motionDataCallback, void *userData); static void setMouseStatusCallback( Paddleboat_MouseStatusCallback statusCallback, void *userData); static void onStop(JNIEnv *env); static void onStart(JNIEnv *env); static void update(JNIEnv *env); static Paddleboat_ErrorCode getControllerData( const int32_t controllerIndex, Paddleboat_Controller_Data *controllerData); static Paddleboat_ErrorCode getControllerInfo( const int32_t controllerIndex, Paddleboat_Controller_Info *deviceInfo); static Paddleboat_ErrorCode getControllerName(const int32_t controllerIndex, const size_t bufferSize, char *controllerName); static Paddleboat_ControllerStatus getControllerStatus( const int32_t controllerIndex); static Paddleboat_ErrorCode setControllerVibrationData( const int32_t controllerIndex, const Paddleboat_Vibration_Data *vibrationData, JNIEnv *env); static Paddleboat_ErrorCode getMouseData(Paddleboat_Mouse_Data *mouseData); static Paddleboat_MouseStatus getMouseStatus(); static int32_t processInputEvent(const AInputEvent *event); static int32_t processGameActivityKeyInputEvent(const void *event, const size_t eventSize); static int32_t processGameActivityMotionInputEvent(const void *event, const size_t eventSize); static uint64_t getActiveAxisMask(); static void addControllerRemapData( const Paddleboat_Remap_Addition_Mode addMode, const int32_t remapTableEntryCount, const Paddleboat_Controller_Mapping_Data *mappingData); static int32_t getControllerRemapTableData( const int32_t destRemapTableEntryCount, Paddleboat_Controller_Mapping_Data *mappingData); // Called from the JNI bridge functions static GameControllerDeviceInfo *onConnection(); static void onDisconnection(const int32_t deviceId); static void onMotionData(const int32_t deviceId, const int32_t motionType, const uint64_t timestamp, const float dataX, const float dataY, const float dataZ); static void onMouseConnection(const int32_t deviceId); static void onMouseDisconnection(const int32_t deviceId); static jclass getGameControllerClass(); static jobject getGameControllerObject(); // device debug helper function static int32_t getLastKeycode(); private: static GameControllerManager *getInstance(); Paddleboat_ErrorCode initMethods(JNIEnv *env); bool isLightTypeSupported(const Paddleboat_Controller_Info &controllerInfo, const Paddleboat_LightType lightType); int32_t processControllerKeyEvent(const AInputEvent *event, GameController &gameController); int32_t processControllerGameActivityKeyEvent( const Paddleboat_GameActivityKeyEvent *event, const size_t eventSize, GameController &gameController); int32_t processMouseEvent(const AInputEvent *event); int32_t processGameActivityMouseEvent(const void *event, const size_t eventSize, const int32_t eventDeviceId); void rescanVirtualMouseControllers(); void updateBattery(JNIEnv *env); void updateMouseDataTimestamp(); void releaseGlobals(JNIEnv *env); const Paddleboat_Controller_Mapping_Data *getMapForController( const GameController &gameController); bool mInitialized = false; bool mGCMClassInitialized = false; bool mBackButtonConsumed = true; bool mMotionEventReporting = false; int32_t mApiLevel = 16; int32_t mBatteryWait = BATTERY_REFRESH_WAIT; jobject mContext = NULL; jclass mGameControllerClass = NULL; jobject mGameControllerObject = NULL; jmethodID mInitMethodId = NULL; jmethodID mGetApiLevelMethodId = NULL; jmethodID mGetBatteryLevelMethodId = NULL; jmethodID mGetBatteryStatusMethodId = NULL; jmethodID mSetLightMethodId = NULL; jmethodID mSetNativeReadyMethodId = NULL; jmethodID mSetReportMotionEventsMethodId = NULL; jmethodID mSetVibrationMethodId = NULL; uint64_t mActiveAxisMask = 0; int32_t mRemapEntryCount = 0; Paddleboat_Controller_Mapping_Data mMappingTable[MAX_REMAP_TABLE_SIZE]; Paddleboat_MotionDataCallback mMotionDataCallback = nullptr; void *mMotionDataCallbackUserData = nullptr; GameController mGameControllers[PADDLEBOAT_MAX_CONTROLLERS]; Paddleboat_ControllerStatusCallback mStatusCallback = nullptr; void *mStatusCallbackUserData = nullptr; // device debug helper int32_t mLastKeyEventKeyCode = 0; Paddleboat_MouseStatus mMouseStatus = PADDLEBOAT_MOUSE_NONE; int32_t mMouseDeviceIds[MAX_MOUSE_DEVICES] = {INVALID_MOUSE_ID, INVALID_MOUSE_ID}; int32_t mMouseControllerIndex = INVALID_MOUSE_ID; Paddleboat_Mouse_Data mMouseData; Paddleboat_MouseStatusCallback mMouseCallback = nullptr; void *mMouseCallbackUserData = nullptr; std::mutex mUpdateMutex; static std::mutex sInstanceMutex; static std::unique_ptr sInstance GUARDED_BY(sInstanceMutex); }; } // namespace paddleboat