ANDROID: Input system overhaul

Rewritten input system with many new feature.
Fixed related bugs and shortcomings on the way.
This commit is contained in:
dhewg 2011-03-15 23:30:17 +01:00
parent e71c2cf850
commit adef4c3f42
12 changed files with 940 additions and 915 deletions

View file

@ -94,12 +94,6 @@ void checkGlError(const char *expr, const char *file, int line) {
}
#endif
// floating point. use sparingly
template <class T>
static inline T scalef(T in, float numerator, float denominator) {
return static_cast<float>(in) * numerator / denominator;
}
OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) :
_audio_sample_rate(audio_sample_rate),
_audio_buffer_size(audio_buffer_size),
@ -126,7 +120,16 @@ OSystem_Android::OSystem_Android(int audio_sample_rate, int audio_buffer_size) :
_timer(0),
_fsFactory(new POSIXFilesystemFactory()),
_shake_offset(0),
_event_queue_lock(createMutex()) {
_event_queue_lock(createMutex()),
_touch_pt_down(),
_touch_pt_dt(),
_eventScaleX(100),
_eventScaleY(100),
// TODO put these values in some option dlg?
_touchpad_mode(true),
_touchpad_scale(50),
_dpad_scale(4),
_trackball_scale(2) {
}
OSystem_Android::~OSystem_Android() {
@ -310,6 +313,10 @@ void OSystem_Android::initBackend() {
ConfMan.setBool("FM_high_quality", false);
ConfMan.setBool("FM_medium_quality", true);
// TODO hackity hack
if (ConfMan.hasKey("multi_midi"))
_touchpad_mode = !ConfMan.getBool("multi_midi");
// must happen before creating TimerManager to avoid race in
// creating EventManager
setupKeymapper();
@ -396,164 +403,6 @@ bool OSystem_Android::getFeatureState(Feature f) {
}
}
void OSystem_Android::setupKeymapper() {
#ifdef ENABLE_KEYMAPPER
using namespace Common;
Keymapper *mapper = getEventManager()->getKeymapper();
HardwareKeySet *keySet = new HardwareKeySet();
keySet->addHardwareKey(
new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)",
kTriggerLeftKeyType,
kVirtualKeyboardActionType));
mapper->registerHardwareKeySet(keySet);
Keymap *globalMap = new Keymap("global");
Action *act;
act = new Action(globalMap, "VIRT", "Display keyboard",
kVirtualKeyboardActionType);
act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0));
mapper->addGlobalKeymap(globalMap);
mapper->pushKeymap("global");
#endif
}
bool OSystem_Android::pollEvent(Common::Event &event) {
//ENTER();
if (pthread_self() == _main_thread) {
if (_screen_changeid != JNI::surface_changeid) {
if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) {
if (_egl_surface_width > 0 && _egl_surface_height > 0) {
// surface still alive but changed
_screen_changeid = JNI::surface_changeid;
_egl_surface_width = JNI::egl_surface_width;
_egl_surface_height = JNI::egl_surface_height;
initViewport();
updateScreenRect();
// double buffered, flip twice
clearScreen(kClearUpdate, 2);
event.type = Common::EVENT_SCREEN_CHANGED;
return true;
} else {
// new surface
initSurface();
updateScreenRect();
// double buffered, flip twice
clearScreen(kClearUpdate, 2);
event.type = Common::EVENT_SCREEN_CHANGED;
return true;
}
} else {
// surface lost
deinitSurface();
}
}
if (JNI::pause) {
deinitSurface();
LOGD("main thread going to sleep");
sem_wait(&JNI::pause_sem);
LOGD("main thread woke up");
}
}
lockMutex(_event_queue_lock);
if (_event_queue.empty()) {
unlockMutex(_event_queue_lock);
return false;
}
event = _event_queue.pop();
unlockMutex(_event_queue_lock);
switch (event.type) {
case Common::EVENT_MOUSEMOVE:
_force_redraw = true;
// fallthrough
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
case Common::EVENT_MBUTTONDOWN:
case Common::EVENT_MBUTTONUP: {
// relative mouse hack
if (event.kbd.flags == 1) {
// Relative (trackball) mouse hack.
const Common::Point& mouse_pos =
getEventManager()->getMousePos();
event.mouse.x += mouse_pos.x;
event.mouse.y += mouse_pos.y;
event.mouse.x = CLIP(event.mouse.x, (int16)0, _show_overlay ?
getOverlayWidth() : getWidth());
event.mouse.y = CLIP(event.mouse.y, (int16)0, _show_overlay ?
getOverlayHeight() : getHeight());
} else {
// Touchscreen events need to be converted
// from device to game coords first.
if (_show_overlay) {
event.mouse.x = scalef(event.mouse.x,
_overlay_texture->width(),
_egl_surface_width);
event.mouse.y = scalef(event.mouse.y,
_overlay_texture->height(),
_egl_surface_height);
} else {
const Common::Rect &r = _game_texture->getDrawRect();
event.mouse.x -= r.left;
event.mouse.y -= r.top;
event.mouse.x = scalef(event.mouse.x,
_game_texture->width(),
r.width());
event.mouse.y = scalef(event.mouse.y,
_game_texture->height(),
r.height());
event.mouse.x -= _shake_offset;
event.mouse.x = CLIP(event.mouse.x, int16(0),
int16(_game_texture->width()));
event.mouse.y = CLIP(event.mouse.y, int16(0),
int16(_game_texture->height()));
}
}
break;
}
default:
break;
}
return true;
}
void OSystem_Android::pushEvent(const Common::Event& event) {
lockMutex(_event_queue_lock);
_event_queue.push(event);
unlockMutex(_event_queue_lock);
}
uint32 OSystem_Android::getMillis() {
timeval curTime;

View file

@ -125,9 +125,6 @@ private:
bool _fullscreen;
bool _ar_correction;
Common::Queue<Common::Event> _event_queue;
MutexRef _event_queue_lock;
pthread_t _main_thread;
bool _timer_thread_exit;
@ -205,6 +202,25 @@ public:
return this;
}
public:
void pushEvent(int type, int arg1, int arg2, int arg3, int arg4, int arg5);
private:
Common::Queue<Common::Event> _event_queue;
MutexRef _event_queue_lock;
Common::Point _touch_pt_down, _touch_pt_dt;
int _eventScaleX;
int _eventScaleY;
bool _touchpad_mode;
int _touchpad_scale;
int _trackball_scale;
int _dpad_scale;
void clipMouse(Common::Point &p);
void scaleMouse(Common::Point &p, int x, int y, bool deductDrawRect = true);
void updateEventScale();
protected:
// PaletteManager API
virtual void setPalette(const byte *colors, uint start, uint num);
@ -242,7 +258,6 @@ public:
virtual void disableCursorPalette(bool disable);
virtual bool pollEvent(Common::Event &event);
void pushEvent(const Common::Event& event);
virtual uint32 getMillis();
virtual void delayMillis(uint msecs);

View file

@ -6,6 +6,7 @@ ANDROID_PLUGIN_VERSIONCODE = 6
JAVA_FILES = \
ScummVM.java \
ScummVMEvents.java \
ScummVMApplication.java \
ScummVMActivity.java \
EditableSurfaceView.java \

View file

