[Scummvm-cvs-logs] scummvm master -> 3a38a97934e422416271dc5dc5bb46709a1c7c13

dhewg dhewg at wiibrew.org
Wed Mar 16 20:56:50 CET 2011


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
6b346c1fe0 ANDROID: Cleanup and extend chooseEglConfig
e71c2cf850 ANDROID: Constify getDrawRect()
adef4c3f42 ANDROID: Input system overhaul
3a38a97934 ANDROID: Reindent


Commit: 6b346c1fe04a8e3ed770d6246532391591265ea2
    https://github.com/scummvm/scummvm/commit/6b346c1fe04a8e3ed770d6246532391591265ea2
Author: dhewg (dhewg at wiibrew.org)
Date: 2011-03-16T12:54:25-07:00

Commit Message:
ANDROID: Cleanup and extend chooseEglConfig

Add more checks and log all possible configs

Changed paths:
    backends/platform/android/org/inodes/gus/scummvm/ScummVM.java



diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
index dfb5855..ed4e00d 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
@@ -144,34 +144,20 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
 		_egl.eglInitialize(_egl_display, version);
 
 		int[] num_config = new int[1];
-		_egl.eglChooseConfig(_egl_display, configSpec, null, 0, num_config);
+		_egl.eglGetConfigs(_egl_display, null, 0, num_config);
 
 		final int numConfigs = num_config[0];
 
 		if (numConfigs <= 0)
-			throw new IllegalArgumentException("No configs match configSpec");
+			throw new IllegalArgumentException("No EGL configs");
 
 		EGLConfig[] configs = new EGLConfig[numConfigs];
-		_egl.eglChooseConfig(_egl_display, configSpec, configs, numConfigs,
-								num_config);
-
-		if (false) {
-			Log.d(LOG_TAG, String.format("Found %d EGL configurations.",
-											numConfigs));
-			for (EGLConfig config : configs)
-				dumpEglConfig(config);
-		}
+		_egl.eglGetConfigs(_egl_display, configs, numConfigs, num_config);
 
 		// Android's eglChooseConfig is busted in several versions and
-		// devices so we have to filter/rank the configs again ourselves.
+		// devices so we have to filter/rank the configs ourselves.
 		_egl_config = chooseEglConfig(configs);
 
-		if (false) {
-			Log.d(LOG_TAG, String.format("Chose from %d EGL configs",
-											numConfigs));
-			dumpEglConfig(_egl_config);
-		}
-
 		_egl_context = _egl.eglCreateContext(_egl_display, _egl_config,
 											EGL10.EGL_NO_CONTEXT, null);
 
@@ -280,121 +266,163 @@ public abstract class ScummVM implements SurfaceHolder.Callback, Runnable {
 		_sample_rate = 0;
 	}
 
