mirror of
https://github.com/minetest/minetest.git
synced 2025-03-06 20:48:40 +01:00
Migrate the Android port to SDL2
This commit is contained in:
parent
fca60e2a41
commit
07fdf7158d
30 changed files with 217 additions and 1538 deletions
18
android/SDL_Java_RMB_fix.patch
Normal file
18
android/SDL_Java_RMB_fix.patch
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
diff --git a/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||||
|
index fd5a056e3..83e3cf657 100644
|
||||||
|
--- a/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||||
|
+++ b/android/app/src/main/java/org/libsdl/app/SDLActivity.java
|
||||||
|
@@ -1345,7 +1345,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
|
||||||
|
+ if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
|
||||||
|
+ /*
|
||||||
|
+ * CUSTOM ADDITION FOR MINETEST
|
||||||
|
+ * should be upstreamed
|
||||||
|
+ */
|
||||||
|
+ (source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {
|
||||||
|
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
|
||||||
|
// they are ignored here because sending them as mouse input to SDL is messy
|
||||||
|
if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
|
|
@ -20,7 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
package net.minetest.minetest;
|
package net.minetest.minetest;
|
||||||
|
|
||||||
import android.app.NativeActivity;
|
import org.libsdl.app.SDLActivity;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -32,6 +33,7 @@ import android.view.WindowManager;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
|
||||||
import androidx.annotation.Keep;
|
import androidx.annotation.Keep;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
@ -45,12 +47,29 @@ import java.util.Objects;
|
||||||
// This annotation prevents the minifier/Proguard from mangling them.
|
// This annotation prevents the minifier/Proguard from mangling them.
|
||||||
@Keep
|
@Keep
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class GameActivity extends NativeActivity {
|
public class GameActivity extends SDLActivity {
|
||||||
static {
|
@Override
|
||||||
System.loadLibrary("c++_shared");
|
protected String getMainSharedObject() {
|
||||||
System.loadLibrary("minetest");
|
return getContext().getApplicationInfo().nativeLibraryDir + "/libminetest.so";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getMainFunction() {
|
||||||
|
return "SDL_Main";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] getLibraries() {
|
||||||
|
return new String[] {
|
||||||
|
"minetest"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent SDL from changing orientation settings since we already set the
|
||||||
|
// correct orientation in our AndroidManifest.xml
|
||||||
|
@Override
|
||||||
|
public void setOrientationBis(int w, int h, boolean resizable, String hint) {}
|
||||||
|
|
||||||
enum DialogType { TEXT_INPUT, SELECTION_INPUT }
|
enum DialogType { TEXT_INPUT, SELECTION_INPUT }
|
||||||
enum DialogState { DIALOG_SHOWN, DIALOG_INPUTTED, DIALOG_CANCELED }
|
enum DialogState { DIALOG_SHOWN, DIALOG_INPUTTED, DIALOG_CANCELED }
|
||||||
|
|
||||||
|
@ -59,32 +78,6 @@ public class GameActivity extends NativeActivity {
|
||||||
private String messageReturnValue = "";
|
private String messageReturnValue = "";
|
||||||
private int selectionReturnValue = 0;
|
private int selectionReturnValue = 0;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void makeFullScreen() {
|
|
||||||
this.getWindow().getDecorView().setSystemUiVisibility(
|
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
|
|
||||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
|
|
||||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onWindowFocusChanged(boolean hasFocus) {
|
|
||||||
super.onWindowFocusChanged(hasFocus);
|
|
||||||
if (hasFocus)
|
|
||||||
makeFullScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onResume() {
|
|
||||||
super.onResume();
|
|
||||||
makeFullScreen();
|
|
||||||
}
|
|
||||||
|
|
||||||
private native void saveSettings();
|
private native void saveSettings();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -96,11 +89,6 @@ public class GameActivity extends NativeActivity {
|
||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBackPressed() {
|
|
||||||
// Ignore the back press so Minetest can handle it
|
|
||||||
}
|
|
||||||
|
|
||||||
public void showTextInputDialog(String hint, String current, int editType) {
|
public void showTextInputDialog(String hint, String current, int editType) {
|
||||||
runOnUiThread(() -> showTextInputDialogUI(hint, current, editType));
|
runOnUiThread(() -> showTextInputDialogUI(hint, current, editType));
|
||||||
}
|
}
|
||||||
|
@ -265,4 +253,8 @@ public class GameActivity extends NativeActivity {
|
||||||
|
|
||||||
return langCode;
|
return langCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasPhysicalKeyboard() {
|
||||||
|
return getContext().getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1345,7 +1345,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) {
|
if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE ||
|
||||||
|
/*
|
||||||
|
* CUSTOM ADDITION FOR MINETEST
|
||||||
|
* should be upstreamed
|
||||||
|
*/
|
||||||
|
(source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) {
|
||||||
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
|
// on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
|
||||||
// they are ignored here because sending them as mouse input to SDL is messy
|
// they are ignored here because sending them as mouse input to SDL is messy
|
||||||
if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
|
if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
|
||||||
|
|
|
@ -153,8 +153,6 @@ invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false
|
||||||
[*Touchscreen]
|
[*Touchscreen]
|
||||||
|
|
||||||
# Enables touchscreen mode, allowing you to play the game with a touchscreen.
|
# Enables touchscreen mode, allowing you to play the game with a touchscreen.
|
||||||
#
|
|
||||||
# Requires: !android
|
|
||||||
enable_touch (Enable touchscreen) bool true
|
enable_touch (Enable touchscreen) bool true
|
||||||
|
|
||||||
# Touchscreen sensitivity multiplier.
|
# Touchscreen sensitivity multiplier.
|
||||||
|
|
|
@ -25,3 +25,5 @@ set(VORBIS_LIBRARY ${DEPS}/Vorbis/libvorbis.a)
|
||||||
set(VORBISFILE_LIBRARY ${DEPS}/Vorbis/libvorbisfile.a)
|
set(VORBISFILE_LIBRARY ${DEPS}/Vorbis/libvorbisfile.a)
|
||||||
set(ZSTD_INCLUDE_DIR ${DEPS}/Zstd/include)
|
set(ZSTD_INCLUDE_DIR ${DEPS}/Zstd/include)
|
||||||
set(ZSTD_LIBRARY ${DEPS}/Zstd/libzstd.a)
|
set(ZSTD_LIBRARY ${DEPS}/Zstd/libzstd.a)
|
||||||
|
set(SDL2_INCLUDE_DIRS ${DEPS}/SDL2/include/SDL2)
|
||||||
|
set(SDL2_LIBRARIES ${DEPS}/SDL2/libSDL2.a)
|
||||||
|
|
|
@ -79,9 +79,6 @@ enum EEVENT_TYPE
|
||||||
*/
|
*/
|
||||||
EET_USER_EVENT,
|
EET_USER_EVENT,
|
||||||
|
|
||||||
//! Pass on raw events from the OS
|
|
||||||
EET_SYSTEM_EVENT,
|
|
||||||
|
|
||||||
//! Application state events like a resume, pause etc.
|
//! Application state events like a resume, pause etc.
|
||||||
EET_APPLICATION_EVENT,
|
EET_APPLICATION_EVENT,
|
||||||
|
|
||||||
|
@ -187,17 +184,6 @@ enum ETOUCH_INPUT_EVENT
|
||||||
ETIE_COUNT
|
ETIE_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ESYSTEM_EVENT_TYPE
|
|
||||||
{
|
|
||||||
//! From Android command handler for native activity messages
|
|
||||||
ESET_ANDROID_CMD = 0,
|
|
||||||
|
|
||||||
// TODO: for example ESET_WINDOWS_MESSAGE for win32 message loop events
|
|
||||||
|
|
||||||
//! No real event, but to get number of event types
|
|
||||||
ESET_COUNT
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Enumeration for a commonly used application state events (it's useful mainly for mobile devices)
|
//! Enumeration for a commonly used application state events (it's useful mainly for mobile devices)
|
||||||
enum EAPPLICATION_EVENT_TYPE
|
enum EAPPLICATION_EVENT_TYPE
|
||||||
{
|
{
|
||||||
|
@ -528,25 +514,6 @@ struct SEvent
|
||||||
size_t UserData2;
|
size_t UserData2;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Raw events from the OS
|
|
||||||
struct SSystemEvent
|
|
||||||
{
|
|
||||||
//! Android command handler native activity messages.
|
|
||||||
struct SAndroidCmd
|
|
||||||
{
|
|
||||||
//! APP_CMD_ enums defined in android_native_app_glue.h from the Android NDK
|
|
||||||
s32 Cmd;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TOOD: more structs for iphone, Windows, X11, etc.
|
|
||||||
|
|
||||||
ESYSTEM_EVENT_TYPE EventType;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct SAndroidCmd AndroidCmd;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Application state event
|
// Application state event
|
||||||
struct SApplicationEvent
|
struct SApplicationEvent
|
||||||
{
|
{
|
||||||
|
@ -567,7 +534,6 @@ struct SEvent
|
||||||
struct SJoystickEvent JoystickEvent;
|
struct SJoystickEvent JoystickEvent;
|
||||||
struct SLogEvent LogEvent;
|
struct SLogEvent LogEvent;
|
||||||
struct SUserEvent UserEvent;
|
struct SUserEvent UserEvent;
|
||||||
struct SSystemEvent SystemEvent;
|
|
||||||
struct SApplicationEvent ApplicationEvent;
|
struct SApplicationEvent ApplicationEvent;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -180,10 +180,7 @@ public:
|
||||||
virtual bool isFullscreen() const = 0;
|
virtual bool isFullscreen() const = 0;
|
||||||
|
|
||||||
//! Checks if the window could possibly be visible.
|
//! Checks if the window could possibly be visible.
|
||||||
//! Currently, this only returns false when the activity is stopped on
|
/** If this returns false, you should not do any rendering. */
|
||||||
//! Android. Note that for Android activities, "stopped" means something
|
|
||||||
//! different than you might expect (and also something different than
|
|
||||||
//! "paused"). Read the Android lifecycle documentation.
|
|
||||||
virtual bool isWindowVisible() const { return true; };
|
virtual bool isWindowVisible() const { return true; };
|
||||||
|
|
||||||
//! Get the current color format of the window
|
//! Get the current color format of the window
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
// Copyright (C) 2002-2011 Nikolaus Gebhardt
|
|
||||||
// This file is part of the "Irrlicht Engine".
|
|
||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
||||||
|
|
||||||
#include "CAndroidAssetReader.h"
|
|
||||||
|
|
||||||
#include "CReadFile.h"
|
|
||||||
#include "coreutil.h"
|
|
||||||
#include "CAndroidAssetFileArchive.h"
|
|
||||||
#include "CIrrDeviceAndroid.h"
|
|
||||||
#include "os.h" // for logging (just keep it in even when not needed right now as it's used all the time)
|
|
||||||
|
|
||||||
#include <android_native_app_glue.h>
|
|
||||||
#include <android/native_activity.h>
|
|
||||||
#include <android/log.h>
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
namespace io
|
|
||||||
{
|
|
||||||
|
|
||||||
CAndroidAssetFileArchive::CAndroidAssetFileArchive(AAssetManager *assetManager, bool ignoreCase, bool ignorePaths) :
|
|
||||||
CFileList("/asset", ignoreCase, ignorePaths), AssetManager(assetManager)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
CAndroidAssetFileArchive::~CAndroidAssetFileArchive()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//! get the archive type
|
|
||||||
E_FILE_ARCHIVE_TYPE CAndroidAssetFileArchive::getType() const
|
|
||||||
{
|
|
||||||
return EFAT_ANDROID_ASSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
const IFileList *CAndroidAssetFileArchive::getFileList() const
|
|
||||||
{
|
|
||||||
// The assert_manager can not read directory names, so
|
|
||||||
// getFileList returns only files in folders which have been added.
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! opens a file by file name
|
|
||||||
IReadFile *CAndroidAssetFileArchive::createAndOpenFile(const io::path &filename)
|
|
||||||
{
|
|
||||||
CAndroidAssetReader *reader = new CAndroidAssetReader(AssetManager, filename);
|
|
||||||
|
|
||||||
if (reader->isOpen())
|
|
||||||
return reader;
|
|
||||||
|
|
||||||
reader->drop();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! opens a file by index
|
|
||||||
IReadFile *CAndroidAssetFileArchive::createAndOpenFile(u32 index)
|
|
||||||
{
|
|
||||||
const io::path &filename(getFullFileName(index));
|
|
||||||
if (filename.empty())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return createAndOpenFile(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CAndroidAssetFileArchive::addDirectoryToFileList(const io::path &dirname_)
|
|
||||||
{
|
|
||||||
io::path dirname(dirname_);
|
|
||||||
fschar_t lastChar = dirname.lastChar();
|
|
||||||
if (lastChar == '/' || lastChar == '\\')
|
|
||||||
dirname.erase(dirname.size() - 1);
|
|
||||||
|
|
||||||
// os::Printer::log("addDirectoryToFileList:", dirname.c_str(), ELL_DEBUG);
|
|
||||||
if (findFile(dirname, true) >= 0)
|
|
||||||
return; // was already added
|
|
||||||
|
|
||||||
AAssetDir *dir = AAssetManager_openDir(AssetManager, core::stringc(dirname).c_str());
|
|
||||||
if (!dir)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// add directory itself
|
|
||||||
addItem(dirname, 0, 0, /*isDir*/ true, getFileCount());
|
|
||||||
|
|
||||||
// add all files in folder.
|
|
||||||
// Note: AAssetDir_getNextFileName does not return directory names (neither does any other NDK function)
|
|
||||||
while (const char *filename = AAssetDir_getNextFileName(dir)) {
|
|
||||||
core::stringc full_filename = dirname == "" ? filename
|
|
||||||
: dirname + "/" + filename;
|
|
||||||
|
|
||||||
// We can't get the size without opening the file - so for performance
|
|
||||||
// reasons we set the file size to 0.
|
|
||||||
// TODO: Does this really cost so much performance that it's worth losing this information? Dirs are usually just added once at startup...
|
|
||||||
addItem(full_filename, /*offet*/ 0, /*size*/ 0, /*isDir*/ false, getFileCount());
|
|
||||||
// os::Printer::log("addItem:", full_filename.c_str(), ELL_DEBUG);
|
|
||||||
}
|
|
||||||
AAssetDir_close(dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace io
|
|
||||||
} // end namespace irr
|
|
|
@ -1,58 +0,0 @@
|
||||||
// Copyright (C) 2012 Joerg Henrichs
|
|
||||||
// This file is part of the "Irrlicht Engine".
|
|
||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IReadFile.h"
|
|
||||||
#include "IFileArchive.h"
|
|
||||||
#include "CFileList.h"
|
|
||||||
|
|
||||||
#include <android/native_activity.h>
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
namespace io
|
|
||||||
{
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Android asset file system written August 2012 by J.Henrichs (later reworked by others).
|
|
||||||
*/
|
|
||||||
class CAndroidAssetFileArchive : public virtual IFileArchive,
|
|
||||||
virtual CFileList
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
//! constructor
|
|
||||||
CAndroidAssetFileArchive(AAssetManager *assetManager, bool ignoreCase, bool ignorePaths);
|
|
||||||
|
|
||||||
//! destructor
|
|
||||||
virtual ~CAndroidAssetFileArchive();
|
|
||||||
|
|
||||||
//! opens a file by file name
|
|
||||||
virtual IReadFile *createAndOpenFile(const io::path &filename);
|
|
||||||
|
|
||||||
//! opens a file by index
|
|
||||||
virtual IReadFile *createAndOpenFile(u32 index);
|
|
||||||
|
|
||||||
//! returns the list of files
|
|
||||||
virtual const IFileList *getFileList() const;
|
|
||||||
|
|
||||||
//! get the archive type
|
|
||||||
virtual E_FILE_ARCHIVE_TYPE getType() const;
|
|
||||||
|
|
||||||
//! Add a directory to read files from. Since the Android
|
|
||||||
//! API does not return names of directories, they need to
|
|
||||||
//! be added manually.
|
|
||||||
virtual void addDirectoryToFileList(const io::path &filename);
|
|
||||||
|
|
||||||
//! return the name (id) of the file Archive
|
|
||||||
const io::path &getArchiveName() const override { return Path; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
//! Android's asset manager
|
|
||||||
AAssetManager *AssetManager;
|
|
||||||
|
|
||||||
}; // CAndroidAssetFileArchive
|
|
||||||
|
|
||||||
} // end namespace io
|
|
||||||
} // end namespace irr
|
|
|
@ -1,65 +0,0 @@
|
||||||
// Copyright (C) 2002-2011 Nikolaus Gebhardt
|
|
||||||
// This file is part of the "Irrlicht Engine".
|
|
||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
||||||
|
|
||||||
#include "CAndroidAssetReader.h"
|
|
||||||
|
|
||||||
#include "CReadFile.h"
|
|
||||||
#include "coreutil.h"
|
|
||||||
#include "CAndroidAssetReader.h"
|
|
||||||
#include "CIrrDeviceAndroid.h"
|
|
||||||
|
|
||||||
#include <android_native_app_glue.h>
|
|
||||||
#include <android/native_activity.h>
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
namespace io
|
|
||||||
{
|
|
||||||
|
|
||||||
CAndroidAssetReader::CAndroidAssetReader(AAssetManager *assetManager, const io::path &filename) :
|
|
||||||
AssetManager(assetManager), Filename(filename)
|
|
||||||
{
|
|
||||||
Asset = AAssetManager_open(AssetManager,
|
|
||||||
core::stringc(filename).c_str(),
|
|
||||||
AASSET_MODE_RANDOM);
|
|
||||||
}
|
|
||||||
|
|
||||||
CAndroidAssetReader::~CAndroidAssetReader()
|
|
||||||
{
|
|
||||||
if (Asset)
|
|
||||||
AAsset_close(Asset);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t CAndroidAssetReader::read(void *buffer, size_t sizeToRead)
|
|
||||||
{
|
|
||||||
int readBytes = AAsset_read(Asset, buffer, sizeToRead);
|
|
||||||
if (readBytes >= 0)
|
|
||||||
return size_t(readBytes);
|
|
||||||
return 0; // direct fd access is not possible (for example, if the asset is compressed).
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CAndroidAssetReader::seek(long finalPos, bool relativeMovement)
|
|
||||||
{
|
|
||||||
off_t status = AAsset_seek(Asset, finalPos, relativeMovement ? SEEK_CUR : SEEK_SET);
|
|
||||||
|
|
||||||
return status + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
long CAndroidAssetReader::getSize() const
|
|
||||||
{
|
|
||||||
return AAsset_getLength(Asset);
|
|
||||||
}
|
|
||||||
|
|
||||||
long CAndroidAssetReader::getPos() const
|
|
||||||
{
|
|
||||||
return AAsset_getLength(Asset) - AAsset_getRemainingLength(Asset);
|
|
||||||
}
|
|
||||||
|
|
||||||
const io::path &CAndroidAssetReader::getFileName() const
|
|
||||||
{
|
|
||||||
return Filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace io
|
|
||||||
} // end namespace irr
|
|
|
@ -1,64 +0,0 @@
|
||||||
// Copyright (C) 2012 Joerg Henrichs
|
|
||||||
// This file is part of the "Irrlicht Engine".
|
|
||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "IReadFile.h"
|
|
||||||
|
|
||||||
struct AAssetManager;
|
|
||||||
struct AAsset;
|
|
||||||
struct ANativeActivity;
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
namespace io
|
|
||||||
{
|
|
||||||
|
|
||||||
class CAndroidAssetReader : public virtual IReadFile
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CAndroidAssetReader(AAssetManager *assetManager, const io::path &filename);
|
|
||||||
|
|
||||||
virtual ~CAndroidAssetReader();
|
|
||||||
|
|
||||||
//! Reads an amount of bytes from the file.
|
|
||||||
/** \param buffer Pointer to buffer where read bytes are written to.
|
|
||||||
\param sizeToRead Amount of bytes to read from the file.
|
|
||||||
\return How many bytes were read. */
|
|
||||||
virtual size_t read(void *buffer, size_t sizeToRead);
|
|
||||||
|
|
||||||
//! Changes position in file
|
|
||||||
/** \param finalPos Destination position in the file.
|
|
||||||
\param relativeMovement If set to true, the position in the file is
|
|
||||||
changed relative to current position. Otherwise the position is changed
|
|
||||||
from beginning of file.
|
|
||||||
\return True if successful, otherwise false. */
|
|
||||||
virtual bool seek(long finalPos, bool relativeMovement = false);
|
|
||||||
|
|
||||||
//! Get size of file.
|
|
||||||
/** \return Size of the file in bytes. */
|
|
||||||
virtual long getSize() const;
|
|
||||||
|
|
||||||
//! Get the current position in the file.
|
|
||||||
/** \return Current position in the file in bytes. */
|
|
||||||
virtual long getPos() const;
|
|
||||||
|
|
||||||
//! Get name of file.
|
|
||||||
/** \return File name as zero terminated character string. */
|
|
||||||
virtual const io::path &getFileName() const;
|
|
||||||
|
|
||||||
/** Return true if the file could be opened. */
|
|
||||||
bool isOpen() const { return Asset != NULL; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
//! Android's asset manager
|
|
||||||
AAssetManager *AssetManager;
|
|
||||||
|
|
||||||
// An asset, i.e. file
|
|
||||||
AAsset *Asset;
|
|
||||||
path Filename;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace io
|
|
||||||
} // end namespace irr
|
|
|
@ -1,828 +0,0 @@
|
||||||
// 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 ¶ms,
|
|
||||||
io::IFileSystem *io, video::IContextManager *contextManager);
|
|
||||||
|
|
||||||
IVideoDriver *createOGLES2Driver(const SIrrlichtCreationParameters ¶ms,
|
|
||||||
io::IFileSystem *io, video::IContextManager *contextManager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
|
|
||||||
CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters ¶m) :
|
|
||||||
CIrrDeviceStub(param), Accelerometer(0), Gyroscope(0), Initialized(false),
|
|
||||||
Stopped(true), Paused(true), Focused(false), 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((!Initialized || isWindowActive()) ? 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 && !Stopped);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CIrrDeviceAndroid::isWindowFocused() const
|
|
||||||
{
|
|
||||||
return Focused;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CIrrDeviceAndroid::isWindowMinimized() const
|
|
||||||
{
|
|
||||||
return !Focused;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CIrrDeviceAndroid::isWindowVisible() const
|
|
||||||
{
|
|
||||||
return !Stopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
device->Stopped = false;
|
|
||||||
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);
|
|
||||||
device->Stopped = true;
|
|
||||||
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
|
|
|
@ -1,98 +0,0 @@
|
||||||
// Copyright (C) 2002-2011 Nikolaus Gebhardt
|
|
||||||
// This file is part of the "Irrlicht Engine".
|
|
||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CIrrDeviceStub.h"
|
|
||||||
#include "IrrlichtDevice.h"
|
|
||||||
#include "ICursorControl.h"
|
|
||||||
|
|
||||||
#include <android/sensor.h>
|
|
||||||
#include <android_native_app_glue.h>
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
class CIrrDeviceAndroid : public CIrrDeviceStub
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CIrrDeviceAndroid(const SIrrlichtCreationParameters ¶m);
|
|
||||||
|
|
||||||
virtual ~CIrrDeviceAndroid();
|
|
||||||
|
|
||||||
virtual bool run();
|
|
||||||
|
|
||||||
virtual void yield();
|
|
||||||
|
|
||||||
virtual void sleep(u32 timeMs, bool pauseTimer = false);
|
|
||||||
|
|
||||||
virtual void setWindowCaption(const wchar_t *text);
|
|
||||||
|
|
||||||
virtual bool isWindowActive() const;
|
|
||||||
|
|
||||||
virtual bool isWindowFocused() const;
|
|
||||||
|
|
||||||
virtual bool isWindowMinimized() const;
|
|
||||||
|
|
||||||
virtual bool isWindowVisible() const;
|
|
||||||
|
|
||||||
virtual void closeDevice();
|
|
||||||
|
|
||||||
virtual void setResizable(bool resize = false);
|
|
||||||
|
|
||||||
virtual void minimizeWindow();
|
|
||||||
|
|
||||||
virtual void maximizeWindow();
|
|
||||||
|
|
||||||
virtual void restoreWindow();
|
|
||||||
|
|
||||||
virtual core::position2di getWindowPosition();
|
|
||||||
|
|
||||||
virtual E_DEVICE_TYPE getType() const;
|
|
||||||
|
|
||||||
virtual bool activateAccelerometer(float updateInterval);
|
|
||||||
|
|
||||||
virtual bool deactivateAccelerometer();
|
|
||||||
|
|
||||||
virtual bool isAccelerometerActive();
|
|
||||||
|
|
||||||
virtual bool isAccelerometerAvailable();
|
|
||||||
|
|
||||||
virtual bool activateGyroscope(float updateInterval);
|
|
||||||
|
|
||||||
virtual bool deactivateGyroscope();
|
|
||||||
|
|
||||||
virtual bool isGyroscopeActive();
|
|
||||||
|
|
||||||
virtual bool isGyroscopeAvailable();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void handleAndroidCommand(android_app *app, int32_t cmd);
|
|
||||||
|
|
||||||
static s32 handleInput(android_app *app, AInputEvent *event);
|
|
||||||
|
|
||||||
void createDriver();
|
|
||||||
|
|
||||||
void createKeyMap();
|
|
||||||
|
|
||||||
video::SExposedVideoData &getExposedVideoData();
|
|
||||||
|
|
||||||
android_app *Android;
|
|
||||||
ASensorManager *SensorManager;
|
|
||||||
ASensorEventQueue *SensorEventQueue;
|
|
||||||
const ASensor *Accelerometer;
|
|
||||||
const ASensor *Gyroscope;
|
|
||||||
|
|
||||||
bool Initialized;
|
|
||||||
bool Stopped;
|
|
||||||
bool Paused;
|
|
||||||
bool Focused;
|
|
||||||
|
|
||||||
JNIEnv *JNIEnvAttachedToVM;
|
|
||||||
|
|
||||||
video::SExposedVideoData ExposedVideoData;
|
|
||||||
|
|
||||||
core::array<EKEY_CODE> KeyMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // end namespace irr
|
|
|
@ -1,52 +0,0 @@
|
||||||
// This file is part of the "Irrlicht Engine".
|
|
||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
||||||
|
|
||||||
#include "CKeyEventWrapper.h"
|
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
namespace jni
|
|
||||||
{
|
|
||||||
|
|
||||||
jclass CKeyEventWrapper::Class_KeyEvent = 0;
|
|
||||||
jmethodID CKeyEventWrapper::Method_constructor = 0;
|
|
||||||
jmethodID CKeyEventWrapper::Method_getUnicodeChar = 0;
|
|
||||||
|
|
||||||
CKeyEventWrapper::CKeyEventWrapper(JNIEnv *jniEnv, int action, int code) :
|
|
||||||
JniEnv(jniEnv), JniKeyEvent(0)
|
|
||||||
{
|
|
||||||
if (JniEnv) {
|
|
||||||
if (!Class_KeyEvent) {
|
|
||||||
// Find java classes & functions on first call
|
|
||||||
os::Printer::log("CKeyEventWrapper first initialize", ELL_DEBUG);
|
|
||||||
jclass localClass = JniEnv->FindClass("android/view/KeyEvent");
|
|
||||||
if (localClass) {
|
|
||||||
Class_KeyEvent = reinterpret_cast<jclass>(JniEnv->NewGlobalRef(localClass));
|
|
||||||
}
|
|
||||||
|
|
||||||
Method_constructor = JniEnv->GetMethodID(Class_KeyEvent, "<init>", "(II)V");
|
|
||||||
Method_getUnicodeChar = JniEnv->GetMethodID(Class_KeyEvent, "getUnicodeChar", "(I)I");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Class_KeyEvent && Method_constructor) {
|
|
||||||
JniKeyEvent = JniEnv->NewObject(Class_KeyEvent, Method_constructor, action, code);
|
|
||||||
} else {
|
|
||||||
os::Printer::log("CKeyEventWrapper didn't find JNI classes/methods", ELL_WARNING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CKeyEventWrapper::~CKeyEventWrapper()
|
|
||||||
{
|
|
||||||
JniEnv->DeleteLocalRef(JniKeyEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CKeyEventWrapper::getUnicodeChar(int metaState)
|
|
||||||
{
|
|
||||||
return JniEnv->CallIntMethod(JniKeyEvent, Method_getUnicodeChar, metaState);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace jni
|
|
||||||
} // namespace irr
|
|
|
@ -1,35 +0,0 @@
|
||||||
// This file is part of the "Irrlicht Engine".
|
|
||||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
|
|
||||||
struct android_app;
|
|
||||||
|
|
||||||
namespace irr
|
|
||||||
{
|
|
||||||
namespace jni
|
|
||||||
{
|
|
||||||
|
|
||||||
//! Minimal JNI wrapper class around android.view.KeyEvent
|
|
||||||
//! NOTE: Only functions we actually use in the engine are wrapped
|
|
||||||
//! This is currently not written to support multithreading - meaning threads are not attached/detached to the Java VM (to be discussed)
|
|
||||||
class CKeyEventWrapper
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CKeyEventWrapper(JNIEnv *jniEnv, int action, int code);
|
|
||||||
~CKeyEventWrapper();
|
|
||||||
|
|
||||||
int getUnicodeChar(int metaState);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static jclass Class_KeyEvent;
|
|
||||||
static jmethodID Method_getUnicodeChar;
|
|
||||||
static jmethodID Method_constructor;
|
|
||||||
JNIEnv *JniEnv;
|
|
||||||
jobject JniKeyEvent; // this object in java
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace jni
|
|
||||||
} // namespace irr
|
|
|
@ -10,10 +10,6 @@
|
||||||
#include "irrArray.h"
|
#include "irrArray.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
|
|
||||||
#include <android/native_activity.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
namespace video
|
namespace video
|
||||||
|
@ -55,9 +51,6 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SE
|
||||||
#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
|
#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_)
|
||||||
EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window;
|
EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window;
|
||||||
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display);
|
EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display);
|
||||||
#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
|
|
||||||
EglWindow = (ANativeWindow *)Data.OGLESAndroid.Window;
|
|
||||||
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
|
||||||
#elif defined(_IRR_COMPILE_WITH_FB_DEVICE_)
|
#elif defined(_IRR_COMPILE_WITH_FB_DEVICE_)
|
||||||
EglWindow = (NativeWindowType)Data.OpenGLFB.Window;
|
EglWindow = (NativeWindowType)Data.OpenGLFB.Window;
|
||||||
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
|
@ -119,10 +112,6 @@ bool CEGLManager::generateSurface()
|
||||||
// at this time only Android support this feature.
|
// at this time only Android support this feature.
|
||||||
// this needs an update method instead!
|
// this needs an update method instead!
|
||||||
|
|
||||||
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
|
|
||||||
EglWindow = (ANativeWindow *)Data.OGLESAndroid.Window;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
|
#if defined(_IRR_EMSCRIPTEN_PLATFORM_)
|
||||||
// eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing)
|
// eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing)
|
||||||
// But the other solution would also be fine as it also only generates a single context so there is not much to choose from.
|
// But the other solution would also be fine as it also only generates a single context so there is not much to choose from.
|
||||||
|
@ -136,13 +125,6 @@ bool CEGLManager::generateSurface()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_)
|
|
||||||
EGLint Format = 0;
|
|
||||||
eglGetConfigAttrib(EglDisplay, EglConfig, EGL_NATIVE_VISUAL_ID, &Format);
|
|
||||||
|
|
||||||
ANativeWindow_setBuffersGeometry(EglWindow, 0, 0, Format);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Now we are able to create EGL surface.
|
// Now we are able to create EGL surface.
|
||||||
EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, EglWindow, 0);
|
EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, EglWindow, 0);
|
||||||
|
|
||||||
|
|
|
@ -252,13 +252,31 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters ¶m) :
|
||||||
Window((SDL_Window *)param.WindowId), SDL_Flags(0),
|
Window((SDL_Window *)param.WindowId), SDL_Flags(0),
|
||||||
MouseX(0), MouseY(0), MouseXRel(0), MouseYRel(0), MouseButtonStates(0),
|
MouseX(0), MouseY(0), MouseXRel(0), MouseYRel(0), MouseButtonStates(0),
|
||||||
Width(param.WindowSize.Width), Height(param.WindowSize.Height),
|
Width(param.WindowSize.Width), Height(param.WindowSize.Height),
|
||||||
Resizable(param.WindowResizable == 1 ? true : false), CurrentTouchCount(0)
|
Resizable(param.WindowResizable == 1 ? true : false), CurrentTouchCount(0),
|
||||||
|
IsInBackground(false)
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
setDebugName("CIrrDeviceSDL");
|
setDebugName("CIrrDeviceSDL");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (++SDLDeviceInstances == 1) {
|
if (++SDLDeviceInstances == 1) {
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
// Blocking on pause causes problems with multiplayer.
|
||||||
|
// See https://github.com/minetest/minetest/issues/10842.
|
||||||
|
SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, "0");
|
||||||
|
SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE_PAUSEAUDIO, "0");
|
||||||
|
|
||||||
|
SDL_SetHint(SDL_HINT_ANDROID_TRAP_BACK_BUTTON, "1");
|
||||||
|
|
||||||
|
// Minetest does its own screen keyboard handling.
|
||||||
|
SDL_SetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD, "0");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Minetest has its own code to synthesize mouse events from touch events,
|
||||||
|
// so we prevent SDL from doing it.
|
||||||
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
|
||||||
|
|
||||||
u32 flags = SDL_INIT_TIMER | SDL_INIT_EVENTS;
|
u32 flags = SDL_INIT_TIMER | SDL_INIT_EVENTS;
|
||||||
if (CreationParams.DriverType != video::EDT_NULL)
|
if (CreationParams.DriverType != video::EDT_NULL)
|
||||||
flags |= SDL_INIT_VIDEO;
|
flags |= SDL_INIT_VIDEO;
|
||||||
|
@ -273,11 +291,6 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters ¶m) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Minetest has its own code to synthesize mouse events from touch events,
|
|
||||||
// so we prevent SDL from doing it.
|
|
||||||
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
|
||||||
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
|
|
||||||
|
|
||||||
// create keymap
|
// create keymap
|
||||||
createKeyMap();
|
createKeyMap();
|
||||||
|
|
||||||
|
@ -448,9 +461,13 @@ bool CIrrDeviceSDL::createWindow()
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Makes context creation fail on some Android devices.
|
||||||
|
See discussion in https://github.com/minetest/minetest/pull/14498.
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG);
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG);
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
if (CreationParams.Bits == 16) {
|
if (CreationParams.Bits == 16) {
|
||||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
|
||||||
|
@ -510,6 +527,14 @@ bool CIrrDeviceSDL::createWindow()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update Width and Height to match the actual window size.
|
||||||
|
// In fullscreen mode, the window size specified in SIrrlichtCreationParameters
|
||||||
|
// is ignored, so we cannot rely on it.
|
||||||
|
int w = 0, h = 0;
|
||||||
|
SDL_GetWindowSize(Window, &w, &h);
|
||||||
|
Width = w;
|
||||||
|
Height = h;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
#endif // !_IRR_EMSCRIPTEN_PLATFORM_
|
#endif // !_IRR_EMSCRIPTEN_PLATFORM_
|
||||||
}
|
}
|
||||||
|
@ -621,7 +646,17 @@ bool CIrrDeviceSDL::run()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
switch (SDL_event.button.button) {
|
auto button = SDL_event.button.button;
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
// Android likes to send the right mouse button as the back button.
|
||||||
|
// According to some web searches I did, this is probably
|
||||||
|
// vendor/device-specific.
|
||||||
|
// Since a working right mouse button is very important for
|
||||||
|
// Minetest, we have this little hack.
|
||||||
|
if (button == SDL_BUTTON_X2)
|
||||||
|
button = SDL_BUTTON_RIGHT;
|
||||||
|
#endif
|
||||||
|
switch (button) {
|
||||||
case SDL_BUTTON_LEFT:
|
case SDL_BUTTON_LEFT:
|
||||||
if (SDL_event.type == SDL_MOUSEBUTTONDOWN) {
|
if (SDL_event.type == SDL_MOUSEBUTTONDOWN) {
|
||||||
irrevent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN;
|
irrevent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN;
|
||||||
|
@ -772,6 +807,20 @@ bool CIrrDeviceSDL::run()
|
||||||
postEventFromUser(irrevent);
|
postEventFromUser(irrevent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Contrary to what the SDL documentation says, SDL_APP_WILLENTERBACKGROUND
|
||||||
|
// and SDL_APP_WILLENTERFOREGROUND are actually sent in onStop/onStart,
|
||||||
|
// not onPause/onResume, on recent Android versions. This can be verified
|
||||||
|
// by testing or by looking at the org.libsdl.app.SDLActivity Java code.
|
||||||
|
// -> This means we can use them to implement isWindowVisible().
|
||||||
|
|
||||||
|
case SDL_APP_WILLENTERBACKGROUND:
|
||||||
|
IsInBackground = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDL_APP_WILLENTERFOREGROUND:
|
||||||
|
IsInBackground = false;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
} // end switch
|
} // end switch
|
||||||
|
@ -1053,6 +1102,11 @@ bool CIrrDeviceSDL::isFullscreen() const
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CIrrDeviceSDL::isWindowVisible() const
|
||||||
|
{
|
||||||
|
return !IsInBackground;
|
||||||
|
}
|
||||||
|
|
||||||
//! returns if window is active. if not, nothing need to be drawn
|
//! returns if window is active. if not, nothing need to be drawn
|
||||||
bool CIrrDeviceSDL::isWindowActive() const
|
bool CIrrDeviceSDL::isWindowActive() const
|
||||||
{
|
{
|
||||||
|
@ -1111,6 +1165,8 @@ void CIrrDeviceSDL::createKeyMap()
|
||||||
|
|
||||||
// buttons missing
|
// buttons missing
|
||||||
|
|
||||||
|
KeyMap.push_back(SKeyMap(SDLK_AC_BACK, KEY_CANCEL));
|
||||||
|
|
||||||
KeyMap.push_back(SKeyMap(SDLK_BACKSPACE, KEY_BACK));
|
KeyMap.push_back(SKeyMap(SDLK_BACKSPACE, KEY_BACK));
|
||||||
KeyMap.push_back(SKeyMap(SDLK_TAB, KEY_TAB));
|
KeyMap.push_back(SKeyMap(SDLK_TAB, KEY_TAB));
|
||||||
KeyMap.push_back(SKeyMap(SDLK_CLEAR, KEY_CLEAR));
|
KeyMap.push_back(SKeyMap(SDLK_CLEAR, KEY_CLEAR));
|
||||||
|
|
|
@ -86,6 +86,9 @@ public:
|
||||||
/** \return True if window is fullscreen. */
|
/** \return True if window is fullscreen. */
|
||||||
bool isFullscreen() const override;
|
bool isFullscreen() const override;
|
||||||
|
|
||||||
|
//! Checks if the window could possibly be visible.
|
||||||
|
bool isWindowVisible() const override;
|
||||||
|
|
||||||
//! Get the position of this window on screen
|
//! Get the position of this window on screen
|
||||||
core::position2di getWindowPosition() override;
|
core::position2di getWindowPosition() override;
|
||||||
|
|
||||||
|
@ -319,6 +322,7 @@ private:
|
||||||
SDL_SysWMinfo Info;
|
SDL_SysWMinfo Info;
|
||||||
|
|
||||||
s32 CurrentTouchCount;
|
s32 CurrentTouchCount;
|
||||||
|
bool IsInBackground;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace irr
|
} // end namespace irr
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
if(NOT ANDROID AND NOT APPLE)
|
if(NOT APPLE)
|
||||||
set(DEFAULT_SDL2 ON)
|
set(DEFAULT_SDL2 ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -77,10 +77,9 @@ elseif(APPLE)
|
||||||
set(DEVICE "OSX")
|
set(DEVICE "OSX")
|
||||||
elseif(ANDROID)
|
elseif(ANDROID)
|
||||||
add_definitions(-D_IRR_ANDROID_PLATFORM_)
|
add_definitions(-D_IRR_ANDROID_PLATFORM_)
|
||||||
if(USE_SDL2)
|
if(NOT USE_SDL2)
|
||||||
message(FATAL_ERROR "SDL2 device is not (yet) supported on Android")
|
message(FATAL_ERROR "The Android build requires SDL2")
|
||||||
endif()
|
endif()
|
||||||
set(DEVICE "ANDROID")
|
|
||||||
elseif(EMSCRIPTEN)
|
elseif(EMSCRIPTEN)
|
||||||
add_definitions(-D_IRR_EMSCRIPTEN_PLATFORM_ -D_IRR_COMPILE_WITH_EGL_MANAGER_)
|
add_definitions(-D_IRR_EMSCRIPTEN_PLATFORM_ -D_IRR_COMPILE_WITH_EGL_MANAGER_)
|
||||||
set(LINUX_PLATFORM TRUE)
|
set(LINUX_PLATFORM TRUE)
|
||||||
|
@ -131,7 +130,10 @@ endif()
|
||||||
# OpenGL
|
# OpenGL
|
||||||
|
|
||||||
if(USE_SDL2)
|
if(USE_SDL2)
|
||||||
option(ENABLE_OPENGL3 "Enable OpenGL 3+" TRUE)
|
if(NOT ANDROID)
|
||||||
|
set(DEFAULT_OPENGL3 TRUE)
|
||||||
|
endif()
|
||||||
|
option(ENABLE_OPENGL3 "Enable OpenGL 3+" ${DEFAULT_OPENGL3})
|
||||||
else()
|
else()
|
||||||
set(ENABLE_OPENGL3 FALSE)
|
set(ENABLE_OPENGL3 FALSE)
|
||||||
endif()
|
endif()
|
||||||
|
@ -142,13 +144,10 @@ else()
|
||||||
option(ENABLE_OPENGL "Enable OpenGL" TRUE)
|
option(ENABLE_OPENGL "Enable OpenGL" TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(EMSCRIPTEN OR APPLE)
|
if(USE_SDL2 OR EMSCRIPTEN OR APPLE)
|
||||||
set(ENABLE_GLES1 FALSE)
|
set(ENABLE_GLES1 FALSE)
|
||||||
else()
|
else()
|
||||||
if(ANDROID)
|
option(ENABLE_GLES1 "Enable OpenGL ES" FALSE)
|
||||||
set(DEFAULT_GLES1 TRUE)
|
|
||||||
endif()
|
|
||||||
option(ENABLE_GLES1 "Enable OpenGL ES" ${DEFAULT_GLES1})
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
@ -188,19 +187,16 @@ if(ENABLE_OPENGL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_GLES1)
|
if(ENABLE_GLES1)
|
||||||
if (USE_SDL2)
|
|
||||||
message(FATAL_ERROR "OpenGL ES 1 is not supported with SDL2")
|
|
||||||
endif()
|
|
||||||
add_definitions(-D_IRR_COMPILE_WITH_OGLES1_)
|
add_definitions(-D_IRR_COMPILE_WITH_OGLES1_)
|
||||||
set(OPENGLES_DIRECT_LINK TRUE)
|
set(OPENGLES_DIRECT_LINK TRUE)
|
||||||
if(DEVICE MATCHES "^(WINDOWS|X11|ANDROID)$")
|
if(DEVICE MATCHES "^(WINDOWS|X11)$")
|
||||||
add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_)
|
add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_GLES2)
|
if(ENABLE_GLES2)
|
||||||
add_definitions(-D_IRR_COMPILE_WITH_OGLES2_)
|
add_definitions(-D_IRR_COMPILE_WITH_OGLES2_)
|
||||||
if(DEVICE MATCHES "^(WINDOWS|X11|ANDROID)$" OR EMSCRIPTEN)
|
if(DEVICE MATCHES "^(WINDOWS|X11)$" OR EMSCRIPTEN)
|
||||||
add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_)
|
add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -248,11 +244,15 @@ endif()
|
||||||
if(ENABLE_GLES2)
|
if(ENABLE_GLES2)
|
||||||
find_package(OpenGLES2 REQUIRED)
|
find_package(OpenGLES2 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
if(ENABLE_OPENGL OR ENABLE_OPENGL3)
|
if(ENABLE_OPENGL)
|
||||||
find_package(OpenGL REQUIRED)
|
find_package(OpenGL REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
if(USE_SDL2)
|
if(USE_SDL2)
|
||||||
find_package(SDL2 REQUIRED)
|
if(NOT ANDROID)
|
||||||
|
find_package(SDL2 REQUIRED)
|
||||||
|
else()
|
||||||
|
# provided by MinetestAndroidLibs.cmake
|
||||||
|
endif()
|
||||||
message(STATUS "Found SDL2: ${SDL2_LIBRARIES}")
|
message(STATUS "Found SDL2: ${SDL2_LIBRARIES}")
|
||||||
|
|
||||||
# unfortunately older SDL does not provide its version to cmake, so check header.
|
# unfortunately older SDL does not provide its version to cmake, so check header.
|
||||||
|
@ -323,7 +323,6 @@ set(link_includes
|
||||||
${OPENGLES2_INCLUDE_DIR}
|
${OPENGLES2_INCLUDE_DIR}
|
||||||
${EGL_INCLUDE_DIR}
|
${EGL_INCLUDE_DIR}
|
||||||
|
|
||||||
"$<$<PLATFORM_ID:Android>:${ANDROID_NDK}/sources/android/native_app_glue>"
|
|
||||||
"$<$<BOOL:${USE_X11}>:${X11_INCLUDE_DIR}>"
|
"$<$<BOOL:${USE_X11}>:${X11_INCLUDE_DIR}>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -453,14 +452,7 @@ if(ENABLE_OPENGL3)
|
||||||
target_compile_definitions(IRROTHEROBJ PRIVATE ENABLE_OPENGL3)
|
target_compile_definitions(IRROTHEROBJ PRIVATE ENABLE_OPENGL3)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ANDROID)
|
if(APPLE)
|
||||||
target_sources(IRROTHEROBJ PRIVATE
|
|
||||||
Android/CIrrDeviceAndroid.cpp
|
|
||||||
Android/CAndroidAssetReader.cpp
|
|
||||||
Android/CAndroidAssetFileArchive.cpp
|
|
||||||
Android/CKeyEventWrapper.cpp
|
|
||||||
)
|
|
||||||
elseif(APPLE)
|
|
||||||
# Build all IRROTHEROBJ sources as objc++, including the .cpp's
|
# Build all IRROTHEROBJ sources as objc++, including the .cpp's
|
||||||
set_target_properties(IRROTHEROBJ PROPERTIES COMPILE_OPTIONS "-xobjective-c++")
|
set_target_properties(IRROTHEROBJ PROPERTIES COMPILE_OPTIONS "-xobjective-c++")
|
||||||
target_sources(IRROTHEROBJ PRIVATE
|
target_sources(IRROTHEROBJ PRIVATE
|
||||||
|
@ -535,7 +527,8 @@ target_link_libraries(IrrlichtMt PRIVATE
|
||||||
"$<$<BOOL:${OPENGLES_DIRECT_LINK}>:${OPENGLES_LIBRARY}>"
|
"$<$<BOOL:${OPENGLES_DIRECT_LINK}>:${OPENGLES_LIBRARY}>"
|
||||||
${EGL_LIBRARY}
|
${EGL_LIBRARY}
|
||||||
|
|
||||||
"$<$<PLATFORM_ID:Android>:-landroid -llog>"
|
# incl. transitive SDL2 dependencies for static linking
|
||||||
|
"$<$<PLATFORM_ID:Android>:-landroid -llog -lGLESv2 -lGLESv1_CM -lOpenSLES>"
|
||||||
${COCOA_LIB}
|
${COCOA_LIB}
|
||||||
${IOKIT_LIB}
|
${IOKIT_LIB}
|
||||||
"$<$<PLATFORM_ID:Windows>:gdi32>"
|
"$<$<PLATFORM_ID:Windows>:gdi32>"
|
||||||
|
|
|
@ -19,10 +19,6 @@
|
||||||
#include "CImage.h"
|
#include "CImage.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
|
|
||||||
#include "android_native_app_glue.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
namespace video
|
namespace video
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#include "SMaterial.h"
|
#include "SMaterial.h"
|
||||||
#include "fast_atof.h"
|
#include "fast_atof.h"
|
||||||
|
|
||||||
#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) || defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_)
|
||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#else
|
#else
|
||||||
#include <GLES/egl.h>
|
#include <GLES/egl.h>
|
||||||
|
|
|
@ -28,10 +28,6 @@ static const char *const copyright = "Irrlicht Engine (c) 2002-2017 Nikolaus Geb
|
||||||
#include "CIrrDeviceSDL.h"
|
#include "CIrrDeviceSDL.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
|
|
||||||
#include "Android/CIrrDeviceAndroid.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
{
|
{
|
||||||
//! stub for calling createDeviceEx
|
//! stub for calling createDeviceEx
|
||||||
|
@ -74,11 +70,6 @@ extern "C" IRRLICHT_API IrrlichtDevice *IRRCALLCONV createDeviceEx(const SIrrlic
|
||||||
dev = new CIrrDeviceLinux(params);
|
dev = new CIrrDeviceLinux(params);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
|
|
||||||
if (params.DeviceType == EIDT_ANDROID || (!dev && params.DeviceType == EIDT_BEST))
|
|
||||||
dev = new CIrrDeviceAndroid(params);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||||
if (params.DeviceType == EIDT_SDL || (!dev && params.DeviceType == EIDT_BEST))
|
if (params.DeviceType == EIDT_SDL || (!dev && params.DeviceType == EIDT_BEST))
|
||||||
dev = new CIrrDeviceSDL(params);
|
dev = new CIrrDeviceSDL(params);
|
||||||
|
|
|
@ -21,10 +21,6 @@
|
||||||
#include "CImage.h"
|
#include "CImage.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_
|
|
||||||
#include "android_native_app_glue.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mt_opengl.h"
|
#include "mt_opengl.h"
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
|
|
|
@ -307,10 +307,6 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
|
|
||||||
add_library(native_app_glue OBJECT ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
|
|
||||||
set(PLATFORM_LIBS ${PLATFORM_LIBS} native_app_glue)
|
|
||||||
|
|
||||||
set(PLATFORM_LIBS ${PLATFORM_LIBS} android log)
|
set(PLATFORM_LIBS ${PLATFORM_LIBS} android log)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -518,6 +514,9 @@ include_directories(SYSTEM
|
||||||
${GMP_INCLUDE_DIR}
|
${GMP_INCLUDE_DIR}
|
||||||
${JSON_INCLUDE_DIR}
|
${JSON_INCLUDE_DIR}
|
||||||
${LUA_BIT_INCLUDE_DIR}
|
${LUA_BIT_INCLUDE_DIR}
|
||||||
|
# on Android, Minetest depends on SDL2 directly
|
||||||
|
# on other platforms, only IrrlichtMt depends on SDL2
|
||||||
|
"$<$<PLATFORM_ID:Android>:${SDL2_INCLUDE_DIRS}>"
|
||||||
)
|
)
|
||||||
|
|
||||||
if(USE_GETTEXT)
|
if(USE_GETTEXT)
|
||||||
|
@ -562,6 +561,9 @@ if(BUILD_CLIENT)
|
||||||
${LUA_BIT_LIBRARY}
|
${LUA_BIT_LIBRARY}
|
||||||
${FREETYPE_LIBRARY}
|
${FREETYPE_LIBRARY}
|
||||||
${PLATFORM_LIBS}
|
${PLATFORM_LIBS}
|
||||||
|
# on Android, Minetest depends on SDL2 directly
|
||||||
|
# on other platforms, only IrrlichtMt depends on SDL2
|
||||||
|
"$<$<PLATFORM_ID:Android>:${SDL2_LIBRARIES}>"
|
||||||
)
|
)
|
||||||
if(NOT USE_LUAJIT)
|
if(NOT USE_LUAJIT)
|
||||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||||
|
|
|
@ -2258,9 +2258,11 @@ void Game::openConsole(float scale, const wchar_t *line)
|
||||||
assert(scale > 0.0f && scale <= 1.0f);
|
assert(scale > 0.0f && scale <= 1.0f);
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
porting::showTextInputDialog("", "", 2);
|
if (!porting::hasPhysicalKeyboardAndroid()) {
|
||||||
m_android_chat_open = true;
|
porting::showTextInputDialog("", "", 2);
|
||||||
#else
|
m_android_chat_open = true;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
if (gui_chat_console->isOpenInhibited())
|
if (gui_chat_console->isOpenInhibited())
|
||||||
return;
|
return;
|
||||||
gui_chat_console->openConsole(scale);
|
gui_chat_console->openConsole(scale);
|
||||||
|
@ -2268,6 +2270,8 @@ void Game::openConsole(float scale, const wchar_t *line)
|
||||||
gui_chat_console->setCloseOnEnter(true);
|
gui_chat_console->setCloseOnEnter(true);
|
||||||
gui_chat_console->replaceAndAddToHistory(line);
|
gui_chat_console->replaceAndAddToHistory(line);
|
||||||
}
|
}
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
} // else
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,9 +229,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
|
||||||
params.Stencilbuffer = false;
|
params.Stencilbuffer = false;
|
||||||
params.Vsync = vsync;
|
params.Vsync = vsync;
|
||||||
params.EventReceiver = receiver;
|
params.EventReceiver = receiver;
|
||||||
#ifdef __ANDROID__
|
|
||||||
params.PrivateData = porting::app_global;
|
|
||||||
#endif
|
|
||||||
// there is no standardized path for these on desktop
|
// there is no standardized path for these on desktop
|
||||||
std::string rel_path = std::string("client") + DIR_DELIM
|
std::string rel_path = std::string("client") + DIR_DELIM
|
||||||
+ "shaders" + DIR_DELIM + "Irrlicht";
|
+ "shaders" + DIR_DELIM + "Irrlicht";
|
||||||
|
|
|
@ -239,7 +239,8 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event)
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
// display software keyboard when clicking edit boxes
|
// display software keyboard when clicking edit boxes
|
||||||
if (event.EventType == EET_MOUSE_INPUT_EVENT &&
|
if (event.EventType == EET_MOUSE_INPUT_EVENT &&
|
||||||
event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
|
event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN &&
|
||||||
|
!porting::hasPhysicalKeyboardAndroid()) {
|
||||||
gui::IGUIElement *hovered =
|
gui::IGUIElement *hovered =
|
||||||
Environment->getRootGUIElement()->getElementFromPoint(
|
Environment->getRootGUIElement()->getElementFromPoint(
|
||||||
core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
|
core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
|
||||||
|
|
|
@ -29,6 +29,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
#include <android/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
|
@ -30,6 +30,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#define SDL_MAIN_HANDLED 1
|
||||||
|
#include <SDL.h>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
@ -53,10 +57,8 @@ namespace porting {
|
||||||
bool setSystemPaths(); // used in porting.cpp
|
bool setSystemPaths(); // used in porting.cpp
|
||||||
}
|
}
|
||||||
|
|
||||||
void android_main(android_app *app)
|
extern "C" int SDL_Main(int _argc, char *_argv[])
|
||||||
{
|
{
|
||||||
porting::app_global = app;
|
|
||||||
|
|
||||||
Thread::setName("Main");
|
Thread::setName("Main");
|
||||||
|
|
||||||
char *argv[] = {strdup(PROJECT_NAME), strdup("--verbose"), nullptr};
|
char *argv[] = {strdup(PROJECT_NAME), strdup("--verbose"), nullptr};
|
||||||
|
@ -70,45 +72,15 @@ void android_main(android_app *app)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace porting {
|
namespace porting {
|
||||||
android_app *app_global = nullptr;
|
|
||||||
JNIEnv *jnienv = nullptr;
|
JNIEnv *jnienv = nullptr;
|
||||||
jclass nativeActivity;
|
jobject activity;
|
||||||
|
jclass activityClass;
|
||||||
jclass findClass(const std::string &classname)
|
|
||||||
{
|
|
||||||
if (jnienv == nullptr)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
jclass nativeactivity = jnienv->FindClass("android/app/NativeActivity");
|
|
||||||
jmethodID getClassLoader = jnienv->GetMethodID(
|
|
||||||
nativeactivity, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
|
||||||
jobject cls = jnienv->CallObjectMethod(
|
|
||||||
app_global->activity->clazz, getClassLoader);
|
|
||||||
jclass classLoader = jnienv->FindClass("java/lang/ClassLoader");
|
|
||||||
jmethodID findClass = jnienv->GetMethodID(classLoader, "loadClass",
|
|
||||||
"(Ljava/lang/String;)Ljava/lang/Class;");
|
|
||||||
jstring strClassName = jnienv->NewStringUTF(classname.c_str());
|
|
||||||
return (jclass) jnienv->CallObjectMethod(cls, findClass, strClassName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void osSpecificInit()
|
void osSpecificInit()
|
||||||
{
|
{
|
||||||
JavaVM *jvm = app_global->activity->vm;
|
jnienv = (JNIEnv*)SDL_AndroidGetJNIEnv();
|
||||||
JavaVMAttachArgs lJavaVMAttachArgs;
|
activity = (jobject)SDL_AndroidGetActivity();
|
||||||
lJavaVMAttachArgs.version = JNI_VERSION_1_6;
|
activityClass = jnienv->GetObjectClass(activity);
|
||||||
lJavaVMAttachArgs.name = PROJECT_NAME_C "NativeThread";
|
|
||||||
lJavaVMAttachArgs.group = nullptr;
|
|
||||||
|
|
||||||
if (jvm->AttachCurrentThread(&porting::jnienv, &lJavaVMAttachArgs) == JNI_ERR) {
|
|
||||||
errorstream << "Failed to attach native thread to jvm" << std::endl;
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
nativeActivity = findClass("net/minetest/minetest/GameActivity");
|
|
||||||
if (nativeActivity == nullptr)
|
|
||||||
errorstream <<
|
|
||||||
"porting::initAndroid unable to find Java native activity class" <<
|
|
||||||
std::endl;
|
|
||||||
|
|
||||||
// Set default language
|
// Set default language
|
||||||
auto lang = getLanguageAndroid();
|
auto lang = getLanguageAndroid();
|
||||||
|
@ -129,9 +101,6 @@ void cleanupAndroid()
|
||||||
setenv("CPUPROFILE", (path_user + DIR_DELIM + "gmon.out").c_str(), 1);
|
setenv("CPUPROFILE", (path_user + DIR_DELIM + "gmon.out").c_str(), 1);
|
||||||
moncleanup();
|
moncleanup();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JavaVM *jvm = app_global->activity->vm;
|
|
||||||
jvm->DetachCurrentThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string readJavaString(jstring j_str)
|
static std::string readJavaString(jstring j_str)
|
||||||
|
@ -149,11 +118,11 @@ bool setSystemPaths()
|
||||||
{
|
{
|
||||||
// Set user and share paths
|
// Set user and share paths
|
||||||
{
|
{
|
||||||
jmethodID getUserDataPath = jnienv->GetMethodID(nativeActivity,
|
jmethodID getUserDataPath = jnienv->GetMethodID(activityClass,
|
||||||
"getUserDataPath", "()Ljava/lang/String;");
|
"getUserDataPath", "()Ljava/lang/String;");
|
||||||
FATAL_ERROR_IF(getUserDataPath==nullptr,
|
FATAL_ERROR_IF(getUserDataPath==nullptr,
|
||||||
"porting::initializePathsAndroid unable to find Java getUserDataPath method");
|
"porting::initializePathsAndroid unable to find Java getUserDataPath method");
|
||||||
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getUserDataPath);
|
jobject result = jnienv->CallObjectMethod(activity, getUserDataPath);
|
||||||
std::string str = readJavaString((jstring) result);
|
std::string str = readJavaString((jstring) result);
|
||||||
path_user = str;
|
path_user = str;
|
||||||
path_share = str;
|
path_share = str;
|
||||||
|
@ -161,11 +130,11 @@ bool setSystemPaths()
|
||||||
|
|
||||||
// Set cache path
|
// Set cache path
|
||||||
{
|
{
|
||||||
jmethodID getCachePath = jnienv->GetMethodID(nativeActivity,
|
jmethodID getCachePath = jnienv->GetMethodID(activityClass,
|
||||||
"getCachePath", "()Ljava/lang/String;");
|
"getCachePath", "()Ljava/lang/String;");
|
||||||
FATAL_ERROR_IF(getCachePath==nullptr,
|
FATAL_ERROR_IF(getCachePath==nullptr,
|
||||||
"porting::initializePathsAndroid unable to find Java getCachePath method");
|
"porting::initializePathsAndroid unable to find Java getCachePath method");
|
||||||
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getCachePath);
|
jobject result = jnienv->CallObjectMethod(activity, getCachePath);
|
||||||
path_cache = readJavaString((jstring) result);
|
path_cache = readJavaString((jstring) result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +143,7 @@ bool setSystemPaths()
|
||||||
|
|
||||||
void showTextInputDialog(const std::string &hint, const std::string ¤t, int editType)
|
void showTextInputDialog(const std::string &hint, const std::string ¤t, int editType)
|
||||||
{
|
{
|
||||||
jmethodID showdialog = jnienv->GetMethodID(nativeActivity, "showTextInputDialog",
|
jmethodID showdialog = jnienv->GetMethodID(activityClass, "showTextInputDialog",
|
||||||
"(Ljava/lang/String;Ljava/lang/String;I)V");
|
"(Ljava/lang/String;Ljava/lang/String;I)V");
|
||||||
|
|
||||||
FATAL_ERROR_IF(showdialog == nullptr,
|
FATAL_ERROR_IF(showdialog == nullptr,
|
||||||
|
@ -184,13 +153,13 @@ void showTextInputDialog(const std::string &hint, const std::string ¤t, in
|
||||||
jstring jcurrent = jnienv->NewStringUTF(current.c_str());
|
jstring jcurrent = jnienv->NewStringUTF(current.c_str());
|
||||||
jint jeditType = editType;
|
jint jeditType = editType;
|
||||||
|
|
||||||
jnienv->CallVoidMethod(app_global->activity->clazz, showdialog,
|
jnienv->CallVoidMethod(activity, showdialog,
|
||||||
jhint, jcurrent, jeditType);
|
jhint, jcurrent, jeditType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showComboBoxDialog(const std::string optionList[], s32 listSize, s32 selectedIdx)
|
void showComboBoxDialog(const std::string optionList[], s32 listSize, s32 selectedIdx)
|
||||||
{
|
{
|
||||||
jmethodID showdialog = jnienv->GetMethodID(nativeActivity, "showSelectionInputDialog",
|
jmethodID showdialog = jnienv->GetMethodID(activityClass, "showSelectionInputDialog",
|
||||||
"([Ljava/lang/String;I)V");
|
"([Ljava/lang/String;I)V");
|
||||||
|
|
||||||
FATAL_ERROR_IF(showdialog == nullptr,
|
FATAL_ERROR_IF(showdialog == nullptr,
|
||||||
|
@ -205,79 +174,79 @@ void showComboBoxDialog(const std::string optionList[], s32 listSize, s32 select
|
||||||
jnienv->NewStringUTF(optionList[i].c_str()));
|
jnienv->NewStringUTF(optionList[i].c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
jnienv->CallVoidMethod(app_global->activity->clazz, showdialog, jOptionList,
|
jnienv->CallVoidMethod(activity, showdialog, jOptionList,
|
||||||
jselectedIdx);
|
jselectedIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void openURIAndroid(const char *url)
|
void openURIAndroid(const char *url)
|
||||||
{
|
{
|
||||||
jmethodID url_open = jnienv->GetMethodID(nativeActivity, "openURI",
|
jmethodID url_open = jnienv->GetMethodID(activityClass, "openURI",
|
||||||
"(Ljava/lang/String;)V");
|
"(Ljava/lang/String;)V");
|
||||||
|
|
||||||
FATAL_ERROR_IF(url_open == nullptr,
|
FATAL_ERROR_IF(url_open == nullptr,
|
||||||
"porting::openURIAndroid unable to find Java openURI method");
|
"porting::openURIAndroid unable to find Java openURI method");
|
||||||
|
|
||||||
jstring jurl = jnienv->NewStringUTF(url);
|
jstring jurl = jnienv->NewStringUTF(url);
|
||||||
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
|
jnienv->CallVoidMethod(activity, url_open, jurl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void shareFileAndroid(const std::string &path)
|
void shareFileAndroid(const std::string &path)
|
||||||
{
|
{
|
||||||
jmethodID url_open = jnienv->GetMethodID(nativeActivity, "shareFile",
|
jmethodID url_open = jnienv->GetMethodID(activityClass, "shareFile",
|
||||||
"(Ljava/lang/String;)V");
|
"(Ljava/lang/String;)V");
|
||||||
|
|
||||||
FATAL_ERROR_IF(url_open == nullptr,
|
FATAL_ERROR_IF(url_open == nullptr,
|
||||||
"porting::shareFileAndroid unable to find Java shareFile method");
|
"porting::shareFileAndroid unable to find Java shareFile method");
|
||||||
|
|
||||||
jstring jurl = jnienv->NewStringUTF(path.c_str());
|
jstring jurl = jnienv->NewStringUTF(path.c_str());
|
||||||
jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl);
|
jnienv->CallVoidMethod(activity, url_open, jurl);
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidDialogType getLastInputDialogType()
|
AndroidDialogType getLastInputDialogType()
|
||||||
{
|
{
|
||||||
jmethodID lastdialogtype = jnienv->GetMethodID(nativeActivity,
|
jmethodID lastdialogtype = jnienv->GetMethodID(activityClass,
|
||||||
"getLastDialogType", "()I");
|
"getLastDialogType", "()I");
|
||||||
|
|
||||||
FATAL_ERROR_IF(lastdialogtype == nullptr,
|
FATAL_ERROR_IF(lastdialogtype == nullptr,
|
||||||
"porting::getLastInputDialogType unable to find Java getLastDialogType method");
|
"porting::getLastInputDialogType unable to find Java getLastDialogType method");
|
||||||
|
|
||||||
int dialogType = jnienv->CallIntMethod(app_global->activity->clazz, lastdialogtype);
|
int dialogType = jnienv->CallIntMethod(activity, lastdialogtype);
|
||||||
return static_cast<AndroidDialogType>(dialogType);
|
return static_cast<AndroidDialogType>(dialogType);
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidDialogState getInputDialogState()
|
AndroidDialogState getInputDialogState()
|
||||||
{
|
{
|
||||||
jmethodID inputdialogstate = jnienv->GetMethodID(nativeActivity,
|
jmethodID inputdialogstate = jnienv->GetMethodID(activityClass,
|
||||||
"getInputDialogState", "()I");
|
"getInputDialogState", "()I");
|
||||||
|
|
||||||
FATAL_ERROR_IF(inputdialogstate == nullptr,
|
FATAL_ERROR_IF(inputdialogstate == nullptr,
|
||||||
"porting::getInputDialogState unable to find Java getInputDialogState method");
|
"porting::getInputDialogState unable to find Java getInputDialogState method");
|
||||||
|
|
||||||
int dialogState = jnienv->CallIntMethod(app_global->activity->clazz, inputdialogstate);
|
int dialogState = jnienv->CallIntMethod(activity, inputdialogstate);
|
||||||
return static_cast<AndroidDialogState>(dialogState);
|
return static_cast<AndroidDialogState>(dialogState);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getInputDialogMessage()
|
std::string getInputDialogMessage()
|
||||||
{
|
{
|
||||||
jmethodID dialogvalue = jnienv->GetMethodID(nativeActivity,
|
jmethodID dialogvalue = jnienv->GetMethodID(activityClass,
|
||||||
"getDialogMessage", "()Ljava/lang/String;");
|
"getDialogMessage", "()Ljava/lang/String;");
|
||||||
|
|
||||||
FATAL_ERROR_IF(dialogvalue == nullptr,
|
FATAL_ERROR_IF(dialogvalue == nullptr,
|
||||||
"porting::getInputDialogMessage unable to find Java getDialogMessage method");
|
"porting::getInputDialogMessage unable to find Java getDialogMessage method");
|
||||||
|
|
||||||
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz,
|
jobject result = jnienv->CallObjectMethod(activity,
|
||||||
dialogvalue);
|
dialogvalue);
|
||||||
return readJavaString((jstring) result);
|
return readJavaString((jstring) result);
|
||||||
}
|
}
|
||||||
|
|
||||||
int getInputDialogSelection()
|
int getInputDialogSelection()
|
||||||
{
|
{
|
||||||
jmethodID dialogvalue = jnienv->GetMethodID(nativeActivity, "getDialogSelection", "()I");
|
jmethodID dialogvalue = jnienv->GetMethodID(activityClass, "getDialogSelection", "()I");
|
||||||
|
|
||||||
FATAL_ERROR_IF(dialogvalue == nullptr,
|
FATAL_ERROR_IF(dialogvalue == nullptr,
|
||||||
"porting::getInputDialogSelection unable to find Java getDialogSelection method");
|
"porting::getInputDialogSelection unable to find Java getDialogSelection method");
|
||||||
|
|
||||||
return jnienv->CallIntMethod(app_global->activity->clazz, dialogvalue);
|
return jnienv->CallIntMethod(activity, dialogvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
|
@ -287,13 +256,13 @@ float getDisplayDensity()
|
||||||
static float value = 0;
|
static float value = 0;
|
||||||
|
|
||||||
if (firstrun) {
|
if (firstrun) {
|
||||||
jmethodID getDensity = jnienv->GetMethodID(nativeActivity,
|
jmethodID getDensity = jnienv->GetMethodID(activityClass,
|
||||||
"getDensity", "()F");
|
"getDensity", "()F");
|
||||||
|
|
||||||
FATAL_ERROR_IF(getDensity == nullptr,
|
FATAL_ERROR_IF(getDensity == nullptr,
|
||||||
"porting::getDisplayDensity unable to find Java getDensity method");
|
"porting::getDisplayDensity unable to find Java getDensity method");
|
||||||
|
|
||||||
value = jnienv->CallFloatMethod(app_global->activity->clazz, getDensity);
|
value = jnienv->CallFloatMethod(activity, getDensity);
|
||||||
firstrun = false;
|
firstrun = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,22 +275,22 @@ v2u32 getDisplaySize()
|
||||||
static v2u32 retval;
|
static v2u32 retval;
|
||||||
|
|
||||||
if (firstrun) {
|
if (firstrun) {
|
||||||
jmethodID getDisplayWidth = jnienv->GetMethodID(nativeActivity,
|
jmethodID getDisplayWidth = jnienv->GetMethodID(activityClass,
|
||||||
"getDisplayWidth", "()I");
|
"getDisplayWidth", "()I");
|
||||||
|
|
||||||
FATAL_ERROR_IF(getDisplayWidth == nullptr,
|
FATAL_ERROR_IF(getDisplayWidth == nullptr,
|
||||||
"porting::getDisplayWidth unable to find Java getDisplayWidth method");
|
"porting::getDisplayWidth unable to find Java getDisplayWidth method");
|
||||||
|
|
||||||
retval.X = jnienv->CallIntMethod(app_global->activity->clazz,
|
retval.X = jnienv->CallIntMethod(activity,
|
||||||
getDisplayWidth);
|
getDisplayWidth);
|
||||||
|
|
||||||
jmethodID getDisplayHeight = jnienv->GetMethodID(nativeActivity,
|
jmethodID getDisplayHeight = jnienv->GetMethodID(activityClass,
|
||||||
"getDisplayHeight", "()I");
|
"getDisplayHeight", "()I");
|
||||||
|
|
||||||
FATAL_ERROR_IF(getDisplayHeight == nullptr,
|
FATAL_ERROR_IF(getDisplayHeight == nullptr,
|
||||||
"porting::getDisplayHeight unable to find Java getDisplayHeight method");
|
"porting::getDisplayHeight unable to find Java getDisplayHeight method");
|
||||||
|
|
||||||
retval.Y = jnienv->CallIntMethod(app_global->activity->clazz,
|
retval.Y = jnienv->CallIntMethod(activity,
|
||||||
getDisplayHeight);
|
getDisplayHeight);
|
||||||
|
|
||||||
firstrun = false;
|
firstrun = false;
|
||||||
|
@ -332,16 +301,29 @@ v2u32 getDisplaySize()
|
||||||
|
|
||||||
std::string getLanguageAndroid()
|
std::string getLanguageAndroid()
|
||||||
{
|
{
|
||||||
jmethodID getLanguage = jnienv->GetMethodID(nativeActivity,
|
jmethodID getLanguage = jnienv->GetMethodID(activityClass,
|
||||||
"getLanguage", "()Ljava/lang/String;");
|
"getLanguage", "()Ljava/lang/String;");
|
||||||
|
|
||||||
FATAL_ERROR_IF(getLanguage == nullptr,
|
FATAL_ERROR_IF(getLanguage == nullptr,
|
||||||
"porting::getLanguageAndroid unable to find Java getLanguage method");
|
"porting::getLanguageAndroid unable to find Java getLanguage method");
|
||||||
|
|
||||||
jobject result = jnienv->CallObjectMethod(app_global->activity->clazz,
|
jobject result = jnienv->CallObjectMethod(activity,
|
||||||
getLanguage);
|
getLanguage);
|
||||||
return readJavaString((jstring) result);
|
return readJavaString((jstring) result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasPhysicalKeyboardAndroid()
|
||||||
|
{
|
||||||
|
jmethodID hasPhysicalKeyboard = jnienv->GetMethodID(activityClass,
|
||||||
|
"hasPhysicalKeyboard", "()Z");
|
||||||
|
|
||||||
|
FATAL_ERROR_IF(hasPhysicalKeyboard == nullptr,
|
||||||
|
"porting::hasPhysicalKeyboardAndroid unable to find Java hasPhysicalKeyboard method");
|
||||||
|
|
||||||
|
jboolean result = jnienv->CallBooleanMethod(activity,
|
||||||
|
hasPhysicalKeyboard);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // ndef SERVER
|
#endif // ndef SERVER
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,21 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
#error This header has to be included on Android port only!
|
#error This header has to be included on Android port only!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
#include <android_native_app_glue.h>
|
|
||||||
#include <android/log.h>
|
|
||||||
|
|
||||||
#include "irrlichttypes_bloated.h"
|
#include "irrlichttypes_bloated.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace porting {
|
namespace porting {
|
||||||
// Java app
|
|
||||||
extern android_app *app_global;
|
|
||||||
|
|
||||||
// Java <-> C++ interaction interface
|
|
||||||
extern JNIEnv *jnienv;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a text input dialog in Java
|
* Show a text input dialog in Java
|
||||||
* @param hint Hint to be shown
|
* @param hint Hint to be shown
|
||||||
|
@ -105,6 +94,9 @@ std::string getInputDialogMessage();
|
||||||
*/
|
*/
|
||||||
int getInputDialogSelection();
|
int getInputDialogSelection();
|
||||||
|
|
||||||
|
|
||||||
|
bool hasPhysicalKeyboardAndroid();
|
||||||
|
|
||||||
#ifndef SERVER
|
#ifndef SERVER
|
||||||
float getDisplayDensity();
|
float getDisplayDensity();
|
||||||
v2u32 getDisplaySize();
|
v2u32 getDisplaySize();
|
||||||
|
|
Loading…
Add table
Reference in a new issue