@ -0,0 +1,661 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#if defined(__ANDROID__)
#include "common/events.h"
#include "backends/platform/android/android.h"
#include "backends/platform/android/jni.h"
// $ANDROID_NDK/platforms/android-9/arch-arm/usr/include/android/keycodes.h
// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=libs/ui/Input.cpp
// http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/java/android/view/KeyEvent.java
// event type
enum {
JE_SYS_KEY = 0,
JE_KEY = 1,
JE_DOWN = 2,
JE_SCROLL = 3,
JE_TAP = 4,
JE_DOUBLE_TAP = 5,
JE_BALL = 6,
JE_QUIT = 0x1000
};
// action type
enum {
JACTION_DOWN = 0,
JACTION_UP = 1,
JACTION_MULTIPLE = 2
};
// system keys
enum {
JKEYCODE_SOFT_RIGHT = 2,
JKEYCODE_HOME = 3,
JKEYCODE_BACK = 4,
JKEYCODE_CALL = 5,
JKEYCODE_ENDCALL = 6,
JKEYCODE_VOLUME_UP = 24,
JKEYCODE_VOLUME_DOWN = 25,
JKEYCODE_POWER = 26,
JKEYCODE_CAMERA = 27,
JKEYCODE_HEADSETHOOK = 79,
JKEYCODE_FOCUS = 80,
JKEYCODE_MENU = 82,
JKEYCODE_SEARCH = 84,
JKEYCODE_MUTE = 91,
JKEYCODE_MEDIA_PLAY_PAUSE = 85,
JKEYCODE_MEDIA_STOP = 86,
JKEYCODE_MEDIA_NEXT = 87,
JKEYCODE_MEDIA_PREVIOUS = 88,
JKEYCODE_MEDIA_REWIND = 89,
JKEYCODE_MEDIA_FAST_FORWARD = 90
};
// five-way navigation control
enum {
JKEYCODE_DPAD_UP = 19,
JKEYCODE_DPAD_DOWN = 20,
JKEYCODE_DPAD_LEFT = 21,
JKEYCODE_DPAD_RIGHT = 22,
JKEYCODE_DPAD_CENTER = 23
};
// meta modifier
enum {
JMETA_SHIFT = 0x01,
JMETA_ALT = 0x02,
JMETA_SYM = 0x04,
JMETA_CTRL = 0x1000
};
// map android key codes to our kbd codes
static const Common::KeyCode jkeymap[] = {
Common::KEYCODE_INVALID, // KEYCODE_UNKNOWN
Common::KEYCODE_INVALID, // KEYCODE_SOFT_LEFT
Common::KEYCODE_INVALID, // KEYCODE_SOFT_RIGHT
Common::KEYCODE_INVALID, // KEYCODE_HOME
Common::KEYCODE_INVALID, // KEYCODE_BACK
Common::KEYCODE_INVALID, // KEYCODE_CALL
Common::KEYCODE_INVALID, // KEYCODE_ENDCALL
Common::KEYCODE_0, // KEYCODE_0
Common::KEYCODE_1, // KEYCODE_1
Common::KEYCODE_2, // KEYCODE_2
Common::KEYCODE_3, // KEYCODE_3
Common::KEYCODE_4, // KEYCODE_4
Common::KEYCODE_5, // KEYCODE_5
Common::KEYCODE_6, // KEYCODE_6
Common::KEYCODE_7, // KEYCODE_7
Common::KEYCODE_8, // KEYCODE_8
Common::KEYCODE_9, // KEYCODE_9
Common::KEYCODE_ASTERISK, // KEYCODE_STAR
Common::KEYCODE_HASH, // KEYCODE_POUND
Common::KEYCODE_INVALID, // KEYCODE_DPAD_UP
Common::KEYCODE_INVALID, // KEYCODE_DPAD_DOWN
Common::KEYCODE_INVALID, // KEYCODE_DPAD_LEFT
Common::KEYCODE_INVALID, // KEYCODE_DPAD_RIGHT
Common::KEYCODE_INVALID, // KEYCODE_DPAD_CENTER
Common::KEYCODE_INVALID, // KEYCODE_VOLUME_UP
Common::KEYCODE_INVALID, // KEYCODE_VOLUME_DOWN
Common::KEYCODE_INVALID, // KEYCODE_POWER
Common::KEYCODE_INVALID, // KEYCODE_CAMERA
Common::KEYCODE_INVALID, // KEYCODE_CLEAR
Common::KEYCODE_a, // KEYCODE_A
Common::KEYCODE_b, // KEYCODE_B
Common::KEYCODE_c, // KEYCODE_C
Common::KEYCODE_d, // KEYCODE_D
Common::KEYCODE_e, // KEYCODE_E
Common::KEYCODE_f, // KEYCODE_F
Common::KEYCODE_g, // KEYCODE_G
Common::KEYCODE_h, // KEYCODE_H
Common::KEYCODE_i, // KEYCODE_I
Common::KEYCODE_j, // KEYCODE_J
Common::KEYCODE_k, // KEYCODE_K
Common::KEYCODE_l, // KEYCODE_L
Common::KEYCODE_m, // KEYCODE_M
Common::KEYCODE_n, // KEYCODE_N
Common::KEYCODE_o, // KEYCODE_O
Common::KEYCODE_p, // KEYCODE_P
Common::KEYCODE_q, // KEYCODE_Q
Common::KEYCODE_r, // KEYCODE_R
Common::KEYCODE_s, // KEYCODE_S
Common::KEYCODE_t, // KEYCODE_T
Common::KEYCODE_u, // KEYCODE_U
Common::KEYCODE_v, // KEYCODE_V
Common::KEYCODE_w, // KEYCODE_W
Common::KEYCODE_x, // KEYCODE_X
Common::KEYCODE_y, // KEYCODE_Y
Common::KEYCODE_z, // KEYCODE_Z
Common::KEYCODE_COMMA, // KEYCODE_COMMA
Common::KEYCODE_PERIOD, // KEYCODE_PERIOD
Common::KEYCODE_LALT, // KEYCODE_ALT_LEFT
Common::KEYCODE_RALT, // KEYCODE_ALT_RIGHT
Common::KEYCODE_LSHIFT, // KEYCODE_SHIFT_LEFT
Common::KEYCODE_RSHIFT, // KEYCODE_SHIFT_RIGHT
Common::KEYCODE_TAB, // KEYCODE_TAB
Common::KEYCODE_SPACE, // KEYCODE_SPACE
Common::KEYCODE_LCTRL, // KEYCODE_SYM
Common::KEYCODE_INVALID, // KEYCODE_EXPLORER
Common::KEYCODE_INVALID, // KEYCODE_ENVELOPE
Common::KEYCODE_RETURN, // KEYCODE_ENTER
Common::KEYCODE_BACKSPACE, // KEYCODE_DEL
Common::KEYCODE_BACKQUOTE, // KEYCODE_GRAVE
Common::KEYCODE_MINUS, // KEYCODE_MINUS
Common::KEYCODE_EQUALS, // KEYCODE_EQUALS
Common::KEYCODE_LEFTPAREN, // KEYCODE_LEFT_BRACKET
Common::KEYCODE_RIGHTPAREN, // KEYCODE_RIGHT_BRACKET
Common::KEYCODE_BACKSLASH, // KEYCODE_BACKSLASH
Common::KEYCODE_SEMICOLON, // KEYCODE_SEMICOLON
Common::KEYCODE_QUOTE, // KEYCODE_APOSTROPHE
Common::KEYCODE_SLASH, // KEYCODE_SLASH
Common::KEYCODE_AT, // KEYCODE_AT
Common::KEYCODE_INVALID, // KEYCODE_NUM
Common::KEYCODE_INVALID, // KEYCODE_HEADSETHOOK
Common::KEYCODE_INVALID, // KEYCODE_FOCUS
Common::KEYCODE_PLUS, // KEYCODE_PLUS
Common::KEYCODE_INVALID, // KEYCODE_MENU
Common::KEYCODE_INVALID, // KEYCODE_NOTIFICATION
Common::KEYCODE_INVALID, // KEYCODE_SEARCH
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PLAY_PAUSE
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_STOP
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_NEXT
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_PREVIOUS
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_REWIND
Common::KEYCODE_INVALID, // KEYCODE_MEDIA_FAST_FORWARD
Common::KEYCODE_INVALID, // KEYCODE_MUTE
Common::KEYCODE_PAGEUP, // KEYCODE_PAGE_UP
Common::KEYCODE_PAGEDOWN // KEYCODE_PAGE_DOWN
};
// floating point. use sparingly
template <class T>
static inline T scalef(T in, float numerator, float denominator) {
return static_cast<float>(in) * numerator / denominator;
}
void OSystem_Android::setupKeymapper() {
#ifdef ENABLE_KEYMAPPER
using namespace Common;
Keymapper *mapper = getEventManager()->getKeymapper();
HardwareKeySet *keySet = new HardwareKeySet();
keySet->addHardwareKey(
new HardwareKey("n", KeyState(KEYCODE_n), "n (vk)",
kTriggerLeftKeyType,
kVirtualKeyboardActionType));
mapper->registerHardwareKeySet(keySet);
Keymap *globalMap = new Keymap("global");
Action *act;
act = new Action(globalMap, "VIRT", "Display keyboard",
kVirtualKeyboardActionType);
act->addKeyEvent(KeyState(KEYCODE_F7, ASCII_F7, 0));
mapper->addGlobalKeymap(globalMap);
mapper->pushKeymap("global");
#endif
}
void OSystem_Android::warpMouse(int x, int y) {
ENTER("%d, %d", x, y);
Common::Event e;
e.type = Common::EVENT_MOUSEMOVE;
e.mouse.x = x;
e.mouse.y = y;
clipMouse(e.mouse);
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
void OSystem_Android::clipMouse(Common::Point &p) {
const GLESBaseTexture *tex;
if (_show_overlay)
tex = _overlay_texture;
else
tex = _game_texture;
p.x = CLIP(p.x, int16(0), int16(tex->width()));
p.y = CLIP(p.y, int16(0), int16(tex->height()));
}
void OSystem_Android::scaleMouse(Common::Point &p, int x, int y,
bool deductDrawRect) {
const GLESBaseTexture *tex;
if (_show_overlay)
tex = _overlay_texture;
else
tex = _game_texture;
const Common::Rect &r = tex->getDrawRect();
if (_touchpad_mode) {
x = x * 100 / _touchpad_scale;
y = y * 100 / _touchpad_scale;
}
if (deductDrawRect) {
x -= r.left;
y -= r.top;
}
p.x = scalef(x, tex->width(), r.width());
p.y = scalef(y, tex->height(), r.height());
}
void OSystem_Android::updateEventScale() {
const GLESBaseTexture *tex;
if (_show_overlay)
tex = _overlay_texture;
else
tex = _game_texture;
_eventScaleY = 100 * 480 / tex->height();
_eventScaleX = 100 * 640 / tex->width();
}
void OSystem_Android::pushEvent(int type, int arg1, int arg2, int arg3,
int arg4, int arg5) {
Common::Event e;
switch (type) {
case JE_SYS_KEY:
switch (arg1) {
case JACTION_DOWN:
e.type = Common::EVENT_KEYDOWN;
break;
case JACTION_UP:
e.type = Common::EVENT_KEYUP;
break;
default:
LOGE("unhandled jaction on system key: %d", arg1);
return;
}
switch (arg2) {
case JKEYCODE_BACK:
e.kbd.keycode = Common::KEYCODE_ESCAPE;
e.kbd.ascii = Common::ASCII_ESCAPE;
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
return;
// special case. we'll only get it's up event
case JKEYCODE_MENU:
e.type = Common::EVENT_MAINMENU;
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
return;
default:
LOGW("unmapped system key: %d", arg2);
return;
}
break;
case JE_KEY:
// five-way first
switch (arg2) {
case JKEYCODE_DPAD_UP:
case JKEYCODE_DPAD_DOWN:
case JKEYCODE_DPAD_LEFT:
case JKEYCODE_DPAD_RIGHT:
{
if (arg1 != JACTION_DOWN)
return;
e.type = Common::EVENT_MOUSEMOVE;
e.synthetic = true;
e.mouse = getEventManager()->getMousePos();
int16 *c;
int s;
if (arg2 == JKEYCODE_DPAD_UP || arg2 == JKEYCODE_DPAD_DOWN) {
c = &e.mouse.y;
s = _eventScaleY;
} else {
c = &e.mouse.x;
s = _eventScaleX;
}
// the longer the button held, the faster the pointer is
// TODO put these values in some option dlg?
int f = CLIP(arg5, 1, 8) * _dpad_scale * 100 / s;
*c += ((arg2 == JKEYCODE_DPAD_UP ||
arg2 == JKEYCODE_DPAD_LEFT) ? -1 : 1) * f;
clipMouse(e.mouse);
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
return;
case JKEYCODE_DPAD_CENTER:
switch (arg1) {
case JACTION_DOWN:
e.type = Common::EVENT_LBUTTONDOWN;
break;
case JACTION_UP:
e.type = Common::EVENT_LBUTTONUP;
break;
default:
LOGE("unhandled jaction on dpad key: %d", arg1);
return;
}
{
const Common::Point &m = getEventManager()->getMousePos();
e.mouse = m;
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
return;
}
switch (arg1) {
case JACTION_DOWN:
e.type = Common::EVENT_KEYDOWN;
break;
case JACTION_UP:
e.type = Common::EVENT_KEYUP;
break;
default:
LOGE("unhandled jaction on key: %d", arg1);
return;
}
if (arg2 < 1 || arg2 > ARRAYSIZE(jkeymap)) {
LOGE("received invalid keycode: %d", arg2);
return;
}
if (arg5 > 0)
e.synthetic = true;
e.kbd.keycode = jkeymap[arg2];
e.kbd.ascii = arg3;
if (arg4 & JMETA_SHIFT)
e.kbd.flags |= Common::KBD_SHIFT;
if (arg4 & JMETA_ALT)
e.kbd.flags |= Common::KBD_ALT;
if (arg4 & (JMETA_SYM | JMETA_CTRL))
e.kbd.flags |= Common::KBD_CTRL;
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
return;
case JE_DOWN:
_touch_pt_down = getEventManager()->getMousePos();
break;
case JE_SCROLL:
e.type = Common::EVENT_MOUSEMOVE;
if (_touchpad_mode) {
scaleMouse(e.mouse, arg3 - arg1, arg4 - arg2, false);
e.mouse += _touch_pt_down;
clipMouse(e.mouse);
} else {
scaleMouse(e.mouse, arg3, arg4);
clipMouse(e.mouse);
}
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
return;
case JE_TAP:
e.type = Common::EVENT_MOUSEMOVE;
if (_touchpad_mode) {
e.mouse = getEventManager()->getMousePos();
} else {
scaleMouse(e.mouse, arg1, arg2);
clipMouse(e.mouse);
}
{
Common::EventType down, up;
// TODO put these values in some option dlg?
if (arg3 > 1000) {
down = Common::EVENT_MBUTTONDOWN;
up = Common::EVENT_MBUTTONUP;
} else if (arg3 > 500) {
down = Common::EVENT_RBUTTONDOWN;
up = Common::EVENT_RBUTTONUP;
} else {
down = Common::EVENT_LBUTTONDOWN;
up = Common::EVENT_LBUTTONUP;
}
lockMutex(_event_queue_lock);
if (!_touchpad_mode)
_event_queue.push(e);
e.type = down;
_event_queue.push(e);
e.type = up;
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
return;
case JE_DOUBLE_TAP:
e.type = Common::EVENT_MOUSEMOVE;
if (_touchpad_mode) {
e.mouse = getEventManager()->getMousePos();
} else {
scaleMouse(e.mouse, arg1, arg2);
clipMouse(e.mouse);
}
{
Common::EventType dptype = Common::EVENT_INVALID;
switch (arg3) {
case JACTION_DOWN:
dptype = Common::EVENT_LBUTTONDOWN;
_touch_pt_dt.x = arg1;
_touch_pt_dt.y = arg2;
break;
case JACTION_UP:
dptype = Common::EVENT_LBUTTONUP;
break;
case JACTION_MULTIPLE:
// held and moved
dptype = Common::EVENT_MOUSEMOVE;
if (_touchpad_mode) {
scaleMouse(e.mouse, arg1 - _touch_pt_dt.x,
arg2 - _touch_pt_dt.y, false);
e.mouse += _touch_pt_down;
clipMouse(e.mouse);
}
break;
default:
LOGE("unhandled jaction on double tap: %d", arg3);
return;
}
lockMutex(_event_queue_lock);
_event_queue.push(e);
e.type = dptype;
_event_queue.push(e);
unlockMutex(_event_queue_lock);
}
return;
case JE_BALL:
e.type = Common::EVENT_MOUSEMOVE;
e.mouse = getEventManager()->getMousePos();
// already multiplied by 100
e.mouse.x += arg1 * _trackball_scale / _eventScaleX;
e.mouse.y += arg2 * _trackball_scale / _eventScaleY;
clipMouse(e.mouse);
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
return;
case JE_QUIT:
e.type = Common::EVENT_QUIT;
lockMutex(_event_queue_lock);
_event_queue.push(e);
unlockMutex(_event_queue_lock);
return;
default:
LOGE("unknown jevent type: %d", type);
break;
}
}
bool OSystem_Android::pollEvent(Common::Event &event) {
//ENTER();
if (pthread_self() == _main_thread) {
if (_screen_changeid != JNI::surface_changeid) {
if (JNI::egl_surface_width > 0 && JNI::egl_surface_height > 0) {
if (_egl_surface_width > 0 && _egl_surface_height > 0) {
// surface still alive but changed
_screen_changeid = JNI::surface_changeid;
_egl_surface_width = JNI::egl_surface_width;
_egl_surface_height = JNI::egl_surface_height;
initViewport();
updateScreenRect();
updateEventScale();
// double buffered, flip twice
clearScreen(kClearUpdate, 2);
event.type = Common::EVENT_SCREEN_CHANGED;
return true;
} else {
// new surface
initSurface();
updateScreenRect();
updateEventScale();
// double buffered, flip twice
clearScreen(kClearUpdate, 2);
event.type = Common::EVENT_SCREEN_CHANGED;
return true;
}
} else {
// surface lost
deinitSurface();
}
}
if (JNI::pause) {
deinitSurface();
LOGD("main thread going to sleep");
sem_wait(&JNI::pause_sem);
LOGD("main thread woke up");
}
}
lockMutex(_event_queue_lock);
if (_event_queue.empty()) {
unlockMutex(_event_queue_lock);
return false;
}
event = _event_queue.pop();
unlockMutex(_event_queue_lock);
if (event.type == Common::EVENT_MOUSEMOVE) {
const Common::Point &m = getEventManager()->getMousePos();
if (m != event.mouse)
_force_redraw = true;
}
return true;
}
#endif

View file

@ -272,6 +272,7 @@ void OSystem_Android::initSize(uint width, uint height,
#endif
updateScreenRect();
updateEventScale();
// Don't know mouse size yet - it gets reallocated in
// setMouseCursor. We need the palette allocated before
@ -285,17 +286,13 @@ void OSystem_Android::initSize(uint width, uint height,
void OSystem_Android::clearScreen(FixupType type, byte count) {
assert(count > 0);
for (byte i = 0; i < count; ++i) {
if (!_show_overlay)
GLCALL(glDisable(GL_SCISSOR_TEST));
for (byte i = 0; i < count; ++i) {
// clear screen
GLCALL(glClearColorx(0, 0, 0, 1 << 16));
GLCALL(glClear(GL_COLOR_BUFFER_BIT));
if (!_show_overlay)
GLCALL(glEnable(GL_SCISSOR_TEST));
switch (type) {
case kClear:
break;
@ -310,6 +307,9 @@ void OSystem_Android::clearScreen(FixupType type, byte count) {
break;
}
}
if (!_show_overlay)
GLCALL(glEnable(GL_SCISSOR_TEST));
}
void OSystem_Android::updateScreenRect() {
@ -577,34 +577,27 @@ void OSystem_Android::clearFocusRectangle() {
void OSystem_Android::showOverlay() {
ENTER();
Common::Event e;
e.type = Common::EVENT_MOUSEMOVE;
e.mouse.x = _egl_surface_width / 2;
e.mouse.y = _egl_surface_height / 2;
pushEvent(e);
_show_overlay = true;
_force_redraw = true;
updateEventScale();
warpMouse(_overlay_texture->width() / 2, _overlay_texture->height() / 2);
GLCALL(glDisable(GL_SCISSOR_TEST));
}
void OSystem_Android::hideOverlay() {
ENTER();
Common::Event e;
e.type = Common::EVENT_MOUSEMOVE;
e.mouse.x = _egl_surface_width / 2;
e.mouse.y = _egl_surface_height / 2;
pushEvent(e);
clearScreen(kClear);
_show_overlay = false;
_force_redraw = true;
// double buffered, flip twice
clearScreen(kClearUpdate, 2);
updateEventScale();
warpMouse(_game_texture->width() / 2, _game_texture->height() / 2);
GLCALL(glEnable(GL_SCISSOR_TEST));
}
@ -673,13 +666,6 @@ bool OSystem_Android::showMouse(bool visible) {
return true;
}
void OSystem_Android::warpMouse(int x, int y) {
ENTER("%d, %d", x, y);
// We use only the eventmanager's idea of the current mouse
// position, so there is nothing extra to do here.
}
void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h,
int hotspotX, int hotspotY,
uint32 keycolor, int cursorTargetScale,
@ -719,8 +705,10 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h,
WRITE_UINT16(_mouse_texture_palette->palette() + keycolor * 2, 0);
}
if (w == 0 || h == 0)
if (w == 0 || h == 0) {
_show_mouse = false;
return;
}
if (_mouse_texture == _mouse_texture_palette) {
_mouse_texture->updateBuffer(0, 0, w, h, buf, w);
@ -737,7 +725,7 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h,
delete[] tmp;
_mouse_texture->fillBuffer(0);
_show_mouse = false;
return;
}

View file

@ -56,15 +56,6 @@ int JNI::egl_surface_width = 0;
int JNI::egl_surface_height = 0;
bool JNI::_ready_for_events = 0;
jfieldID JNI::_FID_Event_type = 0;
jfieldID JNI::_FID_Event_synthetic = 0;
jfieldID JNI::_FID_Event_kbd_keycode = 0;
jfieldID JNI::_FID_Event_kbd_ascii = 0;
jfieldID JNI::_FID_Event_kbd_flags = 0;
jfieldID JNI::_FID_Event_mouse_x = 0;
jfieldID JNI::_FID_Event_mouse_y = 0;
jfieldID JNI::_FID_Event_mouse_relative = 0;
jmethodID JNI::_MID_getDPI = 0;
jmethodID JNI::_MID_displayMessageOnOSD = 0;
jmethodID JNI::_MID_setWindowCaption = 0;
@ -94,7 +85,7 @@ const JNINativeMethod JNI::_natives[] = {
(void *)JNI::setSurface },
{ "main", "([Ljava/lang/String;)I",
(void *)JNI::main },
{ "pushEvent", "(Lorg/inodes/gus/scummvm/Event;)V",
{ "pushEvent", "(IIIIII)V",
(void *)JNI::pushEvent },
{ "enableZoning", "(Z)V",
(void *)JNI::enableZoning },
@ -123,42 +114,6 @@ jint JNI::onLoad(JavaVM *vm) {
if (env->RegisterNatives(cls, _natives, ARRAYSIZE(_natives)) < 0)
return JNI_ERR;
jclass event = env->FindClass("org/inodes/gus/scummvm/Event");
if (event == 0)
return JNI_ERR;
_FID_Event_type = env->GetFieldID(event, "type", "I");
if (_FID_Event_type == 0)
return JNI_ERR;
_FID_Event_synthetic = env->GetFieldID(event, "synthetic", "Z");
if (_FID_Event_synthetic == 0)
return JNI_ERR;
_FID_Event_kbd_keycode = env->GetFieldID(event, "kbd_keycode", "I");
if (_FID_Event_kbd_keycode == 0)
return JNI_ERR;
_FID_Event_kbd_ascii = env->GetFieldID(event, "kbd_ascii", "I");
if (_FID_Event_kbd_ascii == 0)
return JNI_ERR;
_FID_Event_kbd_flags = env->GetFieldID(event, "kbd_flags", "I");
if (_FID_Event_kbd_flags == 0)
return JNI_ERR;
_FID_Event_mouse_x = env->GetFieldID(event, "mouse_x", "I");
if (_FID_Event_mouse_x == 0)
return JNI_ERR;
_FID_Event_mouse_y = env->GetFieldID(event, "mouse_y", "I");
if (_FID_Event_mouse_y == 0)
return JNI_ERR;
_FID_Event_mouse_relative = env->GetFieldID(event, "mouse_relative", "Z");
if (_FID_Event_mouse_relative == 0)
return JNI_ERR;
return JNI_VERSION_1_2;
}
@ -600,54 +555,17 @@ cleanup:
return res;
}
void JNI::pushEvent(JNIEnv *env, jobject self, jobject java_event) {
void JNI::pushEvent(JNIEnv *env, jobject self, int type, int arg1, int arg2,
int arg3, int arg4, int arg5) {
// drop events until we're ready and after we quit
if (!_ready_for_events)
if (!_ready_for_events) {
LOGW("dropping event");
return;
}
assert(_system);
Common::Event event;
event.type = (Common::EventType)env->GetIntField(java_event,
_FID_Event_type);
event.synthetic =
env->GetBooleanField(java_event, _FID_Event_synthetic);
switch (event.type) {
case Common::EVENT_KEYDOWN:
case Common::EVENT_KEYUP:
event.kbd.keycode = (Common::KeyCode)env->GetIntField(
java_event, _FID_Event_kbd_keycode);
event.kbd.ascii = static_cast<int>(env->GetIntField(
java_event, _FID_Event_kbd_ascii));
event.kbd.flags = static_cast<int>(env->GetIntField(
java_event, _FID_Event_kbd_flags));
break;
case Common::EVENT_MOUSEMOVE:
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_WHEELUP:
case Common::EVENT_WHEELDOWN:
case Common::EVENT_MBUTTONDOWN:
case Common::EVENT_MBUTTONUP:
event.mouse.x =
env->GetIntField(java_event, _FID_Event_mouse_x);
event.mouse.y =
env->GetIntField(java_event, _FID_Event_mouse_y);
// This is a terrible hack. We stash "relativeness"
// in the kbd.flags field until pollEvent() can work
// it out.
event.kbd.flags = env->GetBooleanField(
java_event, _FID_Event_mouse_relative) ? 1 : 0;
break;
default:
break;
}
_system->pushEvent(event);
_system->pushEvent(type, arg1, arg2, arg3, arg4, arg5);
}
void JNI::enableZoning(JNIEnv *env, jobject self, jboolean enable) {

View file

@ -91,16 +91,6 @@ private:
static bool _ready_for_events;
static jfieldID _FID_Event_type;
static jfieldID _FID_Event_synthetic;
static jfieldID _FID_Event_kbd_keycode;
static jfieldID _FID_Event_kbd_ascii;
static jfieldID _FID_Event_kbd_flags;
static jfieldID _FID_Event_mouse_x;
static jfieldID _FID_Event_mouse_y;
static jfieldID _FID_Event_mouse_relative;
static jfieldID _FID_ScummVM_nativeScummVM;
static jmethodID _MID_getDPI;
static jmethodID _MID_displayMessageOnOSD;
static jmethodID _MID_setWindowCaption;
@ -133,7 +123,8 @@ private:
static void setSurface(JNIEnv *env, jobject self, jint width, jint height);
static jint main(JNIEnv *env, jobject self, jobjectArray args);
static void pushEvent(JNIEnv *env, jobject self, jobject java_event);
static void pushEvent(JNIEnv *env, jobject self, int type, int arg1,
int arg2, int arg3, int arg4, int arg5);
static void enableZoning(JNIEnv *env, jobject self, jboolean enable);
static void setPause(JNIEnv *env, jobject self, jboolean value);

View file

@ -5,7 +5,8 @@ MODULE_OBJS := \
texture.o \
asset-archive.o \
android.o \
gfx.o
gfx.o \
events.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))

View file

@ -1,330 +0,0 @@
package org.inodes.gus.scummvm;
import android.view.KeyEvent;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class Event {
// Common::EventType enum.
// Must be kept in sync with common/events.h
public final static int EVENT_INVALID = 0;
public final static int EVENT_KEYDOWN = 1;
public final static int EVENT_KEYUP = 2;
public final static int EVENT_MOUSEMOVE = 3;
public final static int EVENT_LBUTTONDOWN = 4;
public final static int EVENT_LBUTTONUP = 5;
public final static int EVENT_RBUTTONDOWN = 6;
public final static int EVENT_RBUTTONUP = 7;
public final static int EVENT_WHEELUP = 8;
public final static int EVENT_WHEELDOWN = 9;
public final static int EVENT_QUIT = 10;
public final static int EVENT_SCREEN_CHANGED = 11;
public final static int EVENT_PREDICTIVE_DIALOG = 12;
public final static int EVENT_MBUTTONDOWN = 13;
public final static int EVENT_MBUTTONUP = 14;
public final static int EVENT_MAINMENU = 15;
public final static int EVENT_RTL = 16;
// common/keyboard.h
public final static int ASCII_F1 = 315;
public final static int ASCII_F2 = 316;
public final static int ASCII_F3 = 317;
public final static int ASCII_F4 = 318;
public final static int ASCII_F5 = 319;
public final static int ASCII_F6 = 320;
public final static int ASCII_F7 = 321;
public final static int ASCII_F8 = 322;
public final static int ASCII_F9 = 323;
public final static int ASCII_F10 = 324;
public final static int ASCII_F11 = 325;
public final static int ASCII_F12 = 326;
public final static int KBD_CTRL = 1 << 0;
public final static int KBD_ALT = 1 << 1;
public final static int KBD_SHIFT = 1 << 2;
public final static int KEYCODE_INVALID = 0;
public final static int KEYCODE_BACKSPACE = 8;
public final static int KEYCODE_TAB = 9;
public final static int KEYCODE_CLEAR = 12;
public final static int KEYCODE_RETURN = 13;
public final static int KEYCODE_PAUSE = 19;
public final static int KEYCODE_ESCAPE = 27;
public final static int KEYCODE_SPACE = 32;
public final static int KEYCODE_EXCLAIM = 33;
public final static int KEYCODE_QUOTEDBL = 34;
public final static int KEYCODE_HASH = 35;
public final static int KEYCODE_DOLLAR = 36;
public final static int KEYCODE_AMPERSAND = 38;
public final static int KEYCODE_QUOTE = 39;
public final static int KEYCODE_LEFTPAREN = 40;
public final static int KEYCODE_RIGHTPAREN = 41;
public final static int KEYCODE_ASTERISK = 42;
public final static int KEYCODE_PLUS = 43;
public final static int KEYCODE_COMMA = 44;
public final static int KEYCODE_MINUS = 45;
public final static int KEYCODE_PERIOD = 46;
public final static int KEYCODE_SLASH = 47;
public final static int KEYCODE_0 = 48;
public final static int KEYCODE_1 = 49;
public final static int KEYCODE_2 = 50;
public final static int KEYCODE_3 = 51;
public final static int KEYCODE_4 = 52;
public final static int KEYCODE_5 = 53;
public final static int KEYCODE_6 = 54;
public final static int KEYCODE_7 = 55;
public final static int KEYCODE_8 = 56;
public final static int KEYCODE_9 = 57;
public final static int KEYCODE_COLON = 58;
public final static int KEYCODE_SEMICOLON = 59;
public final static int KEYCODE_LESS = 60;
public final static int KEYCODE_EQUALS = 61;
public final static int KEYCODE_GREATER = 62;
public final static int KEYCODE_QUESTION = 63;
public final static int KEYCODE_AT = 64;
public final static int KEYCODE_LEFTBRACKET = 91;
public final static int KEYCODE_BACKSLASH = 92;
public final static int KEYCODE_RIGHTBRACKET = 93;
public final static int KEYCODE_CARET = 94;
public final static int KEYCODE_UNDERSCORE = 95;
public final static int KEYCODE_BACKQUOTE = 96;
public final static int KEYCODE_a = 97;
public final static int KEYCODE_b = 98;
public final static int KEYCODE_c = 99;
public final static int KEYCODE_d = 100;
public final static int KEYCODE_e = 101;
public final static int KEYCODE_f = 102;
public final static int KEYCODE_g = 103;
public final static int KEYCODE_h = 104;
public final static int KEYCODE_i = 105;
public final static int KEYCODE_j = 106;
public final static int KEYCODE_k = 107;
public final static int KEYCODE_l = 108;
public final static int KEYCODE_m = 109;
public final static int KEYCODE_n = 110;
public final static int KEYCODE_o = 111;
public final static int KEYCODE_p = 112;
public final static int KEYCODE_q = 113;
public final static int KEYCODE_r = 114;
public final static int KEYCODE_s = 115;
public final static int KEYCODE_t = 116;
public final static int KEYCODE_u = 117;
public final static int KEYCODE_v = 118;
public final static int KEYCODE_w = 119;
public final static int KEYCODE_x = 120;
public final static int KEYCODE_y = 121;
public final static int KEYCODE_z = 122;
public final static int KEYCODE_DELETE = 127;
// Numeric keypad
public final static int KEYCODE_KP0 = 256;
public final static int KEYCODE_KP1 = 257;
public final static int KEYCODE_KP2 = 258;
public final static int KEYCODE_KP3 = 259;
public final static int KEYCODE_KP4 = 260;
public final static int KEYCODE_KP5 = 261;
public final static int KEYCODE_KP6 = 262;
public final static int KEYCODE_KP7 = 263;
public final static int KEYCODE_KP8 = 264;
public final static int KEYCODE_KP9 = 265;
public final static int KEYCODE_KP_PERIOD = 266;
public final static int KEYCODE_KP_DIVIDE = 267;
public final static int KEYCODE_KP_MULTIPLY = 268;
public final static int KEYCODE_KP_MINUS = 269;
public final static int KEYCODE_KP_PLUS = 270;
public final static int KEYCODE_KP_ENTER = 271;
public final static int KEYCODE_KP_EQUALS = 272;
// Arrows + Home/End pad
public final static int KEYCODE_UP = 273;
public final static int KEYCODE_DOWN = 274;
public final static int KEYCODE_RIGHT = 275;
public final static int KEYCODE_LEFT = 276;
public final static int KEYCODE_INSERT = 277;
public final static int KEYCODE_HOME = 278;
public final static int KEYCODE_END = 279;
public final static int KEYCODE_PAGEUP = 280;
public final static int KEYCODE_PAGEDOWN = 281;
// Function keys
public final static int KEYCODE_F1 = 282;
public final static int KEYCODE_F2 = 283;
public final static int KEYCODE_F3 = 284;
public final static int KEYCODE_F4 = 285;
public final static int KEYCODE_F5 = 286;
public final static int KEYCODE_F6 = 287;
public final static int KEYCODE_F7 = 288;
public final static int KEYCODE_F8 = 289;
public final static int KEYCODE_F9 = 290;
public final static int KEYCODE_F10 = 291;
public final static int KEYCODE_F11 = 292;
public final static int KEYCODE_F12 = 293;
public final static int KEYCODE_F13 = 294;
public final static int KEYCODE_F14 = 295;
public final static int KEYCODE_F15 = 296;
// Key state modifier keys
public final static int KEYCODE_NUMLOCK = 300;
public final static int KEYCODE_CAPSLOCK = 301;
public final static int KEYCODE_SCROLLOCK = 302;
public final static int KEYCODE_RSHIFT = 303;
public final static int KEYCODE_LSHIFT = 304;
public final static int KEYCODE_RCTRL = 305;
public final static int KEYCODE_LCTRL = 306;
public final static int KEYCODE_RALT = 307;
public final static int KEYCODE_LALT = 308;
public final static int KEYCODE_RMETA = 309;
public final static int KEYCODE_LMETA = 310;
public final static int KEYCODE_LSUPER = 311; // Left "Windows" key
public final static int KEYCODE_RSUPER = 312; // Right "Windows" key
public final static int KEYCODE_MODE = 313; // "Alt Gr" key
public final static int KEYCODE_COMPOSE = 314; // Multi-key compose key
// Miscellaneous function keys
public final static int KEYCODE_HELP = 315;
public final static int KEYCODE_PRINT = 316;
public final static int KEYCODE_SYSREQ = 317;
public final static int KEYCODE_BREAK = 318;
public final static int KEYCODE_MENU = 319;
public final static int KEYCODE_POWER = 320; // Power Macintosh power key
public final static int KEYCODE_EURO = 321; // Some european keyboards
public final static int KEYCODE_UNDO = 322; // Atari keyboard has Undo
// Android KeyEvent keycode -> ScummVM keycode
public final static Map<Integer, Integer> androidKeyMap;
static {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
map.put(KeyEvent.KEYCODE_DEL, KEYCODE_BACKSPACE);
map.put(KeyEvent.KEYCODE_TAB, KEYCODE_TAB);
map.put(KeyEvent.KEYCODE_CLEAR, KEYCODE_CLEAR);
map.put(KeyEvent.KEYCODE_ENTER, KEYCODE_RETURN);
//map.put(??, KEYCODE_PAUSE);
map.put(KeyEvent.KEYCODE_BACK, KEYCODE_ESCAPE);
map.put(KeyEvent.KEYCODE_SPACE, KEYCODE_SPACE);
//map.put(??, KEYCODE_EXCLAIM);
//map.put(??, KEYCODE_QUOTEDBL);
map.put(KeyEvent.KEYCODE_POUND, KEYCODE_HASH);
//map.put(??, KEYCODE_DOLLAR);
//map.put(??, KEYCODE_AMPERSAND);
map.put(KeyEvent.KEYCODE_APOSTROPHE, KEYCODE_QUOTE);
//map.put(??, KEYCODE_LEFTPAREN);
//map.put(??, KEYCODE_RIGHTPAREN);
//map.put(??, KEYCODE_ASTERISK);
map.put(KeyEvent.KEYCODE_PLUS, KEYCODE_PLUS);
map.put(KeyEvent.KEYCODE_COMMA, KEYCODE_COMMA);
map.put(KeyEvent.KEYCODE_MINUS, KEYCODE_MINUS);
map.put(KeyEvent.KEYCODE_PERIOD, KEYCODE_PERIOD);
map.put(KeyEvent.KEYCODE_SLASH, KEYCODE_SLASH);
map.put(KeyEvent.KEYCODE_0, KEYCODE_0);
map.put(KeyEvent.KEYCODE_1, KEYCODE_1);
map.put(KeyEvent.KEYCODE_2, KEYCODE_2);
map.put(KeyEvent.KEYCODE_3, KEYCODE_3);
map.put(KeyEvent.KEYCODE_4, KEYCODE_4);
map.put(KeyEvent.KEYCODE_5, KEYCODE_5);
map.put(KeyEvent.KEYCODE_6, KEYCODE_6);
map.put(KeyEvent.KEYCODE_7, KEYCODE_7);
map.put(KeyEvent.KEYCODE_8, KEYCODE_8);
map.put(KeyEvent.KEYCODE_9, KEYCODE_9);
//map.put(??, KEYCODE_COLON);
map.put(KeyEvent.KEYCODE_SEMICOLON, KEYCODE_SEMICOLON);
//map.put(??, KEYCODE_LESS);
map.put(KeyEvent.KEYCODE_EQUALS, KEYCODE_EQUALS);
//map.put(??, KEYCODE_GREATER);
//map.put(??, KEYCODE_QUESTION);
map.put(KeyEvent.KEYCODE_AT, KEYCODE_AT);
map.put(KeyEvent.KEYCODE_LEFT_BRACKET, KEYCODE_LEFTBRACKET);
map.put(KeyEvent.KEYCODE_BACKSLASH, KEYCODE_BACKSLASH);
map.put(KeyEvent.KEYCODE_RIGHT_BRACKET, KEYCODE_RIGHTBRACKET);
//map.put(??, KEYCODE_CARET);
//map.put(??, KEYCODE_UNDERSCORE);
//map.put(??, KEYCODE_BACKQUOTE);
map.put(KeyEvent.KEYCODE_A, KEYCODE_a);
map.put(KeyEvent.KEYCODE_B, KEYCODE_b);
map.put(KeyEvent.KEYCODE_C, KEYCODE_c);
map.put(KeyEvent.KEYCODE_D, KEYCODE_d);
map.put(KeyEvent.KEYCODE_E, KEYCODE_e);
map.put(KeyEvent.KEYCODE_F, KEYCODE_f);
map.put(KeyEvent.KEYCODE_G, KEYCODE_g);
map.put(KeyEvent.KEYCODE_H, KEYCODE_h);
map.put(KeyEvent.KEYCODE_I, KEYCODE_i);
map.put(KeyEvent.KEYCODE_J, KEYCODE_j);
map.put(KeyEvent.KEYCODE_K, KEYCODE_k);
map.put(KeyEvent.KEYCODE_L, KEYCODE_l);
map.put(KeyEvent.KEYCODE_M, KEYCODE_m);
map.put(KeyEvent.KEYCODE_N, KEYCODE_n);
map.put(KeyEvent.KEYCODE_O, KEYCODE_o);
map.put(KeyEvent.KEYCODE_P, KEYCODE_p);
map.put(KeyEvent.KEYCODE_Q, KEYCODE_q);
map.put(KeyEvent.KEYCODE_R, KEYCODE_r);
map.put(KeyEvent.KEYCODE_S, KEYCODE_s);
map.put(KeyEvent.KEYCODE_T, KEYCODE_t);
map.put(KeyEvent.KEYCODE_U, KEYCODE_u);
map.put(KeyEvent.KEYCODE_V, KEYCODE_v);
map.put(KeyEvent.KEYCODE_W, KEYCODE_w);
map.put(KeyEvent.KEYCODE_X, KEYCODE_x);
map.put(KeyEvent.KEYCODE_Y, KEYCODE_y);
map.put(KeyEvent.KEYCODE_Z, KEYCODE_z);
//map.put(KeyEvent.KEYCODE_DEL, KEYCODE_DELETE); use BACKSPACE instead
//map.put(??, KEYCODE_KP_*);
map.put(KeyEvent.KEYCODE_DPAD_UP, KEYCODE_UP);
map.put(KeyEvent.KEYCODE_DPAD_DOWN, KEYCODE_DOWN);
map.put(KeyEvent.KEYCODE_DPAD_RIGHT, KEYCODE_RIGHT);
map.put(KeyEvent.KEYCODE_DPAD_LEFT, KEYCODE_LEFT);
//map.put(??, KEYCODE_INSERT);
//map.put(??, KEYCODE_HOME);
//map.put(??, KEYCODE_END);
//map.put(??, KEYCODE_PAGEUP);
//map.put(??, KEYCODE_PAGEDOWN);
//map.put(??, KEYCODE_F{1-15});
map.put(KeyEvent.KEYCODE_NUM, KEYCODE_NUMLOCK);
//map.put(??, KEYCODE_CAPSLOCK);
//map.put(??, KEYCODE_SCROLLLOCK);
map.put(KeyEvent.KEYCODE_SHIFT_RIGHT, KEYCODE_RSHIFT);
map.put(KeyEvent.KEYCODE_SHIFT_LEFT, KEYCODE_LSHIFT);
//map.put(??, KEYCODE_RCTRL);
//map.put(??, KEYCODE_LCTRL);
map.put(KeyEvent.KEYCODE_ALT_RIGHT, KEYCODE_RALT);
map.put(KeyEvent.KEYCODE_ALT_LEFT, KEYCODE_LALT);
// ?? META, SUPER
// ?? MODE, COMPOSE
// ?? HELP, PRINT, SYSREQ, BREAK, EURO, UNDO
map.put(KeyEvent.KEYCODE_MENU, KEYCODE_MENU);
map.put(KeyEvent.KEYCODE_POWER, KEYCODE_POWER);
androidKeyMap = Collections.unmodifiableMap(map);
}
public int type;
public boolean synthetic;
public int kbd_keycode;
public int kbd_ascii;
public int kbd_flags;
public int mouse_x;
public int mouse_y;
public boolean mouse_relative; // Used for trackball events
public Event() {
type = EVENT_INVALID;
synthetic = false;
}
public Event(int type) {
this.type = type;
synthetic = false;
}
public static Event KeyboardEvent(int type, int keycode, int ascii,
int flags) {
Event e = new Event();
e.type = type;
e.kbd_keycode = keycode;
e.kbd_ascii = ascii;
e.kbd_flags = flags;
return e;
}
public static Event MouseEvent(int type, int x, int y) {
Event e = new Event();
e.type = type;
e.mouse_x = x;
e.mouse_y = y;
return e;
}
}

View file

@ -9,14 +9,12 @@ import android.media.AudioTrack;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGL11;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import java.io.File;
import java.util.Map;
import java.util.LinkedHashMap;
public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
@ -49,7 +47,8 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
final public native void setPause(boolean pause);
final public native void enableZoning(boolean enable);
// Feed an event to ScummVM. Safe to call from other threads.
final public native void pushEvent(Event e);
final public native void pushEvent(int type, int arg1, int arg2, int arg3,
int arg4, int arg5);
// Callbacks from C++ peer instance
abstract protected void getDPI(float[] values);

View file

@ -3,33 +3,18 @@ package org.inodes.gus.scummvm;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.MotionEvent;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import java.io.IOException;
public class ScummVMActivity extends Activity {
private boolean _do_right_click;
private boolean _last_click_was_right;
// game pixels to move per trackball/dpad event.
// FIXME: replace this with proper mouse acceleration
private final static int TRACKBALL_SCALE = 2;
private class MyScummVM extends ScummVM {
private boolean usingSmallScreen() {
@ -106,13 +91,13 @@ public class ScummVMActivity extends Activity {
}
private MyScummVM _scummvm;
private ScummVMEvents _events;
private Thread _scummvm_thread;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
_do_right_click = false;
setVolumeControlStream(AudioManager.STREAM_MUSIC);
setContentView(R.layout.main);
@ -139,18 +124,6 @@ public class ScummVMActivity extends Activity {
SurfaceView main_surface = (SurfaceView)findViewById(R.id.main_surface);
main_surface.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return onTouchEvent(event);
}
});
main_surface.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int code, KeyEvent ev) {
return onKeyDown(code, ev);
}
});
main_surface.requestFocus();
getFilesDir().mkdirs();
@ -166,6 +139,11 @@ public class ScummVMActivity extends Activity {
"--savepath=" + getDir("saves", 0).getPath()
});
_events = new ScummVMEvents(this, _scummvm);
main_surface.setOnKeyListener(_events);
main_surface.setOnTouchListener(_events);
_scummvm_thread = new Thread(_scummvm, "ScummVM");
_scummvm_thread.start();
}
@ -210,8 +188,8 @@ public class ScummVMActivity extends Activity {
super.onDestroy();
if (_scummvm != null) {
_scummvm.pushEvent(new Event(Event.EVENT_QUIT));
if (_events != null) {
_events.sendQuitEvent();
try {
// 1s timeout
@ -224,259 +202,12 @@ public class ScummVMActivity extends Activity {
}
}
static final int MSG_MENU_LONG_PRESS = 1;
private final Handler keycodeMenuTimeoutHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_MENU_LONG_PRESS) {
InputMethodManager imm = (InputMethodManager)
getSystemService(INPUT_METHOD_SERVICE);
if (imm != null)
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
}
};
@Override
public boolean onKeyUp(int keyCode, KeyEvent kevent) {
return onKeyDown(keyCode, kevent);
}
@Override
public boolean onKeyMultiple(int keyCode, int repeatCount,
KeyEvent kevent) {
return onKeyDown(keyCode, kevent);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent kevent) {
// Filter out "special" keys
switch (keyCode) {
case KeyEvent.KEYCODE_MENU:
// Have to reimplement hold-down-menu-brings-up-softkeybd
// ourselves, since we are otherwise hijacking the menu key :(
// See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel()
// for the usual Android implementation of this feature.
// Ignore keyrepeat for menu
if (kevent.getRepeatCount() > 0)
return false;
boolean timeout_fired = !keycodeMenuTimeoutHandler.hasMessages(MSG_MENU_LONG_PRESS);
keycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
if (kevent.getAction() == KeyEvent.ACTION_DOWN) {
keycodeMenuTimeoutHandler.sendMessageDelayed(keycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS),
ViewConfiguration.getLongPressTimeout());
return true;
}
if (kevent.getAction() == KeyEvent.ACTION_UP) {
if (!timeout_fired)
_scummvm.pushEvent(new Event(Event.EVENT_MAINMENU));
return true;
}
public boolean onTrackballEvent(MotionEvent e) {
if (_events != null)
return _events.onTrackballEvent(e);
return false;
case KeyEvent.KEYCODE_CAMERA:
case KeyEvent.KEYCODE_SEARCH:
_do_right_click = (kevent.getAction() == KeyEvent.ACTION_DOWN);
return true;
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_DPAD_DOWN:
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT: {
// HTC Hero doesn't seem to generate
// MotionEvent.ACTION_DOWN events on trackball press :(
// We'll have to just fake one here.
// Some other handsets lack a trackball, so the DPAD is
// the only way of moving the cursor.
int motion_action;
// FIXME: this logic is a mess.
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
switch (kevent.getAction()) {
case KeyEvent.ACTION_DOWN:
motion_action = MotionEvent.ACTION_DOWN;
break;
case KeyEvent.ACTION_UP:
motion_action = MotionEvent.ACTION_UP;
break;
// ACTION_MULTIPLE
default:
return false;
}
} else {
motion_action = MotionEvent.ACTION_MOVE;
}
Event e = new Event(getEventType(motion_action));
e.mouse_x = 0;
e.mouse_y = 0;
e.mouse_relative = true;
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
e.mouse_y = -TRACKBALL_SCALE;
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
e.mouse_y = TRACKBALL_SCALE;
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
e.mouse_x = -TRACKBALL_SCALE;
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
e.mouse_x = TRACKBALL_SCALE;
break;
}
_scummvm.pushEvent(e);
return true;
}
case KeyEvent.KEYCODE_BACK:
// skip isSystem() check and fall through to main code
break;
default:
if (kevent.isSystem())
return false;
}
// FIXME: what do I need to do for composed characters?
Event e = new Event();
switch (kevent.getAction()) {
case KeyEvent.ACTION_DOWN:
e.type = Event.EVENT_KEYDOWN;
e.synthetic = false;
break;
case KeyEvent.ACTION_UP:
e.type = Event.EVENT_KEYUP;
e.synthetic = false;
break;
case KeyEvent.ACTION_MULTIPLE:
// e.type is handled below
e.synthetic = true;
break;
default:
return false;
}
e.kbd_keycode = Event.androidKeyMap.containsKey(keyCode) ?
Event.androidKeyMap.get(keyCode) : Event.KEYCODE_INVALID;
e.kbd_ascii = kevent.getUnicodeChar();
if (e.kbd_ascii == 0)
e.kbd_ascii = e.kbd_keycode; // scummvm keycodes are mostly ascii
e.kbd_flags = 0;
if (kevent.isAltPressed())
e.kbd_flags |= Event.KBD_ALT;
// no ctrl key in android, so use sym (?)
if (kevent.isSymPressed())
e.kbd_flags |= Event.KBD_CTRL;
if (kevent.isShiftPressed()) {
if (keyCode >= KeyEvent.KEYCODE_0 &&
keyCode <= KeyEvent.KEYCODE_9) {
// Shift+number -> convert to F* key
int offset = keyCode == KeyEvent.KEYCODE_0 ?
10 : keyCode - KeyEvent.KEYCODE_1; // turn 0 into 10
e.kbd_keycode = Event.KEYCODE_F1 + offset;
e.kbd_ascii = Event.ASCII_F1 + offset;
} else {
e.kbd_flags |= Event.KBD_SHIFT;
}
}
if (kevent.getAction() == KeyEvent.ACTION_MULTIPLE) {
for (int i = 0; i <= kevent.getRepeatCount(); i++) {
e.type = Event.EVENT_KEYDOWN;
_scummvm.pushEvent(e);
e.type = Event.EVENT_KEYUP;
_scummvm.pushEvent(e);
}
} else {
_scummvm.pushEvent(e);
}
return true;
}
private int getEventType(int action) {
switch (action) {
case MotionEvent.ACTION_DOWN:
_last_click_was_right = _do_right_click;
return _last_click_was_right ?
Event.EVENT_RBUTTONDOWN : Event.EVENT_LBUTTONDOWN;
case MotionEvent.ACTION_UP:
return _last_click_was_right ?
Event.EVENT_RBUTTONUP : Event.EVENT_LBUTTONUP;
case MotionEvent.ACTION_MOVE:
return Event.EVENT_MOUSEMOVE;
default:
return Event.EVENT_INVALID;
}
}
@Override
public boolean onTrackballEvent(MotionEvent event) {
int type = getEventType(event.getAction());
if (type == Event.EVENT_INVALID)
return false;
Event e = new Event(type);
e.mouse_x =
(int)(event.getX() * event.getXPrecision()) * TRACKBALL_SCALE;
e.mouse_y =
(int)(event.getY() * event.getYPrecision()) * TRACKBALL_SCALE;
e.mouse_relative = true;
_scummvm.pushEvent(e);
return true;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int type = getEventType(event.getAction());
if (type == Event.EVENT_INVALID)
return false;
Event e = new Event(type);
e.mouse_x = (int)event.getX();
e.mouse_y = (int)event.getY();
e.mouse_relative = false;
_scummvm.pushEvent(e);
return true;
}
private void showKeyboard(boolean show) {

View file

@ -0,0 +1,201 @@
package org.inodes.gus.scummvm;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.content.Context;
import android.view.KeyEvent;
import android.view.KeyCharacterMap;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.GestureDetector;
import android.view.inputmethod.InputMethodManager;
public class ScummVMEvents implements
android.view.View.OnKeyListener,
android.view.View.OnTouchListener,
android.view.GestureDetector.OnGestureListener,
android.view.GestureDetector.OnDoubleTapListener {
public static final int JE_SYS_KEY = 0;
public static final int JE_KEY = 1;
public static final int JE_DOWN = 2;
public static final int JE_SCROLL = 3;
public static final int JE_TAP = 4;
public static final int JE_DOUBLE_TAP = 5;
public static final int JE_BALL = 6;
public static final int JE_QUIT = 0x1000;
final protected Context _context;
final protected ScummVM _scummvm;
final protected GestureDetector _gd;
final protected int _longPress;
final protected int _slop;
public ScummVMEvents(Context context, ScummVM scummvm) {
_context = context;
_scummvm = scummvm;
_gd = new GestureDetector(context, this);
_gd.setOnDoubleTapListener(this);
_gd.setIsLongpressEnabled(false);
_longPress = ViewConfiguration.getLongPressTimeout();
_slop = ViewConfiguration.get(context).getScaledTouchSlop();
}
final public void sendQuitEvent() {
_scummvm.pushEvent(JE_QUIT, 0, 0, 0, 0, 0);
}
public boolean onTrackballEvent(MotionEvent e) {
_scummvm.pushEvent(JE_BALL, (int)(e.getX() * e.getXPrecision() * 100),
(int)(e.getY() * e.getYPrecision() * 100), 0, 0, 0);
return true;
}
final static int MSG_MENU_LONG_PRESS = 1;
final private Handler keyHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_MENU_LONG_PRESS) {
InputMethodManager imm = (InputMethodManager)
_context.getSystemService(_context.INPUT_METHOD_SERVICE);
if (imm != null)
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
}
};
// OnKeyListener
final public boolean onKey(View v, int keyCode, KeyEvent e) {
final int action = e.getAction();
if (e.isSystem()) {
// filter what we handle
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_MENU:
break;
default:
return false;
}
// no repeats for system keys
if (e.getRepeatCount() > 0)
return false;
// Have to reimplement hold-down-menu-brings-up-softkeybd
// ourselves, since we are otherwise hijacking the menu key :(
// See com.android.internal.policy.impl.PhoneWindow.onKeyDownPanel()
// for the usual Android implementation of this feature.
if (keyCode == KeyEvent.KEYCODE_MENU) {
final boolean fired =
!keyHandler.hasMessages(MSG_MENU_LONG_PRESS);
keyHandler.removeMessages(MSG_MENU_LONG_PRESS);
if (action == KeyEvent.ACTION_DOWN) {
keyHandler.sendMessageDelayed(keyHandler.obtainMessage(
MSG_MENU_LONG_PRESS), _longPress);
return true;
}
if (fired)
return true;
// only send up events of the menu button to the native side
if (action != KeyEvent.ACTION_UP)
return true;
}
_scummvm.pushEvent(JE_SYS_KEY, action, keyCode, 0, 0, 0);
return true;
}
// sequence of characters
if (action == KeyEvent.ACTION_MULTIPLE &&
keyCode == KeyEvent.KEYCODE_UNKNOWN) {
KeyCharacterMap m = KeyCharacterMap.load(e.getDeviceId());
for (KeyEvent s : m.getEvents(e.getCharacters().toCharArray())) {
_scummvm.pushEvent(JE_KEY, s.getAction(), s.getKeyCode(),
s.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK,
s.getMetaState(), s.getRepeatCount());
}
return true;
}
_scummvm.pushEvent(JE_KEY, action, keyCode,
e.getUnicodeChar() & KeyCharacterMap.COMBINING_ACCENT_MASK,
e.getMetaState(), e.getRepeatCount());
return true;
}
// OnTouchListener
final public boolean onTouch(View v, MotionEvent e) {
return _gd.onTouchEvent(e);
}
// OnGestureListener
final public boolean onDown(MotionEvent e) {
_scummvm.pushEvent(JE_DOWN, (int)e.getX(), (int)e.getY(), 0, 0, 0);
return true;
}
final public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
//Log.d(ScummVM.LOG_TAG, String.format("onFling: %s -> %s (%.3f %.3f)",
// e1.toString(), e2.toString(),
// velocityX, velocityY));
return true;
}
final public void onLongPress(MotionEvent e) {
// disabled, interferes with drag&drop
}
final public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
_scummvm.pushEvent(JE_SCROLL, (int)e1.getX(), (int)e1.getY(),
(int)e2.getX(), (int)e2.getY(), _slop);
return true;
}
final public void onShowPress(MotionEvent e) {
}
final public boolean onSingleTapUp(MotionEvent e) {
_scummvm.pushEvent(JE_TAP, (int)e.getX(), (int)e.getY(),
(int)(e.getEventTime() - e.getDownTime()), 0, 0);
return true;
}
// OnDoubleTapListener
final public boolean onDoubleTap(MotionEvent e) {
return true;
}
final public boolean onDoubleTapEvent(MotionEvent e) {
_scummvm.pushEvent(JE_DOUBLE_TAP, (int)e.getX(), (int)e.getY(),
e.getAction(), _slop, 0);
return true;
}
final public boolean onSingleTapConfirmed(MotionEvent e) {
return true;
}
}