1 /*
2  * A800view.java - atari screen view
3  *
4  * Copyright (C) 2010 Kostas Nakos
5  * Copyright (C) 2010 Atari800 development team (see DOC/CREDITS)
6  *
7  * This file is part of the Atari800 emulator project which emulates
8  * the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
9  *
10  * Atari800 is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * Atari800 is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Atari800; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23 */
24 
25 package name.nick.jubanka.colleen;
26 
27 import android.content.Context;
28 import android.opengl.GLSurfaceView;
29 import android.view.MotionEvent;
30 import android.view.KeyEvent;
31 import android.util.Log;
32 import android.view.KeyCharacterMap;
33 import android.os.Build;
34 import android.widget.Toast;
35 import android.view.View;
36 import android.util.SparseArray;
37 import android.os.Handler;
38 import android.os.Message;
39 import android.view.inputmethod.InputConnection;
40 import android.view.inputmethod.BaseInputConnection;
41 import android.view.inputmethod.EditorInfo;
42 import static android.view.KeyEvent.*;
43 
44 
45 public final class A800view extends GLSurfaceView
46 {
47 	public static final int KEY_SHIFT     = 256;
48 	public static final int KEY_CONTROL   = 257;
49 	public static final int KEY_BACKSPACE = 255;
50 	public static final int KEY_UP        = 254;
51 	public static final int KEY_DOWN      = 253;
52 	public static final int KEY_LEFT      = 252;
53 	public static final int KEY_RIGHT     = 251;
54 	public static final int KEY_FIRE      = 250;
55 	public static final int KEY_ENTER     = 249;
56 	public static final int KEY_ESCAPE    = 248;
57 	public static final int KEY_CENTER    = 247;
58 	public static final int KEY_BT_X      = 246;
59 	public static final int KEY_BT_Y      = 245;
60 	public static final int KEY_BT_L1     = 244;
61 	public static final int KEY_BT_R1     = 243;
62 	public static final int KEY_BREAK     = 242;
63 	// keycodes from newer sdks
64 	public static final int KC_BUTTON_X   = 307;
65 	public static final int KC_BUTTON_Y   = 308;
66 	public static final int KC_BUTTON_L1  = 310;
67 	public static final int KC_BUTTON_R1  = 311;
68 
69 
70 	private static final String TAG = "A800View";
71 	private A800Renderer _renderer;
72 	private KeyCharacterMap _keymap;
73 	private int _key, _meta, _hit;
74 	private TouchFactory _touchHandler = null;
75 	private Toast _toastquit;
76 	private Integer _xkey;
77 
A800view(Context context)78 	public A800view(Context context) {
79 		super(context);
80 
81 		_renderer = new A800Renderer();
82 		setRenderer(_renderer);
83 		_renderer.prepareToast(context);
84 		_renderer.setHandler(new Handler() {
85 			@Override
86 			public void handleMessage(Message msg) {
87 				((MainActivity) getContext()).message(msg.what);
88 			}
89 		});
90 
91 		setFocusable(true);
92 		setFocusableInTouchMode(true);
93 		requestFocus();
94 
95 		_keymap = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
96 
97 		if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.ECLAIR)
98 			_touchHandler = new SingleTouch();
99 		else
100 			_touchHandler = new MultiTouch();
101 
102 		_toastquit = Toast.makeText(context, R.string.pressback, Toast.LENGTH_SHORT);
103 	}
104 
pause(boolean p)105 	public void pause(boolean p) {
106 		setRenderMode(p ? GLSurfaceView.RENDERMODE_WHEN_DIRTY :
107 						  GLSurfaceView.RENDERMODE_CONTINUOUSLY);
108 	}
109 
110 	// Touch input
111 	@Override
onTouchEvent(final MotionEvent ev)112 	public boolean onTouchEvent(final MotionEvent ev) {
113 		int ret = _touchHandler.onTouchEvent(ev);
114 
115 		if (Integer.parseInt(Build.VERSION.SDK) >= Build.VERSION_CODES.HONEYCOMB) {
116 			MainActivity m = (MainActivity) getContext();
117 			if (ret == 2)
118 				m._aBar.show(m);
119 			else if (ret == 1)
120 				m._aBar.hide(m);
121 		}
122 		return true;
123 	}
124 
125 	abstract static class TouchFactory {
onTouchEvent(MotionEvent ev)126 		public abstract int onTouchEvent(MotionEvent ev);
127 	};
128 
129 	private static final class SingleTouch extends TouchFactory {
130 		private int _x1, _y1, _s1;
131 		private int _action, _actioncode;
132 
133 
134 		@Override
onTouchEvent(final MotionEvent ev)135 		public int onTouchEvent(final MotionEvent ev) {
136 			_action = ev.getAction();
137 			_actioncode = _action & MotionEvent.ACTION_MASK;
138 			_x1 = (int) ev.getX();
139 			_y1 = (int) ev.getY();
140 			_s1 = 1;
141 			if (_actioncode == MotionEvent.ACTION_UP)
142 				_s1 = 0;
143 
144 			return NativeTouch(_x1, _y1, _s1, -1000, -1000, 0);
145 		}
146 	}
147 
148 	private static final class MultiTouch extends TouchFactory {
149 		private int _x1, _y1, _s1, _x2, _y2, _s2;
150 		private int _action, _actioncode, _ptrcnt;
151 
152 		@Override
onTouchEvent(final MotionEvent ev)153 		public int onTouchEvent(final MotionEvent ev) {
154 			_action = ev.getAction();
155 			_actioncode = _action & MotionEvent.ACTION_MASK;
156 			_ptrcnt = ev.getPointerCount();
157 			_x1 = (int) ev.getX(0);
158 			_y1 = (int) ev.getY(0);
159 			_s1 = 1;
160 			if (_ptrcnt > 1) {
161 				_x2 = (int) ev.getX(1);
162 				_y2 = (int) ev.getY(1);
163 				_s2 = 1;
164 			} else {
165 				_x2 = -1000;
166 				_y2 = -1000;
167 				_s2 = 0;
168 			}
169 			if (_actioncode == MotionEvent.ACTION_UP) {
170 				_s1 = _s2 = 0;
171 			} else if (_actioncode == MotionEvent.ACTION_POINTER_UP) {
172 				if ( (_action >> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0)
173 					_s1 = 0;
174 				else
175 					_s2 = 0;
176 			}
177 
178 			return NativeTouch(_x1, _y1, _s1, _x2, _y2, _s2);
179 		}
180 	}
181 
182 	// Key input
183 	@Override
onKeyDown(int kc, final KeyEvent ev)184 	public boolean onKeyDown(int kc, final KeyEvent ev) {
185 		return doKey(kc, ev);
186 	}
187 
188 	@Override
onKeyUp(int kc, final KeyEvent ev)189 	public boolean onKeyUp(int kc, final KeyEvent ev) {
190 		return doKey(kc, ev);
191 	}
192 
193 	@Override
onCheckIsTextEditor()194     public boolean onCheckIsTextEditor() {
195         return true;
196     }
197 
198 	@Override
onCreateInputConnection(EditorInfo outAttrs)199 	public InputConnection onCreateInputConnection (EditorInfo outAttrs) {
200 		return new BaseInputConnection(this, false) {
201 				@Override
202 				public boolean deleteSurroundingText (int leftLength, int rightLength) {
203 					//Log.d(TAG, "Synthetic del");
204 					this.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
205 					this.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
206 					return true;
207 				}
208 			};
209 	}
210 
211 	private boolean doKey(int kc, final KeyEvent ev) {
212 		_hit =(ev.getAction() == ACTION_DOWN) ? 1 : 0;
213 
214 		if (kc == KEYCODE_BACK && _hit == 1) {
215 			MainActivity m = (MainActivity) getContext();
216 			if (_toastquit.getView().getWindowVisibility() == View.VISIBLE) {
217 				_toastquit.cancel();
218 				m.finish();
219 			} else if (m._aBar.isShowing(m))
220 				m._aBar.hide(m);
221 			else
222 				_toastquit.show();
223 			return true;
224 		}
225 
226 		_xkey = XLATKEYS.get(kc);
227 		if (_xkey != null)
228 			_key = _xkey.intValue();
229 		else {
230 			_meta = ev.getMetaState();
231 			if ((_meta & KeyEvent.META_SHIFT_RIGHT_ON) == KeyEvent.META_SHIFT_RIGHT_ON)
232 				_meta &= ~(KeyEvent.META_SHIFT_RIGHT_ON | KeyEvent.META_SHIFT_ON);
233 			_key = _keymap.get(kc, _meta);
234 			if (_key == 0)
235 				return false;
236 		}
237 
238 		//Log.d(TAG, String.format("key %d %d -> %d", ev.getAction(), kc, _key));
239 
240 		NativeKey(_key, _hit);
241 
242 		return true;
243 	}
244 
245 	private native static int NativeTouch(int x1, int y1, int s1, int x2, int y2, int s2);
246 	private native void NativeKey(int keycode, int status);
247 
248 	public static final SparseArray<Integer> XLATKEYS = new SparseArray<Integer>(14);
249 	static {
250 		XLATKEYS.put(KEYCODE_DPAD_UP,		KEY_UP);
251 		XLATKEYS.put(KEYCODE_DPAD_DOWN,		KEY_DOWN);
252 		XLATKEYS.put(KEYCODE_DPAD_LEFT,		KEY_LEFT);
253 		XLATKEYS.put(KEYCODE_DPAD_RIGHT,	KEY_RIGHT);
254 		XLATKEYS.put(KEYCODE_DPAD_CENTER,	KEY_BREAK);
255 		XLATKEYS.put(KEYCODE_SEARCH,		KEY_FIRE);
256 		XLATKEYS.put(KEYCODE_SHIFT_LEFT,	KEY_SHIFT);
257 		XLATKEYS.put(KEYCODE_SHIFT_RIGHT,	KEY_CONTROL);
258 		XLATKEYS.put(KEYCODE_DEL,			KEY_BACKSPACE);
259 		XLATKEYS.put(KEYCODE_ENTER,			KEY_ENTER);
260 		XLATKEYS.put(KC_BUTTON_X,			KEY_BT_X);
261 		XLATKEYS.put(KC_BUTTON_Y,			KEY_BT_Y);
262 		XLATKEYS.put(KC_BUTTON_L1,			KEY_BT_L1);
263 		XLATKEYS.put(KC_BUTTON_R1,			KEY_BT_R1);
264 	}
265 }
266