irrlicht/source/Irrlicht/Android/CIrrDeviceAndroid.cpp
2023-11-30 15:52:04 +01:00

859 lines
29 KiB
C++

// Copyright (C) 2002-2007 Nikolaus Gebhardt
// Copyright (C) 2007-2011 Christian Stehno
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "CIrrDeviceAndroid.h"
#include "os.h"
#include "CFileSystem.h"
#include "CAndroidAssetReader.h"
#include "CAndroidAssetFileArchive.h"
#include "CKeyEventWrapper.h"
#include "CEGLManager.h"
#include "ISceneManager.h"
#include "IGUIEnvironment.h"
#include "CEGLManager.h"
namespace irr
{
namespace video
{
IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params,
io::IFileSystem* io, video::IContextManager* contextManager);
IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params,
io::IFileSystem* io, video::IContextManager* contextManager);
}
}
namespace irr
{
CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters& param)
: CIrrDeviceStub(param), Accelerometer(0), Gyroscope(0), Focused(false), Initialized(false), Paused(true), JNIEnvAttachedToVM(0)
{
#ifdef _DEBUG
setDebugName("CIrrDeviceAndroid");
#endif
// Get the interface to the native Android activity.
Android = (android_app*)(param.PrivateData);
// Set the private data so we can use it in any static callbacks.
Android->userData = this;
// Set the default command handler. This is a callback function that the Android
// OS invokes to send the native activity messages.
Android->onAppCmd = handleAndroidCommand;
createKeyMap();
// Create a sensor manager to receive touch screen events from the java activity.
SensorManager = ASensorManager_getInstance();
SensorEventQueue = ASensorManager_createEventQueue(SensorManager, Android->looper, LOOPER_ID_USER, 0, 0);
Android->onInputEvent = handleInput;
// Create EGL manager.
ContextManager = new video::CEGLManager();
os::Printer::log("Waiting for Android activity window to be created.", ELL_DEBUG);
do
{
s32 Events = 0;
android_poll_source* Source = 0;
while ((ALooper_pollAll(((Focused && !Paused) || !Initialized) ? 0 : -1, 0, &Events, (void**)&Source)) >= 0)
{
if(Source)
Source->process(Android, Source);
}
}
while(!Initialized);
}
CIrrDeviceAndroid::~CIrrDeviceAndroid()
{
if (GUIEnvironment)
{
GUIEnvironment->drop();
GUIEnvironment = 0;
}
if (SceneManager)
{
SceneManager->drop();
SceneManager = 0;
}
if (VideoDriver)
{
VideoDriver->drop();
VideoDriver = 0;
}
}
bool CIrrDeviceAndroid::run()
{
if (!Initialized)
return false;
os::Timer::tick();
s32 id;
s32 Events = 0;
android_poll_source* Source = 0;
while ((id = ALooper_pollAll(0, 0, &Events, (void**)&Source)) >= 0)
{
if(Source)
Source->process(Android, Source);
// if a sensor has data, we'll process it now.
if (id == LOOPER_ID_USER)
{
ASensorEvent sensorEvent;
while (ASensorEventQueue_getEvents(SensorEventQueue, &sensorEvent, 1) > 0)
{
switch (sensorEvent.type)
{
case ASENSOR_TYPE_ACCELEROMETER:
SEvent accEvent;
accEvent.EventType = EET_ACCELEROMETER_EVENT;
accEvent.AccelerometerEvent.X = sensorEvent.acceleration.x;
accEvent.AccelerometerEvent.Y = sensorEvent.acceleration.y;
accEvent.AccelerometerEvent.Z = sensorEvent.acceleration.z;
postEventFromUser(accEvent);
break;
case ASENSOR_TYPE_GYROSCOPE:
SEvent gyroEvent;
gyroEvent.EventType = EET_GYROSCOPE_EVENT;
gyroEvent.GyroscopeEvent.X = sensorEvent.vector.x;
gyroEvent.GyroscopeEvent.Y = sensorEvent.vector.y;
gyroEvent.GyroscopeEvent.Z = sensorEvent.vector.z;
postEventFromUser(gyroEvent);
break;
default:
break;
}
}
}
if(!Initialized)
break;
}
return Initialized;
}
void CIrrDeviceAndroid::yield()
{
struct timespec ts = {0,1};
nanosleep(&ts, NULL);
}
void CIrrDeviceAndroid::sleep(u32 timeMs, bool pauseTimer)
{
const bool wasStopped = Timer ? Timer->isStopped() : true;
struct timespec ts;
ts.tv_sec = (time_t) (timeMs / 1000);
ts.tv_nsec = (long) (timeMs % 1000) * 1000000;
if (pauseTimer && !wasStopped)
Timer->stop();
nanosleep(&ts, NULL);
if (pauseTimer && !wasStopped)
Timer->start();
}
void CIrrDeviceAndroid::setWindowCaption(const wchar_t* text)
{
}
bool CIrrDeviceAndroid::isWindowActive() const
{
return (Focused && !Paused);
}
bool CIrrDeviceAndroid::isWindowFocused() const
{
return Focused;
}
bool CIrrDeviceAndroid::isWindowMinimized() const
{
return !Focused;
}
void CIrrDeviceAndroid::closeDevice()
{
ANativeActivity_finish(Android->activity);
}
void CIrrDeviceAndroid::setResizable(bool resize)
{
}
void CIrrDeviceAndroid::minimizeWindow()
{
}
void CIrrDeviceAndroid::maximizeWindow()
{
}
void CIrrDeviceAndroid::restoreWindow()
{
}
core::position2di CIrrDeviceAndroid::getWindowPosition()
{
return core::position2di(0, 0);
}
E_DEVICE_TYPE CIrrDeviceAndroid::getType() const
{
return EIDT_ANDROID;
}
void CIrrDeviceAndroid::handleAndroidCommand(android_app* app, int32_t cmd)
{
CIrrDeviceAndroid* device = (CIrrDeviceAndroid*)app->userData;
SEvent event;
event.EventType = EET_SYSTEM_EVENT;
event.SystemEvent.EventType = ESET_ANDROID_CMD;
event.SystemEvent.AndroidCmd.Cmd = cmd;
if ( device->postEventFromUser(event) )
return;
switch (cmd)
{
case APP_CMD_INPUT_CHANGED:
os::Printer::log("Android command APP_CMD_INPUT_CHANGED", ELL_DEBUG);
break;
case APP_CMD_WINDOW_RESIZED:
os::Printer::log("Android command APP_CMD_WINDOW_RESIZED", ELL_DEBUG);
break;
case APP_CMD_WINDOW_REDRAW_NEEDED:
os::Printer::log("Android command APP_CMD_WINDOW_REDRAW_NEEDED", ELL_DEBUG);
break;
case APP_CMD_SAVE_STATE:
os::Printer::log("Android command APP_CMD_SAVE_STATE", ELL_DEBUG);
break;
case APP_CMD_CONTENT_RECT_CHANGED:
os::Printer::log("Android command APP_CMD_CONTENT_RECT_CHANGED", ELL_DEBUG);
break;
case APP_CMD_CONFIG_CHANGED:
os::Printer::log("Android command APP_CMD_CONFIG_CHANGED", ELL_DEBUG);
break;
case APP_CMD_LOW_MEMORY:
os::Printer::log("Android command APP_CMD_LOW_MEMORY", ELL_DEBUG);
break;
case APP_CMD_START:
os::Printer::log("Android command APP_CMD_START", ELL_DEBUG);
break;
case APP_CMD_INIT_WINDOW:
os::Printer::log("Android command APP_CMD_INIT_WINDOW", ELL_DEBUG);
device->getExposedVideoData().OGLESAndroid.Window = app->window;
if (device->CreationParams.WindowSize.Width == 0 || device->CreationParams.WindowSize.Height == 0)
{
device->CreationParams.WindowSize.Width = ANativeWindow_getWidth(app->window);
device->CreationParams.WindowSize.Height = ANativeWindow_getHeight(app->window);
}
device->getContextManager()->initialize(device->CreationParams, device->ExposedVideoData);
device->getContextManager()->generateSurface();
device->getContextManager()->generateContext();
device->getContextManager()->activateContext(device->getContextManager()->getContext());
if (!device->Initialized)
{
io::CAndroidAssetFileArchive* assets = new io::CAndroidAssetFileArchive( device->Android->activity->assetManager, false, false);
assets->addDirectoryToFileList("");
device->FileSystem->addFileArchive(assets);
assets->drop();
device->createDriver();
if (device->VideoDriver)
device->createGUIAndScene();
}
device->Initialized = true;
break;
case APP_CMD_TERM_WINDOW:
os::Printer::log("Android command APP_CMD_TERM_WINDOW", ELL_DEBUG);
device->getContextManager()->destroySurface();
break;
case APP_CMD_GAINED_FOCUS:
os::Printer::log("Android command APP_CMD_GAINED_FOCUS", ELL_DEBUG);
device->Focused = true;
break;
case APP_CMD_LOST_FOCUS:
os::Printer::log("Android command APP_CMD_LOST_FOCUS", ELL_DEBUG);
device->Focused = false;
break;
case APP_CMD_DESTROY:
os::Printer::log("Android command APP_CMD_DESTROY", ELL_DEBUG);
if ( device->JNIEnvAttachedToVM )
{
device->JNIEnvAttachedToVM = 0;
device->Android->activity->vm->DetachCurrentThread();
}
device->Initialized = false;
break;
case APP_CMD_PAUSE:
os::Printer::log("Android command APP_CMD_PAUSE", ELL_DEBUG);
device->Paused = true;
break;
case APP_CMD_STOP:
os::Printer::log("Android command APP_CMD_STOP", ELL_DEBUG);
break;
case APP_CMD_RESUME:
os::Printer::log("Android command APP_CMD_RESUME", ELL_DEBUG);
device->Paused = false;
break;
default:
break;
}
}
s32 CIrrDeviceAndroid::handleInput(android_app* app, AInputEvent* androidEvent)
{
CIrrDeviceAndroid* device = (CIrrDeviceAndroid*)app->userData;
s32 status = 0;
switch ( AInputEvent_getType(androidEvent) )
{
case AINPUT_EVENT_TYPE_MOTION:
{
SEvent event;
event.EventType = EET_TOUCH_INPUT_EVENT;
s32 eventAction = AMotionEvent_getAction(androidEvent);
s32 eventType = eventAction & AMOTION_EVENT_ACTION_MASK;
#if 0
// Useful for debugging. We might have to pass some of those infos on at some point.
// but preferably device independent (so iphone can use same irrlicht flags).
int32_t flags = AMotionEvent_getFlags(androidEvent);
os::Printer::log("flags: ", core::stringc(flags).c_str(), ELL_DEBUG);
int32_t metaState = AMotionEvent_getMetaState(androidEvent);
os::Printer::log("metaState: ", core::stringc(metaState).c_str(), ELL_DEBUG);
int32_t edgeFlags = AMotionEvent_getEdgeFlags(androidEvent);
os::Printer::log("edgeFlags: ", core::stringc(flags).c_str(), ELL_DEBUG);
#endif
bool touchReceived = true;
switch (eventType)
{
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_POINTER_DOWN:
event.TouchInput.Event = ETIE_PRESSED_DOWN;
break;
case AMOTION_EVENT_ACTION_MOVE:
event.TouchInput.Event = ETIE_MOVED;
break;
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_CANCEL:
event.TouchInput.Event = ETIE_LEFT_UP;
break;
default:
touchReceived = false;
break;
}
if (touchReceived)
{
// Process all touches for move action.
if (event.TouchInput.Event == ETIE_MOVED)
{
s32 pointerCount = AMotionEvent_getPointerCount(androidEvent);
for (s32 i = 0; i < pointerCount; ++i)
{
event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, i);
event.TouchInput.X = AMotionEvent_getX(androidEvent, i);
event.TouchInput.Y = AMotionEvent_getY(androidEvent, i);
event.TouchInput.touchedCount = AMotionEvent_getPointerCount(androidEvent);
device->postEventFromUser(event);
}
}
else // Process one touch for other actions.
{
s32 pointerIndex = (eventAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, pointerIndex);
event.TouchInput.X = AMotionEvent_getX(androidEvent, pointerIndex);
event.TouchInput.Y = AMotionEvent_getY(androidEvent, pointerIndex);
event.TouchInput.touchedCount = AMotionEvent_getPointerCount(androidEvent);
device->postEventFromUser(event);
}
status = 1;
}
}
break;
case AINPUT_EVENT_TYPE_KEY:
{
SEvent event;
event.EventType = EET_KEY_INPUT_EVENT;
int32_t keyCode = AKeyEvent_getKeyCode(androidEvent);
// os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG);
int32_t keyAction = AKeyEvent_getAction(androidEvent);
int32_t keyMetaState = AKeyEvent_getMetaState(androidEvent);
if ( keyCode >= 0 && (u32)keyCode < device->KeyMap.size() )
event.KeyInput.Key = device->KeyMap[keyCode];
else
event.KeyInput.Key = KEY_UNKNOWN;
event.KeyInput.SystemKeyCode = (u32)keyCode;
if ( keyAction == AKEY_EVENT_ACTION_DOWN )
event.KeyInput.PressedDown = true;
else if ( keyAction == AKEY_EVENT_ACTION_UP )
event.KeyInput.PressedDown = false;
else if ( keyAction == AKEY_EVENT_ACTION_MULTIPLE )
{
// TODO: Multiple duplicate key events have occurred in a row,
// or a complex string is being delivered. The repeat_count
// property of the key event contains the number of times the
// given key code should be executed.
// I guess this might necessary for more complicated i18n key input,
// but don't see yet how to handle this correctly.
}
/* no use for meta keys so far.
if ( keyMetaState & AMETA_ALT_ON
|| keyMetaState & AMETA_ALT_LEFT_ON
|| keyMetaState & AMETA_ALT_RIGHT_ON )
;
// what is a sym?
if ( keyMetaState & AMETA_SYM_ON )
;
*/
if ( keyMetaState & AMETA_SHIFT_ON
|| keyMetaState & AMETA_SHIFT_LEFT_ON
|| keyMetaState & AMETA_SHIFT_RIGHT_ON )
event.KeyInput.Shift = true;
else
event.KeyInput.Shift = false;
event.KeyInput.Control = false;
// Having memory allocations + going through JNI for each key-press is pretty bad (slow).
// So we do it only for those keys which are likely text-characters and avoid it for all other keys.
// So it's fast for keys like game controller input and special keys. And text keys are typically
// only used or entering text and not for gaming on Android, so speed likely doesn't matter there too much.
if ( event.KeyInput.Key > 0 )
{
// TODO:
// Not sure why we have to attach a JNIEnv here, but it won't work when doing that in the constructor or
// trying to use the activity->env. My best guess is that the event-handling happens in an own thread.
// It means JNIEnvAttachedToVM will never get detached as I don't know a safe way where to do that
// (we could attach & detach each time, but that would probably be slow)
// Also - it has to be each time as it get's invalid when the application mode changes.
if ( device->Initialized && device->Android && device->Android->activity && device->Android->activity->vm )
{
JavaVMAttachArgs attachArgs;
attachArgs.version = JNI_VERSION_1_6;
attachArgs.name = 0;
attachArgs.group = NULL;
// Not a big problem calling it each time - it's a no-op when the thread already is attached.
// And we have to do that as someone else can have detached the thread in the meantime.
jint result = device->Android->activity->vm->AttachCurrentThread(&device->JNIEnvAttachedToVM, &attachArgs);
if(result == JNI_ERR)
{
os::Printer::log("AttachCurrentThread for the JNI environment failed.", ELL_WARNING);
device->JNIEnvAttachedToVM = 0;
}
if ( device->JNIEnvAttachedToVM )
{
jni::CKeyEventWrapper * keyEventWrapper = new jni::CKeyEventWrapper(device->JNIEnvAttachedToVM, keyAction, keyCode);
event.KeyInput.Char = keyEventWrapper->getUnicodeChar(keyMetaState);
delete keyEventWrapper;
}
}
if ( event.KeyInput.Key == KEY_BACK )
{
event.KeyInput.Char = 0x08; // same key-code as on other operating systems. Otherwise we have to handle too much system specific stuff in the editbox.
}
//os::Printer::log("char-code: ", core::stringc((int)event.KeyInput.Char).c_str(), ELL_DEBUG);
}
else
{
// os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG);
event.KeyInput.Char = 0;
}
status = device->postEventFromUser(event);
}
break;
default:
break;
}
return status;
}
void CIrrDeviceAndroid::createDriver()
{
switch(CreationParams.DriverType)
{
case video::EDT_OGLES1:
#ifdef _IRR_COMPILE_WITH_OGLES1_
VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager);
#else
os::Printer::log("No OpenGL ES 1.0 support compiled in.", ELL_ERROR);
#endif
break;
case video::EDT_OGLES2:
#ifdef _IRR_COMPILE_WITH_OGLES2_
VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);
#else
os::Printer::log("No OpenGL ES 2.0 support compiled in.", ELL_ERROR);
#endif
break;
case video::EDT_NULL:
VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
break;
case video::EDT_OPENGL:
os::Printer::log("This driver is not available in Android. Try OpenGL ES 1.0 or ES 2.0.", ELL_ERROR);
break;
default:
os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
break;
}
}
video::SExposedVideoData& CIrrDeviceAndroid::getExposedVideoData()
{
return ExposedVideoData;
}
void CIrrDeviceAndroid::createKeyMap()
{
KeyMap.set_used(223);
KeyMap[0] = KEY_UNKNOWN; // AKEYCODE_UNKNOWN
KeyMap[1] = KEY_LBUTTON; // AKEYCODE_SOFT_LEFT
KeyMap[2] = KEY_RBUTTON; // AKEYCODE_SOFT_RIGHT
KeyMap[3] = KEY_HOME; // AKEYCODE_HOME
KeyMap[4] = KEY_CANCEL; // AKEYCODE_BACK
KeyMap[5] = KEY_UNKNOWN; // AKEYCODE_CALL
KeyMap[6] = KEY_UNKNOWN; // AKEYCODE_ENDCALL
KeyMap[7] = KEY_KEY_0; // AKEYCODE_0
KeyMap[8] = KEY_KEY_1; // AKEYCODE_1
KeyMap[9] = KEY_KEY_2; // AKEYCODE_2
KeyMap[10] = KEY_KEY_3; // AKEYCODE_3
KeyMap[11] = KEY_KEY_4; // AKEYCODE_4
KeyMap[12] = KEY_KEY_5; // AKEYCODE_5
KeyMap[13] = KEY_KEY_6; // AKEYCODE_6
KeyMap[14] = KEY_KEY_7; // AKEYCODE_7
KeyMap[15] = KEY_KEY_8; // AKEYCODE_8
KeyMap[16] = KEY_KEY_9; // AKEYCODE_9
KeyMap[17] = KEY_UNKNOWN; // AKEYCODE_STAR
KeyMap[18] = KEY_UNKNOWN; // AKEYCODE_POUND
KeyMap[19] = KEY_UP; // AKEYCODE_DPAD_UP
KeyMap[20] = KEY_DOWN; // AKEYCODE_DPAD_DOWN
KeyMap[21] = KEY_LEFT; // AKEYCODE_DPAD_LEFT
KeyMap[22] = KEY_RIGHT; // AKEYCODE_DPAD_RIGHT
KeyMap[23] = KEY_SELECT; // AKEYCODE_DPAD_CENTER
KeyMap[24] = KEY_VOLUME_DOWN; // AKEYCODE_VOLUME_UP
KeyMap[25] = KEY_VOLUME_UP; // AKEYCODE_VOLUME_DOWN
KeyMap[26] = KEY_UNKNOWN; // AKEYCODE_POWER
KeyMap[27] = KEY_UNKNOWN; // AKEYCODE_CAMERA
KeyMap[28] = KEY_CLEAR; // AKEYCODE_CLEAR
KeyMap[29] = KEY_KEY_A; // AKEYCODE_A
KeyMap[30] = KEY_KEY_B; // AKEYCODE_B
KeyMap[31] = KEY_KEY_C; // AKEYCODE_C
KeyMap[32] = KEY_KEY_D; // AKEYCODE_D
KeyMap[33] = KEY_KEY_E; // AKEYCODE_E
KeyMap[34] = KEY_KEY_F; // AKEYCODE_F
KeyMap[35] = KEY_KEY_G; // AKEYCODE_G
KeyMap[36] = KEY_KEY_H; // AKEYCODE_H
KeyMap[37] = KEY_KEY_I; // AKEYCODE_I
KeyMap[38] = KEY_KEY_J; // AKEYCODE_J
KeyMap[39] = KEY_KEY_K; // AKEYCODE_K
KeyMap[40] = KEY_KEY_L; // AKEYCODE_L
KeyMap[41] = KEY_KEY_M; // AKEYCODE_M
KeyMap[42] = KEY_KEY_N; // AKEYCODE_N
KeyMap[43] = KEY_KEY_O; // AKEYCODE_O
KeyMap[44] = KEY_KEY_P; // AKEYCODE_P
KeyMap[45] = KEY_KEY_Q; // AKEYCODE_Q
KeyMap[46] = KEY_KEY_R; // AKEYCODE_R
KeyMap[47] = KEY_KEY_S; // AKEYCODE_S
KeyMap[48] = KEY_KEY_T; // AKEYCODE_T
KeyMap[49] = KEY_KEY_U; // AKEYCODE_U
KeyMap[50] = KEY_KEY_V; // AKEYCODE_V
KeyMap[51] = KEY_KEY_W; // AKEYCODE_W
KeyMap[52] = KEY_KEY_X; // AKEYCODE_X
KeyMap[53] = KEY_KEY_Y; // AKEYCODE_Y
KeyMap[54] = KEY_KEY_Z; // AKEYCODE_Z
KeyMap[55] = KEY_COMMA; // AKEYCODE_COMMA
KeyMap[56] = KEY_PERIOD; // AKEYCODE_PERIOD
KeyMap[57] = KEY_MENU; // AKEYCODE_ALT_LEFT
KeyMap[58] = KEY_MENU; // AKEYCODE_ALT_RIGHT
KeyMap[59] = KEY_LSHIFT; // AKEYCODE_SHIFT_LEFT
KeyMap[60] = KEY_RSHIFT; // AKEYCODE_SHIFT_RIGHT
KeyMap[61] = KEY_TAB; // AKEYCODE_TAB
KeyMap[62] = KEY_SPACE; // AKEYCODE_SPACE
KeyMap[63] = KEY_UNKNOWN; // AKEYCODE_SYM
KeyMap[64] = KEY_UNKNOWN; // AKEYCODE_EXPLORER
KeyMap[65] = KEY_UNKNOWN; // AKEYCODE_ENVELOPE
KeyMap[66] = KEY_RETURN; // AKEYCODE_ENTER
KeyMap[67] = KEY_BACK; // AKEYCODE_DEL
KeyMap[68] = KEY_OEM_3; // AKEYCODE_GRAVE
KeyMap[69] = KEY_MINUS; // AKEYCODE_MINUS
KeyMap[70] = KEY_UNKNOWN; // AKEYCODE_EQUALS
KeyMap[71] = KEY_UNKNOWN; // AKEYCODE_LEFT_BRACKET
KeyMap[72] = KEY_UNKNOWN; // AKEYCODE_RIGHT_BRACKET
KeyMap[73] = KEY_UNKNOWN; // AKEYCODE_BACKSLASH
KeyMap[74] = KEY_UNKNOWN; // AKEYCODE_SEMICOLON
KeyMap[75] = KEY_UNKNOWN; // AKEYCODE_APOSTROPHE
KeyMap[76] = KEY_UNKNOWN; // AKEYCODE_SLASH
KeyMap[77] = KEY_UNKNOWN; // AKEYCODE_AT
KeyMap[78] = KEY_UNKNOWN; // AKEYCODE_NUM
KeyMap[79] = KEY_UNKNOWN; // AKEYCODE_HEADSETHOOK
KeyMap[80] = KEY_UNKNOWN; // AKEYCODE_FOCUS (*Camera* focus)
KeyMap[81] = KEY_PLUS; // AKEYCODE_PLUS
KeyMap[82] = KEY_MENU; // AKEYCODE_MENU
KeyMap[83] = KEY_UNKNOWN; // AKEYCODE_NOTIFICATION
KeyMap[84] = KEY_UNKNOWN; // AKEYCODE_SEARCH
KeyMap[85] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PLAY_PAUSE
KeyMap[86] = KEY_MEDIA_STOP; // AKEYCODE_MEDIA_STOP
KeyMap[87] = KEY_MEDIA_NEXT_TRACK; // AKEYCODE_MEDIA_NEXT
KeyMap[88] = KEY_MEDIA_PREV_TRACK; // AKEYCODE_MEDIA_PREVIOUS
KeyMap[89] = KEY_UNKNOWN; // AKEYCODE_MEDIA_REWIND
KeyMap[90] = KEY_UNKNOWN; // AKEYCODE_MEDIA_FAST_FORWARD
KeyMap[91] = KEY_VOLUME_MUTE; // AKEYCODE_MUTE
KeyMap[92] = KEY_PRIOR; // AKEYCODE_PAGE_UP
KeyMap[93] = KEY_NEXT; // AKEYCODE_PAGE_DOWN
KeyMap[94] = KEY_UNKNOWN; // AKEYCODE_PICTSYMBOLS
KeyMap[95] = KEY_UNKNOWN; // AKEYCODE_SWITCH_CHARSET
// following look like controller inputs
KeyMap[96] = KEY_UNKNOWN; // AKEYCODE_BUTTON_A
KeyMap[97] = KEY_UNKNOWN; // AKEYCODE_BUTTON_B
KeyMap[98] = KEY_UNKNOWN; // AKEYCODE_BUTTON_C
KeyMap[99] = KEY_UNKNOWN; // AKEYCODE_BUTTON_X
KeyMap[100] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Y
KeyMap[101] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Z
KeyMap[102] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L1
KeyMap[103] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R1
KeyMap[104] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L2
KeyMap[105] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R2
KeyMap[106] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBL
KeyMap[107] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBR
KeyMap[108] = KEY_UNKNOWN; // AKEYCODE_BUTTON_START
KeyMap[109] = KEY_UNKNOWN; // AKEYCODE_BUTTON_SELECT
KeyMap[110] = KEY_UNKNOWN; // AKEYCODE_BUTTON_MODE
KeyMap[111] = KEY_ESCAPE; // AKEYCODE_ESCAPE
KeyMap[112] = KEY_DELETE; // AKEYCODE_FORWARD_DEL
KeyMap[113] = KEY_CONTROL; // AKEYCODE_CTRL_LEFT
KeyMap[114] = KEY_CONTROL; // AKEYCODE_CTRL_RIGHT
KeyMap[115] = KEY_CAPITAL; // AKEYCODE_CAPS_LOCK
KeyMap[116] = KEY_SCROLL; // AKEYCODE_SCROLL_LOCK
KeyMap[117] = KEY_UNKNOWN; // AKEYCODE_META_LEFT
KeyMap[118] = KEY_UNKNOWN; // AKEYCODE_META_RIGHT
KeyMap[119] = KEY_UNKNOWN; // AKEYCODE_FUNCTION
KeyMap[120] = KEY_SNAPSHOT; // AKEYCODE_SYSRQ
KeyMap[121] = KEY_PAUSE; // AKEYCODE_BREAK
KeyMap[122] = KEY_HOME; // AKEYCODE_MOVE_HOME
KeyMap[123] = KEY_END; // AKEYCODE_MOVE_END
KeyMap[124] = KEY_INSERT; // AKEYCODE_INSERT
KeyMap[125] = KEY_UNKNOWN; // AKEYCODE_FORWARD
KeyMap[126] = KEY_PLAY; // AKEYCODE_MEDIA_PLAY
KeyMap[127] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PAUSE
KeyMap[128] = KEY_UNKNOWN; // AKEYCODE_MEDIA_CLOSE
KeyMap[129] = KEY_UNKNOWN; // AKEYCODE_MEDIA_EJECT
KeyMap[130] = KEY_UNKNOWN; // AKEYCODE_MEDIA_RECORD
KeyMap[131] = KEY_F1; // AKEYCODE_F1
KeyMap[132] = KEY_F2; // AKEYCODE_F2
KeyMap[133] = KEY_F3; // AKEYCODE_F3
KeyMap[134] = KEY_F4; // AKEYCODE_F4
KeyMap[135] = KEY_F5; // AKEYCODE_F5
KeyMap[136] = KEY_F6; // AKEYCODE_F6
KeyMap[137] = KEY_F7; // AKEYCODE_F7
KeyMap[138] = KEY_F8; // AKEYCODE_F8
KeyMap[139] = KEY_F9; // AKEYCODE_F9
KeyMap[140] = KEY_F10; // AKEYCODE_F10
KeyMap[141] = KEY_F11; // AKEYCODE_F11
KeyMap[142] = KEY_F12; // AKEYCODE_F12
KeyMap[143] = KEY_NUMLOCK; // AKEYCODE_NUM_LOCK
KeyMap[144] = KEY_NUMPAD0; // AKEYCODE_NUMPAD_0
KeyMap[145] = KEY_NUMPAD1; // AKEYCODE_NUMPAD_1
KeyMap[146] = KEY_NUMPAD2; // AKEYCODE_NUMPAD_2
KeyMap[147] = KEY_NUMPAD3; // AKEYCODE_NUMPAD_3
KeyMap[148] = KEY_NUMPAD4; // AKEYCODE_NUMPAD_4
KeyMap[149] = KEY_NUMPAD5; // AKEYCODE_NUMPAD_5
KeyMap[150] = KEY_NUMPAD6; // AKEYCODE_NUMPAD_6
KeyMap[151] = KEY_NUMPAD7; // AKEYCODE_NUMPAD_7
KeyMap[152] = KEY_NUMPAD8; // AKEYCODE_NUMPAD_8
KeyMap[153] = KEY_NUMPAD9; // AKEYCODE_NUMPAD_9
KeyMap[154] = KEY_DIVIDE; // AKEYCODE_NUMPAD_DIVIDE
KeyMap[155] = KEY_MULTIPLY; // AKEYCODE_NUMPAD_MULTIPLY
KeyMap[156] = KEY_SUBTRACT; // AKEYCODE_NUMPAD_SUBTRACT
KeyMap[157] = KEY_ADD; // AKEYCODE_NUMPAD_ADD
KeyMap[158] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_DOT
KeyMap[159] = KEY_COMMA; // AKEYCODE_NUMPAD_COMMA
KeyMap[160] = KEY_RETURN; // AKEYCODE_NUMPAD_ENTER
KeyMap[161] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_EQUALS
KeyMap[162] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_LEFT_PAREN
KeyMap[163] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_RIGHT_PAREN
KeyMap[164] = KEY_VOLUME_MUTE; // AKEYCODE_VOLUME_MUTE
KeyMap[165] = KEY_UNKNOWN; // AKEYCODE_INFO
KeyMap[166] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_UP
KeyMap[167] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_DOWN
KeyMap[168] = KEY_ZOOM; // AKEYCODE_ZOOM_IN
KeyMap[169] = KEY_UNKNOWN; // AKEYCODE_ZOOM_OUT
KeyMap[170] = KEY_UNKNOWN; // AKEYCODE_TV
KeyMap[171] = KEY_UNKNOWN; // AKEYCODE_WINDOW
KeyMap[172] = KEY_UNKNOWN; // AKEYCODE_GUIDE
KeyMap[173] = KEY_UNKNOWN; // AKEYCODE_DVR
KeyMap[174] = KEY_UNKNOWN; // AKEYCODE_BOOKMARK
KeyMap[175] = KEY_UNKNOWN; // AKEYCODE_CAPTIONS
KeyMap[176] = KEY_UNKNOWN; // AKEYCODE_SETTINGS
KeyMap[177] = KEY_UNKNOWN; // AKEYCODE_TV_POWER
KeyMap[178] = KEY_UNKNOWN; // AKEYCODE_TV_INPUT
KeyMap[179] = KEY_UNKNOWN; // AKEYCODE_STB_POWER
KeyMap[180] = KEY_UNKNOWN; // AKEYCODE_STB_INPUT
KeyMap[181] = KEY_UNKNOWN; // AKEYCODE_AVR_POWER
KeyMap[182] = KEY_UNKNOWN; // AKEYCODE_AVR_INPUT
KeyMap[183] = KEY_UNKNOWN; // AKEYCODE_PROG_RED
KeyMap[184] = KEY_UNKNOWN; // AKEYCODE_PROG_GREEN
KeyMap[185] = KEY_UNKNOWN; // AKEYCODE_PROG_YELLOW
KeyMap[186] = KEY_UNKNOWN; // AKEYCODE_PROG_BLUE
KeyMap[187] = KEY_UNKNOWN; // AKEYCODE_APP_SWITCH
KeyMap[188] = KEY_UNKNOWN; // AKEYCODE_BUTTON_1
KeyMap[189] = KEY_UNKNOWN; // AKEYCODE_BUTTON_2
KeyMap[190] = KEY_UNKNOWN; // AKEYCODE_BUTTON_3
KeyMap[191] = KEY_UNKNOWN; // AKEYCODE_BUTTON_4
KeyMap[192] = KEY_UNKNOWN; // AKEYCODE_BUTTON_5
KeyMap[193] = KEY_UNKNOWN; // AKEYCODE_BUTTON_6
KeyMap[194] = KEY_UNKNOWN; // AKEYCODE_BUTTON_7
KeyMap[195] = KEY_UNKNOWN; // AKEYCODE_BUTTON_8
KeyMap[196] = KEY_UNKNOWN; // AKEYCODE_BUTTON_9
KeyMap[197] = KEY_UNKNOWN; // AKEYCODE_BUTTON_10
KeyMap[198] = KEY_UNKNOWN; // AKEYCODE_BUTTON_11
KeyMap[199] = KEY_UNKNOWN; // AKEYCODE_BUTTON_12
KeyMap[200] = KEY_UNKNOWN; // AKEYCODE_BUTTON_13
KeyMap[201] = KEY_UNKNOWN; // AKEYCODE_BUTTON_14
KeyMap[202] = KEY_UNKNOWN; // AKEYCODE_BUTTON_15
KeyMap[203] = KEY_UNKNOWN; // AKEYCODE_BUTTON_16
KeyMap[204] = KEY_UNKNOWN; // AKEYCODE_LANGUAGE_SWITCH
KeyMap[205] = KEY_UNKNOWN; // AKEYCODE_MANNER_MODE
KeyMap[206] = KEY_UNKNOWN; // AKEYCODE_3D_MODE
KeyMap[207] = KEY_UNKNOWN; // AKEYCODE_CONTACTS
KeyMap[208] = KEY_UNKNOWN; // AKEYCODE_CALENDAR
KeyMap[209] = KEY_UNKNOWN; // AKEYCODE_MUSIC
KeyMap[210] = KEY_UNKNOWN; // AKEYCODE_CALCULATOR
KeyMap[211] = KEY_UNKNOWN; // AKEYCODE_ZENKAKU_HANKAKU
KeyMap[212] = KEY_UNKNOWN; // AKEYCODE_EISU
KeyMap[213] = KEY_UNKNOWN; // AKEYCODE_MUHENKAN
KeyMap[214] = KEY_UNKNOWN; // AKEYCODE_HENKAN
KeyMap[215] = KEY_UNKNOWN; // AKEYCODE_KATAKANA_HIRAGANA
KeyMap[216] = KEY_UNKNOWN; // AKEYCODE_YEN
KeyMap[217] = KEY_UNKNOWN; // AKEYCODE_RO
KeyMap[218] = KEY_UNKNOWN; // AKEYCODE_KANA
KeyMap[219] = KEY_UNKNOWN; // AKEYCODE_ASSIST
KeyMap[220] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_DOWN
KeyMap[221] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_UP ,
KeyMap[222] = KEY_UNKNOWN; // AKEYCODE_MEDIA_AUDIO_TRACK
}
bool CIrrDeviceAndroid::activateAccelerometer(float updateInterval)
{
if (!isAccelerometerAvailable())
return false;
ASensorEventQueue_enableSensor(SensorEventQueue, Accelerometer);
ASensorEventQueue_setEventRate(SensorEventQueue, Accelerometer, (int32_t)(updateInterval*1000.f*1000.f)); // in microseconds
os::Printer::log("Activated accelerometer", ELL_DEBUG);
return true;
}
bool CIrrDeviceAndroid::deactivateAccelerometer()
{
if (Accelerometer)
{
ASensorEventQueue_disableSensor(SensorEventQueue, Accelerometer);
Accelerometer = 0;
os::Printer::log("Deactivated accelerometer", ELL_DEBUG);
return true;
}
return false;
}
bool CIrrDeviceAndroid::isAccelerometerActive()
{
return (Accelerometer != 0);
}
bool CIrrDeviceAndroid::isAccelerometerAvailable()
{
if (!Accelerometer)
Accelerometer = ASensorManager_getDefaultSensor(SensorManager, ASENSOR_TYPE_ACCELEROMETER);
return (Accelerometer != 0);
}
bool CIrrDeviceAndroid::activateGyroscope(float updateInterval)
{
if (!isGyroscopeAvailable())
return false;
ASensorEventQueue_enableSensor(SensorEventQueue, Gyroscope);
ASensorEventQueue_setEventRate(SensorEventQueue, Gyroscope, (int32_t)(updateInterval*1000.f*1000.f)); // in microseconds
os::Printer::log("Activated gyroscope", ELL_DEBUG);
return true;
}
bool CIrrDeviceAndroid::deactivateGyroscope()
{
if (Gyroscope)
{
ASensorEventQueue_disableSensor(SensorEventQueue, Gyroscope);
Gyroscope = 0;
os::Printer::log("Deactivated gyroscope", ELL_DEBUG);
return true;
}
return false;
}
bool CIrrDeviceAndroid::isGyroscopeActive()
{
return (Gyroscope != 0);
}
bool CIrrDeviceAndroid::isGyroscopeAvailable()
{
if (!Gyroscope)
Gyroscope = ASensorManager_getDefaultSensor(SensorManager, ASENSOR_TYPE_GYROSCOPE);
return (Gyroscope != 0);
}
} // end namespace irr