-	static final int configSpec[] = {
-		EGL10.EGL_RED_SIZE, 5,
-		EGL10.EGL_GREEN_SIZE, 5,
-		EGL10.EGL_BLUE_SIZE, 5,
-		EGL10.EGL_DEPTH_SIZE, 0,
-		EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
-		EGL10.EGL_NONE,
+	private static final int[] s_eglAttribs = {
+		EGL10.EGL_CONFIG_ID,
+		EGL10.EGL_BUFFER_SIZE,
+		EGL10.EGL_RED_SIZE,
+		EGL10.EGL_GREEN_SIZE,
+		EGL10.EGL_BLUE_SIZE,
+		EGL10.EGL_ALPHA_SIZE,
+		EGL10.EGL_CONFIG_CAVEAT,
+		EGL10.EGL_DEPTH_SIZE,
+		EGL10.EGL_LEVEL,
+		EGL10.EGL_MAX_PBUFFER_WIDTH,
+		EGL10.EGL_MAX_PBUFFER_HEIGHT,
+		EGL10.EGL_MAX_PBUFFER_PIXELS,
+		EGL10.EGL_NATIVE_RENDERABLE,
+		EGL10.EGL_NATIVE_VISUAL_ID,
+		EGL10.EGL_NATIVE_VISUAL_TYPE,
+		EGL10.EGL_SAMPLE_BUFFERS,
+		EGL10.EGL_SAMPLES,
+		EGL10.EGL_STENCIL_SIZE,
+		EGL10.EGL_SURFACE_TYPE,
+		EGL10.EGL_TRANSPARENT_TYPE,
+		EGL10.EGL_TRANSPARENT_RED_VALUE,
+		EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+		EGL10.EGL_TRANSPARENT_BLUE_VALUE
 	};
 
-	// For debugging
-	private static final Map<String, Integer> attribs;
+	final private class EglAttribs extends LinkedHashMap<Integer, Integer> {
+		public EglAttribs(EGLConfig config) {
+			super(s_eglAttribs.length);
 
-	static {
-		attribs = new LinkedHashMap<String, Integer>();
-		attribs.put("CONFIG_ID", EGL10.EGL_CONFIG_ID);
-		attribs.put("BUFFER_SIZE", EGL10.EGL_BUFFER_SIZE);
-		attribs.put("RED_SIZE", EGL10.EGL_RED_SIZE);
-		attribs.put("GREEN_SIZE", EGL10.EGL_GREEN_SIZE);
-		attribs.put("BLUE_SIZE", EGL10.EGL_BLUE_SIZE);
-		attribs.put("ALPHA_SIZE", EGL10.EGL_ALPHA_SIZE);
-		//attribs.put("BIND_TO_RGB", EGL10.EGL_BIND_TO_TEXTURE_RGB);
-		//attribs.put("BIND_TO_RGBA", EGL10.EGL_BIND_TO_TEXTURE_RGBA);
-		attribs.put("CONFIG_CAVEAT", EGL10.EGL_CONFIG_CAVEAT);
-		attribs.put("DEPTH_SIZE", EGL10.EGL_DEPTH_SIZE);
-		attribs.put("LEVEL", EGL10.EGL_LEVEL);
-		attribs.put("MAX_PBUFFER_WIDTH", EGL10.EGL_MAX_PBUFFER_WIDTH);
-		attribs.put("MAX_PBUFFER_HEIGHT", EGL10.EGL_MAX_PBUFFER_HEIGHT);
-		attribs.put("MAX_PBUFFER_PIXELS", EGL10.EGL_MAX_PBUFFER_PIXELS);
-		//attribs.put("MAX_SWAP_INTERVAL", EGL10.EGL_MAX_SWAP_INTERVAL);
-		//attribs.put("MIN_SWAP_INTERVAL", EGL10.EGL_MIN_SWAP_INTERVAL);
-		attribs.put("NATIVE_RENDERABLE", EGL10.EGL_NATIVE_RENDERABLE);
-		attribs.put("NATIVE_VISUAL_ID", EGL10.EGL_NATIVE_VISUAL_ID);
-		attribs.put("NATIVE_VISUAL_TYPE", EGL10.EGL_NATIVE_VISUAL_TYPE);
-		attribs.put("SAMPLE_BUFFERS", EGL10.EGL_SAMPLE_BUFFERS);
-		attribs.put("SAMPLES", EGL10.EGL_SAMPLES);
-		attribs.put("STENCIL_SIZE", EGL10.EGL_STENCIL_SIZE);
-		attribs.put("SURFACE_TYPE", EGL10.EGL_SURFACE_TYPE);
-		attribs.put("TRANSPARENT_TYPE", EGL10.EGL_TRANSPARENT_TYPE);
-		attribs.put("TRANSPARENT_RED_VALUE", EGL10.EGL_TRANSPARENT_RED_VALUE);
-		attribs.put("TRANSPARENT_GREEN_VALUE", EGL10.EGL_TRANSPARENT_GREEN_VALUE);
-		attribs.put("TRANSPARENT_BLUE_VALUE", EGL10.EGL_TRANSPARENT_BLUE_VALUE);
-	}
+			int[] value = new int[1];
 
-	final private void dumpEglConfig(EGLConfig config) {
-		int[] value = new int[1];
+			for (int i : s_eglAttribs) {
+				_egl.eglGetConfigAttrib(_egl_display, config, i, value);
 
-		for (Map.Entry<String, Integer> entry : attribs.entrySet()) {
-			_egl.eglGetConfigAttrib(_egl_display, config,
-									entry.getValue(), value);
-
-			if (value[0] == EGL10.EGL_NONE)
-				Log.d(LOG_TAG, entry.getKey() + ": NONE");
-			else
-				Log.d(LOG_TAG, String.format("%s: %d", entry.getKey(), value[0]));
+				put(i, value[0]);
+			}
 		}
-	}
 
-	final private EGLConfig chooseEglConfig(EGLConfig[] configs) {
-		int best = 0;
-		int bestScore = -1;
-		int[] value = new int[1];
+		private int weightBits(int attr, int size) {
+			final int value = get(attr);
 
-		for (int i = 0; i < configs.length; i++) {
-			EGLConfig config = configs[i];
-			int score = 10000;
+			int score = 0;
 
-			_egl.eglGetConfigAttrib(_egl_display, config,
-									EGL10.EGL_SURFACE_TYPE, value);
+			if (value == size || (size > 0 && value > size))
+				score += 10;
 
-			// must have
-			if ((value[0] & EGL10.EGL_WINDOW_BIT) == 0)
-				continue;
+			// penalize for wasted bits
+			score -= value - size;
+
+			return score;
+		}
 
-			_egl.eglGetConfigAttrib(_egl_display, config,
-									EGL10.EGL_CONFIG_CAVEAT, value);
+		public int weight() {
+			int score = 10000;
 
-			if (value[0] != EGL10.EGL_NONE)
+			if (get(EGL10.EGL_CONFIG_CAVEAT) != EGL10.EGL_NONE)
 				score -= 1000;
 
-			// Must be at least 555, but then smaller is better
-			final int[] colorBits = { EGL10.EGL_RED_SIZE,
-										EGL10.EGL_GREEN_SIZE,
-										EGL10.EGL_BLUE_SIZE,
-										EGL10.EGL_ALPHA_SIZE
-									};
+			// less MSAA is better
+			score -= get(EGL10.EGL_SAMPLES) * 100;
 
-			for (int component : colorBits) {
-				_egl.eglGetConfigAttrib(_egl_display, config, component, value);
+			// Must be at least 565, but then smaller is better
+			score += weightBits(EGL10.EGL_RED_SIZE, 5);
+			score += weightBits(EGL10.EGL_GREEN_SIZE, 6);
+			score += weightBits(EGL10.EGL_BLUE_SIZE, 5);
+			score += weightBits(EGL10.EGL_ALPHA_SIZE, 0);
+			score += weightBits(EGL10.EGL_DEPTH_SIZE, 0);
+			score += weightBits(EGL10.EGL_STENCIL_SIZE, 0);
 
-				// boost if >5 bits accuracy
-				if (value[0] >= 5)
-					score += 10;
+			return score;
+		}
+
+		public String toString() {
+			String s;
 
-				// penalize for wasted bits
-				score -= value[0];
+			if (get(EGL10.EGL_ALPHA_SIZE) > 0)
+				s = String.format("[%d] RGBA%d%d%d%d",
+									get(EGL10.EGL_CONFIG_ID),
+									get(EGL10.EGL_RED_SIZE),
+									get(EGL10.EGL_GREEN_SIZE),
+									get(EGL10.EGL_BLUE_SIZE),
+									get(EGL10.EGL_ALPHA_SIZE));
+			else
+				s = String.format("[%d] RGB%d%d%d",
+									get(EGL10.EGL_CONFIG_ID),
+									get(EGL10.EGL_RED_SIZE),
+									get(EGL10.EGL_GREEN_SIZE),
+									get(EGL10.EGL_BLUE_SIZE));
+
+			if (get(EGL10.EGL_DEPTH_SIZE) > 0)
+				s += String.format(" D%d", get(EGL10.EGL_DEPTH_SIZE));
+
+			if (get(EGL10.EGL_STENCIL_SIZE) > 0)
+				s += String.format(" S%d", get(EGL10.EGL_STENCIL_SIZE));
+
+			if (get(EGL10.EGL_SAMPLES) > 0)
+				s += String.format(" MSAAx%d", get(EGL10.EGL_SAMPLES));
+
+			if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) > 0)
+				s += " W";
+			if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_PBUFFER_BIT) > 0)
+				s += " P";
+			if ((get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_PIXMAP_BIT) > 0)
+				s += " X";
+
+			switch (get(EGL10.EGL_CONFIG_CAVEAT)) {
+			case EGL10.EGL_NONE:
+				break;
+
+			case EGL10.EGL_SLOW_CONFIG:
+				s += " SLOW";
+				break;
+
+			case EGL10.EGL_NON_CONFORMANT_CONFIG:
+				s += " NON_CONFORMANT";
+
+			default:
+				s += String.format(" unknown CAVEAT 0x%x",
+									get(EGL10.EGL_CONFIG_CAVEAT));
 			}
 
-			_egl.eglGetConfigAttrib(_egl_display, config,
-									EGL10.EGL_DEPTH_SIZE, value);
+			return s;
+		}
+	};
 
-			// penalize for wasted bits
-			score -= value[0];
+	final private EGLConfig chooseEglConfig(EGLConfig[] configs) {
+		EGLConfig res = configs[0];
+		int bestScore = -1;
+
+		Log.d(LOG_TAG, "EGL configs:");
+
+		for (EGLConfig config : configs) {
+			EglAttribs attr = new EglAttribs(config);
+
+			// must have
+			if ((attr.get(EGL10.EGL_SURFACE_TYPE) & EGL10.EGL_WINDOW_BIT) == 0)
+				continue;
+
+			int score = attr.weight();
+
+			Log.d(LOG_TAG, String.format("%s (%d)", attr.toString(), score));
 
 			if (score > bestScore) {
-				best = i;
+				res = config;
 				bestScore = score;
 			}
 		}
 
-		if (bestScore < 0) {
-			Log.e(LOG_TAG, "Unable to find an acceptable EGL config, expect badness.");
-			return configs[0];
-		}
+		if (bestScore < 0)
+			Log.e(LOG_TAG,
+					"Unable to find an acceptable EGL config, expect badness.");
+
+		Log.d(LOG_TAG, String.format("Chosen EGL config: %s",
+										new EglAttribs(res).toString()));
 
-		return configs[best];
+		return res;
 	}
 
 	static {


Commit: e71c2cf850388b2a25200d544d2fb422525b4c88
    https://github.com/scummvm/scummvm/commit/e71c2cf850388b2a25200d544d2fb422525b4c88
Author: dhewg (dhewg at wiibrew.org)
Date: 2011-03-16T12:54:25-07:00

Commit Message:
ANDROID: Constify getDrawRect()

Changed paths:
    backends/platform/android/texture.h



diff --git a/backends/platform/android/texture.h b/backends/platform/android/texture.h
index 4f2bfe4..64489da 100644
--- a/backends/platform/android/texture.h
+++ b/backends/platform/android/texture.h
@@ -73,7 +73,7 @@ public:
 		_draw_rect = Common::Rect(x1, y1, x2, y2);
 	}
 
-	inline const Common::Rect &getDrawRect() {
+	inline const Common::Rect &getDrawRect() const {
 		return _draw_rect;
 	}
 


Commit: adef4c3f4256a690b374b9801279952c39ccf7a4
    https://github.com/scummvm/scummvm/commit/adef4c3f4256a690b374b9801279952c39ccf7a4
Author: dhewg (dhewg at wiibrew.org)
Date: 2011-03-16T12:54:49-07:00

Commit Message:
ANDROID: Input system overhaul

Rewritten input system with many new feature.
Fixed related bugs and shortcomings on the way.

Changed paths:
  A backends/platform/android/events.cpp
  A backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java
  R backends/platform/android/org/inodes/gus/scummvm/Event.java
    backends/platform/android/android.cpp
    backends/platform/android/android.h
    backends/platform/android/android.mk
    backends/platform/android/gfx.cpp
    backends/platform/android/jni.cpp
    backends/platform/android/jni.h
    backends/platform/android/module.mk
    backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
    backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java



diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp
index ddef427..4e1373a 100644
--- a/backends/platform/android/android.cpp
+++ b/backends/platform/android/android.cpp
@@ -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;
 
diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h
index dc45f06..7ff9618 100644
--- a/backends/platform/android/android.h
+++ b/backends/platform/android/android.h
@@ -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);
 
diff --git a/backends/platform/android/android.mk b/backends/platform/android/android.mk
index eb58089..cb39f8a 100644
--- a/backends/platform/android/android.mk
+++ b/backends/platform/android/android.mk
@@ -6,6 +6,7 @@ ANDROID_PLUGIN_VERSIONCODE = 6
 
 JAVA_FILES = \
 	ScummVM.java \
+	ScummVMEvents.java \
 	ScummVMApplication.java \
 	ScummVMActivity.java \
 	EditableSurfaceView.java \
diff --git a/backends/platform/android/events.cpp b/backends/platform/android/events.cpp
new file mode 100644
index 0000000..1715e6a
--- /dev/null
+++ b/backends/platform/android/events.cpp
@@ -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
+
diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp
index 65f98d5..fc45f4c 100644
--- a/backends/platform/android/gfx.cpp
+++ b/backends/platform/android/gfx.cpp
@@ -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));
+	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;
 		}
