/ime/latinime/src/com/googlecode/eyesfree/inputmethod/latin/LatinKeyboardView.java

http://eyes-free.googlecode.com/ · Java · 327 lines · 269 code · 30 blank · 28 comment · 49 complexity · bccfcdb040517fdfa0983acb1a9312c5 MD5 · raw file

  1. /*
  2. * Copyright (C) 2008 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * 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, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.googlecode.eyesfree.inputmethod.latin;
  17. import android.content.Context;
  18. import android.graphics.Canvas;
  19. import android.graphics.Paint;
  20. import android.inputmethodservice.Keyboard;
  21. import android.inputmethodservice.Keyboard.Key;
  22. import android.os.Handler;
  23. import android.os.Message;
  24. import android.os.SystemClock;
  25. import android.text.TextUtils;
  26. import android.util.AttributeSet;
  27. import android.view.KeyEvent;
  28. import android.view.MotionEvent;
  29. import java.util.List;
  30. public class LatinKeyboardView extends LatinKeyboardBaseView {
  31. public static final int KEYCODE_TAB = 9;
  32. public static final int KEYCODE_RETURN = 10;
  33. public static final int KEYCODE_SPACE = 32;
  34. public static final int KEYCODE_SHIFT = -1;
  35. public static final int KEYCODE_SYMBOL = -2;
  36. public static final int KEYCODE_DELETE = -5;
  37. public static final int KEYCODE_OPTIONS = -100;
  38. public static final int KEYCODE_OPTIONS_LONGPRESS = -101;
  39. public static final int KEYCODE_VOICE = -102;
  40. public static final int KEYCODE_F1 = -103;
  41. public static final int KEYCODE_NEXT_LANGUAGE = -104;
  42. public static final int KEYCODE_PREV_LANGUAGE = -105;
  43. public static final int KEYCODE_BACK = -106;
  44. public static final int KEYCODE_SEARCH = -107;
  45. public static final int KEYCODE_HOME = -108;
  46. public static final int KEYCODE_MENU = -109;
  47. public static final int KEYCODE_CALL = -110;
  48. public static final int KEYCODE_ENDCALL = -111;
  49. public static final int KEYCODE_ALT = -112;
  50. public static final int KEYCODE_DPAD_UP = -113;
  51. public static final int KEYCODE_DPAD_LEFT = -114;
  52. public static final int KEYCODE_DPAD_CENTER = -115;
  53. public static final int KEYCODE_DPAD_RIGHT = -116;
  54. public static final int KEYCODE_DPAD_DOWN = -117;
  55. public static final int KEYCODE_UNKNOWN = Integer.MIN_VALUE;
  56. /**
  57. * Returns the key code from {@link KeyEvent} for a given internal key code.
  58. *
  59. * @param internalKeyCode The internal key code.
  60. * @return the key code from {@link KeyEvent}
  61. */
  62. static int getKeyCode(int internalKeyCode) {
  63. switch (internalKeyCode) {
  64. case KEYCODE_BACK:
  65. return KeyEvent.KEYCODE_BACK;
  66. case KEYCODE_SEARCH:
  67. return KeyEvent.KEYCODE_SEARCH;
  68. case KEYCODE_MENU:
  69. return KeyEvent.KEYCODE_MENU;
  70. case KEYCODE_CALL:
  71. return KeyEvent.KEYCODE_CALL;
  72. case KEYCODE_ENDCALL:
  73. return KeyEvent.KEYCODE_ENDCALL;
  74. case KEYCODE_ALT:
  75. return KeyEvent.KEYCODE_ALT_LEFT;
  76. case KEYCODE_DPAD_UP:
  77. return KeyEvent.KEYCODE_DPAD_UP;
  78. case KEYCODE_DPAD_LEFT:
  79. return KeyEvent.KEYCODE_DPAD_LEFT;
  80. case KEYCODE_DPAD_CENTER:
  81. return KeyEvent.KEYCODE_DPAD_CENTER;
  82. case KEYCODE_DPAD_RIGHT:
  83. return KeyEvent.KEYCODE_DPAD_RIGHT;
  84. case KEYCODE_DPAD_DOWN:
  85. return KeyEvent.KEYCODE_DPAD_DOWN;
  86. default:
  87. return KeyEvent.KEYCODE_UNKNOWN;
  88. }
  89. }
  90. private Keyboard mPhoneKeyboard;
  91. public LatinKeyboardView(Context context, AttributeSet attrs) {
  92. this(context, attrs, 0);
  93. }
  94. public LatinKeyboardView(Context context, AttributeSet attrs, int defStyle) {
  95. super(context, attrs, defStyle);
  96. }
  97. public void setPhoneKeyboard(Keyboard phoneKeyboard) {
  98. mPhoneKeyboard = phoneKeyboard;
  99. }
  100. @Override
  101. public void setPreviewEnabled(boolean previewEnabled) {
  102. if (getKeyboard() == mPhoneKeyboard) {
  103. // Phone keyboard never shows popup preview (except language switch).
  104. super.setPreviewEnabled(false);
  105. } else {
  106. super.setPreviewEnabled(previewEnabled);
  107. }
  108. }
  109. @Override
  110. public void setKeyboard(Keyboard k) {
  111. super.setKeyboard(k);
  112. setKeyboardLocal(k);
  113. }
  114. @Override
  115. protected boolean onLongPress(Key key) {
  116. int primaryCode = key.codes[0];
  117. if (primaryCode == KEYCODE_OPTIONS) {
  118. return invokeOnKey(KEYCODE_OPTIONS_LONGPRESS);
  119. } else if (primaryCode == '0' && getKeyboard() == mPhoneKeyboard) {
  120. // Long pressing on 0 in phone number keypad gives you a '+'.
  121. return invokeOnKey('+');
  122. } else {
  123. return super.onLongPress(key);
  124. }
  125. }
  126. private boolean invokeOnKey(int primaryCode) {
  127. getOnKeyboardActionListener().onKey(primaryCode, null,
  128. LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE,
  129. LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE);
  130. return true;
  131. }
  132. @Override
  133. protected CharSequence adjustCase(CharSequence label) {
  134. Keyboard keyboard = getKeyboard();
  135. if (keyboard.isShifted()
  136. && keyboard instanceof LatinKeyboard
  137. && ((LatinKeyboard) keyboard).isAlphaKeyboard()
  138. && !TextUtils.isEmpty(label) && label.length() < 3
  139. && Character.isLowerCase(label.charAt(0))) {
  140. label = label.toString().toUpperCase();
  141. }
  142. return label;
  143. }
  144. public boolean setShiftLocked(boolean shiftLocked) {
  145. Keyboard keyboard = getKeyboard();
  146. if (keyboard instanceof LatinKeyboard) {
  147. ((LatinKeyboard)keyboard).setShiftLocked(shiftLocked);
  148. invalidateAllKeys();
  149. return true;
  150. }
  151. return false;
  152. }
  153. public boolean isShiftLocked() {
  154. Keyboard keyboard = getKeyboard();
  155. if (keyboard instanceof LatinKeyboard) {
  156. return ((LatinKeyboard)keyboard).isShiftLocked();
  157. }
  158. return false;
  159. }
  160. @Override
  161. public boolean onTouchEvent(MotionEvent me) {
  162. LatinKeyboard keyboard = (LatinKeyboard) getKeyboard();
  163. if (DEBUG_LINE) {
  164. mLastX = (int) me.getX();
  165. mLastY = (int) me.getY();
  166. invalidate();
  167. }
  168. // Reset any bounding box controls in the keyboard
  169. if (me.getAction() == MotionEvent.ACTION_DOWN) {
  170. keyboard.keyReleased();
  171. }
  172. return super.onTouchEvent(me);
  173. }
  174. /**************************** INSTRUMENTATION *******************************/
  175. static final boolean DEBUG_AUTO_PLAY = false;
  176. static final boolean DEBUG_LINE = false;
  177. private static final int MSG_TOUCH_DOWN = 1;
  178. private static final int MSG_TOUCH_UP = 2;
  179. Handler mHandler2;
  180. private String mStringToPlay;
  181. private int mStringIndex;
  182. private boolean mDownDelivered;
  183. private Key[] mAsciiKeys = new Key[256];
  184. private boolean mPlaying;
  185. private int mLastX;
  186. private int mLastY;
  187. private Paint mPaint;
  188. private void setKeyboardLocal(Keyboard k) {
  189. if (DEBUG_AUTO_PLAY) {
  190. findKeys();
  191. if (mHandler2 == null) {
  192. mHandler2 = new Handler() {
  193. @Override
  194. public void handleMessage(Message msg) {
  195. removeMessages(MSG_TOUCH_DOWN);
  196. removeMessages(MSG_TOUCH_UP);
  197. if (mPlaying == false) return;
  198. switch (msg.what) {
  199. case MSG_TOUCH_DOWN:
  200. if (mStringIndex >= mStringToPlay.length()) {
  201. mPlaying = false;
  202. return;
  203. }
  204. char c = mStringToPlay.charAt(mStringIndex);
  205. while (c > 255 || mAsciiKeys[c] == null) {
  206. mStringIndex++;
  207. if (mStringIndex >= mStringToPlay.length()) {
  208. mPlaying = false;
  209. return;
  210. }
  211. c = mStringToPlay.charAt(mStringIndex);
  212. }
  213. int x = mAsciiKeys[c].x + 10;
  214. int y = mAsciiKeys[c].y + 26;
  215. MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
  216. SystemClock.uptimeMillis(),
  217. MotionEvent.ACTION_DOWN, x, y, 0);
  218. LatinKeyboardView.this.dispatchTouchEvent(me);
  219. me.recycle();
  220. sendEmptyMessageDelayed(MSG_TOUCH_UP, 500); // Deliver up in 500ms if nothing else
  221. // happens
  222. mDownDelivered = true;
  223. break;
  224. case MSG_TOUCH_UP:
  225. char cUp = mStringToPlay.charAt(mStringIndex);
  226. int x2 = mAsciiKeys[cUp].x + 10;
  227. int y2 = mAsciiKeys[cUp].y + 26;
  228. mStringIndex++;
  229. MotionEvent me2 = MotionEvent.obtain(SystemClock.uptimeMillis(),
  230. SystemClock.uptimeMillis(),
  231. MotionEvent.ACTION_UP, x2, y2, 0);
  232. LatinKeyboardView.this.dispatchTouchEvent(me2);
  233. me2.recycle();
  234. sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 500); // Deliver up in 500ms if nothing else
  235. // happens
  236. mDownDelivered = false;
  237. break;
  238. }
  239. }
  240. };
  241. }
  242. }
  243. }
  244. private void findKeys() {
  245. List<Key> keys = getKeyboard().getKeys();
  246. // Get the keys on this keyboard
  247. for (int i = 0; i < keys.size(); i++) {
  248. int code = keys.get(i).codes[0];
  249. if (code >= 0 && code <= 255) {
  250. mAsciiKeys[code] = keys.get(i);
  251. }
  252. }
  253. }
  254. public void startPlaying(String s) {
  255. if (DEBUG_AUTO_PLAY) {
  256. if (s == null) return;
  257. mStringToPlay = s.toLowerCase();
  258. mPlaying = true;
  259. mDownDelivered = false;
  260. mStringIndex = 0;
  261. mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 10);
  262. }
  263. }
  264. @Override
  265. public void draw(Canvas c) {
  266. LatinIMEUtil.GCUtils.getInstance().reset();
  267. boolean tryGC = true;
  268. for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
  269. try {
  270. super.draw(c);
  271. tryGC = false;
  272. } catch (OutOfMemoryError e) {
  273. tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait("LatinKeyboardView", e);
  274. }
  275. }
  276. if (DEBUG_AUTO_PLAY) {
  277. if (mPlaying) {
  278. mHandler2.removeMessages(MSG_TOUCH_DOWN);
  279. mHandler2.removeMessages(MSG_TOUCH_UP);
  280. if (mDownDelivered) {
  281. mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_UP, 20);
  282. } else {
  283. mHandler2.sendEmptyMessageDelayed(MSG_TOUCH_DOWN, 20);
  284. }
  285. }
  286. }
  287. if (DEBUG_LINE) {
  288. if (mPaint == null) {
  289. mPaint = new Paint();
  290. mPaint.setColor(0x80FFFFFF);
  291. mPaint.setAntiAlias(false);
  292. }
  293. c.drawLine(mLastX, 0, mLastX, getHeight(), mPaint);
  294. c.drawLine(0, mLastY, getWidth(), mLastY, mPaint);
  295. }
  296. }
  297. }