1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.quake; 18/* 19 * Copyright (C) 2008 The Android Open Source Project 20 * 21 * Licensed under the Apache License, Version 2.0 (the "License"); 22 * you may not use this file except in compliance with the License. 23 * You may obtain a copy of the License at 24 * 25 * http://www.apache.org/licenses/LICENSE-2.0 26 * 27 * Unless required by applicable law or agreed to in writing, software 28 * distributed under the License is distributed on an "AS IS" BASIS, 29 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 * See the License for the specific language governing permissions and 31 * limitations under the License. 32 */ 33 34 35import android.content.Context; 36import android.opengl.GLSurfaceView; 37import android.util.AttributeSet; 38import android.util.Log; 39import android.view.KeyEvent; 40import android.view.MotionEvent; 41 42import javax.microedition.khronos.egl.EGL10; 43import javax.microedition.khronos.egl.EGLConfig; 44import javax.microedition.khronos.opengles.GL10; 45/** 46 * An implementation of SurfaceView that uses the dedicated surface for 47 * displaying an OpenGL animation. This allows the animation to run in a 48 * separate thread, without requiring that it be driven by the update mechanism 49 * of the view hierarchy. 50 * 51 * The application-specific rendering code is delegated to a GLView.Renderer 52 * instance. 53 */ 54class QuakeView extends GLSurfaceView { 55 QuakeView(Context context) { 56 super(context); 57 init(); 58 } 59 60 public QuakeView(Context context, AttributeSet attrs) { 61 super(context, attrs); 62 init(); 63 } 64 65 private void init() { 66 // We want events. 67 setFocusable(true); 68 setFocusableInTouchMode(true); 69 requestFocus(); 70 } 71 72 public void setQuakeLib(QuakeLib quakeLib) { 73 mQuakeLib = quakeLib; 74 setRenderer(new QuakeRenderer()); 75 } 76 77 @Override 78 public boolean onKeyDown(int keyCode, KeyEvent event) { 79 if (!weWantThisKeyCode(keyCode)) { 80 return super.onKeyDown(keyCode, event); 81 } 82 switch (keyCode) { 83 case KeyEvent.KEYCODE_ALT_RIGHT: 84 case KeyEvent.KEYCODE_ALT_LEFT: 85 mAltKeyPressed = true; 86 break; 87 case KeyEvent.KEYCODE_SHIFT_RIGHT: 88 case KeyEvent.KEYCODE_SHIFT_LEFT: 89 mShiftKeyPressed = true; 90 break; 91 } 92 queueKeyEvent(QuakeLib.KEY_PRESS, 93 keyCodeToQuakeCode(keyCode)); 94 return true; 95 } 96 97 @Override 98 public boolean onKeyUp(int keyCode, KeyEvent event) { 99 if (!weWantThisKeyCode(keyCode)) { 100 return super.onKeyUp(keyCode, event); 101 } 102 switch (keyCode) { 103 case KeyEvent.KEYCODE_ALT_RIGHT: 104 case KeyEvent.KEYCODE_ALT_LEFT: 105 mAltKeyPressed = false; 106 break; 107 case KeyEvent.KEYCODE_SHIFT_RIGHT: 108 case KeyEvent.KEYCODE_SHIFT_LEFT: 109 mShiftKeyPressed = false; 110 break; } 111 queueKeyEvent(QuakeLib.KEY_RELEASE, 112 keyCodeToQuakeCode(keyCode)); 113 return true; 114 } 115 116 @Override 117 public boolean onTrackballEvent(MotionEvent event) { 118 if (!mGameMode) { 119 return super.onTrackballEvent(event); 120 } 121 queueTrackballEvent(event); 122 return true; 123 } 124 125 private boolean weWantThisKeyCode(int keyCode) { 126 return (keyCode != KeyEvent.KEYCODE_VOLUME_UP) && 127 (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN) && 128 (keyCode != KeyEvent.KEYCODE_SEARCH); 129 } 130 131 @Override 132 public boolean dispatchTouchEvent(MotionEvent ev) { 133 queueMotionEvent(ev); 134 return true; 135 } 136 137 private int keyCodeToQuakeCode(int keyCode) { 138 int key = 0; 139 if (keyCode >= sKeyCodeToQuakeCode.length) { 140 return 0; 141 } 142 if (mAltKeyPressed) { 143 key = sKeyCodeToQuakeCodeAlt[keyCode]; 144 if (key == 0) { 145 key = sKeyCodeToQuakeCodeShift[keyCode]; 146 if (key == 0) { 147 key = sKeyCodeToQuakeCode[keyCode]; 148 } 149 } 150 } else if (mShiftKeyPressed) { 151 key = sKeyCodeToQuakeCodeShift[keyCode]; 152 if (key == 0) { 153 key = sKeyCodeToQuakeCode[keyCode]; 154 } 155 } else { 156 key = sKeyCodeToQuakeCode[keyCode]; 157 } 158 if (key == 0) { 159 key = '$'; 160 } 161 return key; 162 } 163 164 public void queueKeyEvent(final int type, final int keyCode) { 165 queueEvent( 166 new Runnable() { 167 public void run() { 168 mQuakeLib.event(type, keyCode); 169 } 170 }); 171 } 172 173 public void queueMotionEvent(final MotionEvent ev) { 174 queueEvent( 175 new Runnable() { 176 public void run() { 177 mQuakeLib.motionEvent(ev.getEventTime(), 178 ev.getAction(), 179 ev.getX(), ev.getY(), 180 ev.getPressure(), ev.getSize(), 181 ev.getDeviceId()); 182 } 183 }); 184 } 185 186 public void queueTrackballEvent(final MotionEvent ev) { 187 queueEvent( 188 new Runnable() { 189 public void run() { 190 mQuakeLib.trackballEvent(ev.getEventTime(), 191 ev.getAction(), 192 ev.getX(), ev.getY()); 193 } 194 }); 195 } 196 197 private boolean mShiftKeyPressed; 198 private boolean mAltKeyPressed; 199 200 private static final int[] sKeyCodeToQuakeCode = { 201 '$', QuakeLib.K_ESCAPE, '$', '$', QuakeLib.K_ESCAPE, '$', '$', '0', // 0.. 7 202 '1', '2', '3', '4', '5', '6', '7', '8', // 8..15 203 '9', '$', '$', QuakeLib.K_UPARROW, QuakeLib.K_DOWNARROW, QuakeLib.K_LEFTARROW, QuakeLib.K_RIGHTARROW, QuakeLib.K_ENTER, // 16..23 204 '$', '$', '$', QuakeLib.K_HOME, '$', 'a', 'b', 'c', // 24..31 205 206 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', // 32..39 207 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', // 40..47 208 't', 'u', 'v', 'w', 'x', 'y', 'z', ',', // 48..55 209 '.', QuakeLib.K_ALT, QuakeLib.K_ALT, QuakeLib.K_SHIFT, QuakeLib.K_SHIFT, QuakeLib.K_TAB, ' ', '$', // 56..63 210 '$', '$', QuakeLib.K_ENTER, QuakeLib.K_BACKSPACE, '`', '-', '=', '[', // 64..71 211 ']', '\\', ';', '\'', '/', QuakeLib.K_CTRL, '#', '$', // 72..79 212 QuakeLib.K_HOME, '$', QuakeLib.K_ESCAPE, '$', '$', 0, 0, 0, 0, // 80.. 213 0, 0, QuakeLib.K_PGUP, QuakeLib.K_PGDN, 0, 0, 0, 0, 0, 0, // 90.. 214 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100.. 215 0, QuakeLib.K_ESCAPE, QuakeLib.K_DEL, QuakeLib.K_CTRL, QuakeLib.K_CTRL, 0, 0, 0, 0, 0, // 110.. 216 0, 0, QuakeLib.K_HOME, QuakeLib.K_END, QuakeLib.K_INS, 0, 0, 0, 0, 0, // 120.. 217 0, QuakeLib.K_F1, QuakeLib.K_F2, QuakeLib.K_F3, QuakeLib.K_F4, // 130..134 218 QuakeLib.K_F5, QuakeLib.K_F6, QuakeLib.K_F7, QuakeLib.K_F8, QuakeLib.K_F9, // 135..139 219 QuakeLib.K_F10, QuakeLib.K_F11, QuakeLib.K_F12, 0, 0, 0, 0, 0, 0, 0, // 140.. 220 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150.. 221 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 222 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170.. 223 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 180.. 224 }; 225 226 private static final int sKeyCodeToQuakeCodeShift[] = 227 { 228 0, 0, 0, 0, 0, 0, 0, ')', // 0.. 7 229 '!', '@', '#', '$', '%', '^', '&', '*', // 8..15 230 '(', 0, 0, 0, 0, 0, 0, 0, // 16..23 231 0, 0, 0, 0, 0, 0, ']', 0, // 24..31 232 233 '\\', '_', '{', '}', ':', '-', ';', '"', // 32..39 234 '\'', '>', '<', '+', '=', 0, 0, '|', // 40..47 235 0, 0, '[', '`', 0, 0, QuakeLib.K_PAUSE, ';', // 48..55 236 0, 0, 0, 0, 0, 0, 0, 0, // 56..63 237 0, 0, 0, 0, 0, 0, 0, 0, // 64..71 238 0, 0, '?', '0', 0, QuakeLib.K_CTRL, 0, 0, // 72..79 239 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80.. 240 0, 0, QuakeLib.K_PGUP, QuakeLib.K_PGDN, 0, 0, 0, 0, 0, 0, // 90.. 241 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100.. 242 0, QuakeLib.K_ESCAPE, QuakeLib.K_DEL, QuakeLib.K_CTRL, QuakeLib.K_CTRL, 0, 0, 0, 0, 0, // 110.. 243 0, 0, QuakeLib.K_HOME, QuakeLib.K_END, QuakeLib.K_INS, 0, 0, 0, 0, 0, // 120.. 244 0, QuakeLib.K_F1, QuakeLib.K_F2, QuakeLib.K_F3, QuakeLib.K_F4, // 130..134 245 QuakeLib.K_F5, QuakeLib.K_F6, QuakeLib.K_F7, QuakeLib.K_F8, QuakeLib.K_F9, // 135..139 246 QuakeLib.K_F10, QuakeLib.K_F11, QuakeLib.K_F12, 0, 0, 0, 0, 0, 0, 0, // 140.. 247 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150.. 248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 249 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170.. 250 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 180.. 251 }; 252 253 private static final int sKeyCodeToQuakeCodeAlt[] = 254 { 255 0, 0, 0, 0, 0, 0, 0, QuakeLib.K_F10, // 0.. 7 256 QuakeLib.K_F1, QuakeLib.K_F2, QuakeLib.K_F3, QuakeLib.K_F4, QuakeLib.K_F5, QuakeLib.K_F6, QuakeLib.K_F7, QuakeLib.K_F8, // 8..15 257 QuakeLib.K_F9, 0, 0, 0, 0, 0, 0, 0, // 16..23 258 0, 0, 0, 0, 0, 0, 0, 0, // 24..31 259 260 0, 0, 0, 0, 0, 0, 0, 0, // 32..39 261 0, 0, 0, 0, 0, 0, 0, 0, // 40..47 262 QuakeLib.K_F11, 0, 0, 0, 0, QuakeLib.K_F12, 0, 0, // 48..55 263 0, 0, 0, 0, 0, 0, 0, 0, // 56..63 264 0, 0, 0, 0, 0, 0, 0, 0, // 64..71 265 0, 0, 0, 0, 0, 0, 0, 0, // 72..79 266 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80.. 267 0, 0, QuakeLib.K_PGUP, QuakeLib.K_PGDN, 0, 0, 0, 0, 0, 0, // 90.. 268 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100.. 269 0, QuakeLib.K_ESCAPE, QuakeLib.K_DEL, QuakeLib.K_CTRL, QuakeLib.K_CTRL, 0, 0, 0, 0, 0, // 110.. 270 0, 0, QuakeLib.K_HOME, QuakeLib.K_END, QuakeLib.K_INS, 0, 0, 0, 0, 0, // 120.. 271 0, QuakeLib.K_F1, QuakeLib.K_F2, QuakeLib.K_F3, QuakeLib.K_F4, // 130..134 272 QuakeLib.K_F5, QuakeLib.K_F6, QuakeLib.K_F7, QuakeLib.K_F8, QuakeLib.K_F9, // 135..139 273 QuakeLib.K_F10, QuakeLib.K_F11, QuakeLib.K_F12, 0, 0, 0, 0, 0, 0, 0, // 140.. 274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 150.. 275 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160 276 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170.. 277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 180.. 278 }; 279 280 private class QuakeRenderer implements GLSurfaceView.Renderer { 281 private static final String TAG = "QuakeRenderer"; 282 public void onDrawFrame(GL10 gl) { 283 if (mWidth != 0 && mHeight != 0) { 284 mGameMode = mQuakeLib.step(mWidth, mHeight); 285 } 286 } 287 288 public void onSurfaceChanged(GL10 gl, int width, int height) { 289 mWidth = width; 290 mHeight = height; 291 mQuakeLib.init(); 292 } 293 294 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 295 // Do nothing. 296 } 297 private int mWidth; 298 private int mHeight; 299 } 300 301 private QuakeLib mQuakeLib; 302 private boolean mGameMode; 303} 304 305