diff --git a/backends/platform/android/jni.cpp b/backends/platform/android/jni.cpp
index 0628d92..92cb049 100644
--- a/backends/platform/android/jni.cpp
+++ b/backends/platform/android/jni.cpp
@@ -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) {
diff --git a/backends/platform/android/jni.h b/backends/platform/android/jni.h
index 5746c01..d029f1a 100644
--- a/backends/platform/android/jni.h
+++ b/backends/platform/android/jni.h
@@ -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);
diff --git a/backends/platform/android/module.mk b/backends/platform/android/module.mk
index 3bcfa7a..2fe4b40 100644
--- a/backends/platform/android/module.mk
+++ b/backends/platform/android/module.mk
@@ -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))
diff --git a/backends/platform/android/org/inodes/gus/scummvm/Event.java b/backends/platform/android/org/inodes/gus/scummvm/Event.java
deleted file mode 100644
index f9c7aba..0000000
--- a/backends/platform/android/org/inodes/gus/scummvm/Event.java
+++ /dev/null
@@ -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;
-	}
-}
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
index ed4e00d..fe225af 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVM.java
@@ -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);
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java
index 2cf6f58..1978b69 100644
--- a/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMActivity.java
@@ -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;
-			}
-
-			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);
+	public boolean onTrackballEvent(MotionEvent e) {
+		if (_events != null)
+			return _events.onTrackballEvent(e);
 
-		return true;
+		return false;
 	}
 
 	private void showKeyboard(boolean show) {
diff --git a/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java
new file mode 100644
index 0000000..3d3fdee
--- /dev/null
+++ b/backends/platform/android/org/inodes/gus/scummvm/ScummVMEvents.java
@@ -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;
+	}
+}
+


Commit: 3a38a97934e422416271dc5dc5bb46709a1c7c13
    https://github.com/scummvm/scummvm/commit/3a38a97934e422416271dc5dc5bb46709a1c7c13
Author: dhewg (dhewg at wiibrew.org)
Date: 2011-03-16T12:54:49-07:00

Commit Message:
ANDROID: Reindent

Changed paths:
    dists/android/res/layout/main.xml



diff --git a/dists/android/res/layout/main.xml b/dists/android/res/layout/main.xml
index f5276ce..b6164ed 100644
--- a/dists/android/res/layout/main.xml
+++ b/dists/android/res/layout/main.xml
@@ -1,10 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
+
 <org.inodes.gus.scummvm.EditableSurfaceView
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="fill_parent" android:layout_height="fill_parent"
-        android:id="@+id/main_surface"
-        android:gravity="center"
-        android:keepScreenOn="true"
-        android:focusable="true"
-        android:focusableInTouchMode="true"
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	android:id="@+id/main_surface"
+	android:layout_width="fill_parent"
+	android:layout_height="fill_parent"
+	android:gravity="center"
+	android:keepScreenOn="true"
+	android:focusable="true"
+	android:focusableInTouchMode="true"
 />
+






More information about the Scummvm-git-logs mailing list