Back to project page ZShaolin.
The source code is released under:
GNU General Public License
If you think the Android project ZShaolin listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright (C) 2007 The Android Open Source Project *//from ww w . j a va2 s . c om * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.spartacusrex.spartacuside; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.Typeface; import android.os.Bundle; import android.os.Handler; import android.os.Environment; import android.text.ClipboardManager; import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import com.spartacusrex.spartacuside.model.TextRenderer; import com.spartacusrex.spartacuside.model.UpdateCallback; import com.spartacusrex.spartacuside.session.TerminalEmulator; import com.spartacusrex.spartacuside.session.TermSession; import com.spartacusrex.spartacuside.session.TranscriptScreen; import com.spartacusrex.spartacuside.util.TermSettings; import com.spartacusrex.spartacuside.util.hardkeymappings; import com.spartacusrex.spartacuside.util.keydata; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.Vector; import org.dyne.zshaolin.R; /** * A view on a transcript and a terminal emulator. Displays the text of the * transcript and the current cursor position of the terminal emulator. */ public class EmulatorView extends View implements GestureDetector.OnGestureListener { private final String TAG = "EmulatorView"; private final boolean LOG_KEY_EVENTS = false; private TermSettings mSettings; private TermViewFlipper mViewFlipper; /** * We defer some initialization until we have been layed out in the view * hierarchy. The boolean tracks when we know what our size is. */ private boolean mKnownSize; private int mVisibleWidth; private int mVisibleHeight; private Rect mVisibleRect = new Rect(); private TermSession mTermSession; /** * Our transcript. Contains the screen and the transcript. */ private TranscriptScreen mTranscriptScreen; /** * Total width of each character, in pixels */ private float mCharacterWidth; /** * Total height of each character, in pixels */ private int mCharacterHeight; /** * Used to render text */ private TextRenderer mTextRenderer; /** * Text size. Zero means 4 x 8 font. */ private int mTextSize; private int mCursorStyle; private int mCursorBlink; /** * Foreground color. */ private int mForeground; /** * Background color. */ private int mBackground; /** * Used to paint the cursor */ private Paint mCursorPaint; private Paint mBackgroundPaint; private boolean mUseCookedIme; /** * Our terminal emulator. We use this to get the current cursor position. */ private TerminalEmulator mEmulator; /** * The number of rows of text to display. */ private int mRows; /** * The number of columns of text to display. */ private int mColumns; /** * The number of columns that are visible on the display. */ private int mVisibleColumns; /** * The top row of text to display. Ranges from -activeTranscriptRows to 0 */ private int mTopRow; private int mLeftColumn; /** * Used to receive data from the remote process. */ private FileOutputStream mTermOut; private static final int SCREEN_CHECK_PERIOD = 1000; private static final int CURSOR_BLINK_PERIOD = 1000; private boolean mCursorVisible = true; private boolean mIsSelectingText = false; private float mDensity; private float mScaledDensity; private static final int SELECT_TEXT_OFFSET_Y = -40; private int mSelXAnchor = -1; private int mSelYAnchor = -1; private int mSelX1 = -1; private int mSelY1 = -1; private int mSelX2 = -1; private int mSelY2 = -1; /** * Used to poll if the view has changed size. Wish there was a better way to do this. */ private Runnable mCheckSize = new Runnable() { public void run() { updateSize(false); mHandler.postDelayed(this, SCREEN_CHECK_PERIOD); } }; private Runnable mBlinkCursor = new Runnable() { public void run() { if (mCursorBlink != 0) { mCursorVisible = ! mCursorVisible; mHandler.postDelayed(this, CURSOR_BLINK_PERIOD); } else { mCursorVisible = true; } // Perhaps just invalidate the character with the cursor. invalidate(); } }; private GestureDetector mGestureDetector; private float mScrollRemainder; private TermKeyListener mKeyListener; private String mImeBuffer = ""; /** * Our message handler class. Implements a periodic callback. */ private final Handler mHandler = new Handler(); Animation mAnimLeftIn; Animation mAnimRightIn; Animation mAnimLeftOut; Animation mAnimRightOut; /** * Called by the TermSession when the contents of the view need updating */ private UpdateCallback mUpdateNotify = new UpdateCallback() { public void onUpdate() { if ( mIsSelectingText ) { int rowShift = mEmulator.getScrollCounter(); mSelY1 -= rowShift; mSelY2 -= rowShift; mSelYAnchor -= rowShift; } mEmulator.clearScrollCounter(); ensureCursorVisible(); invalidate(); } }; public UpdateCallback getUpdateCallback() { return mUpdateNotify; } public EmulatorView(Context context, TermSession session, TermViewFlipper viewFlipper, DisplayMetrics metrics) { super(context); commonConstructor(session, viewFlipper); setDensity(metrics); mAnimLeftIn = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left); mAnimLeftOut = AnimationUtils.loadAnimation(context, R.anim.slide_out_left); mAnimRightIn = AnimationUtils.loadAnimation(context, R.anim.slide_in_right); mAnimRightOut = AnimationUtils.loadAnimation(context, android.R.anim.slide_out_right); } public void setDensity(DisplayMetrics metrics) { mDensity = metrics.density; mScaledDensity = metrics.scaledDensity; } public void onResume() { updateSize(false); mHandler.postDelayed(mCheckSize, SCREEN_CHECK_PERIOD); if (mCursorBlink != 0) { mHandler.postDelayed(mBlinkCursor, CURSOR_BLINK_PERIOD); } } public void onPause() { mHandler.removeCallbacks(mCheckSize); if (mCursorBlink != 0) { mHandler.removeCallbacks(mBlinkCursor); } } public void updatePrefs(TermSettings settings) { mSettings = settings; setTextSize((int) (mSettings.getFontSize() * mDensity)); setCursorStyle(mSettings.getCursorStyle(), mSettings.getCursorBlink()); setUseCookedIME(mSettings.useCookedIME()); setColors(); } public void setColors() { int[] scheme = mSettings.getColorScheme(); mForeground = scheme[0]; mBackground = scheme[1]; updateText(); } public void resetTerminal() { mEmulator.reset(); invalidate(); } @Override public boolean onCheckIsTextEditor() { return true; } @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { outAttrs.inputType = mUseCookedIme ? EditorInfo.TYPE_CLASS_TEXT : EditorInfo.TYPE_NULL; return new InputConnection() { private boolean mInBatchEdit; /** * Used to handle composing text requests */ private int mCursor; private int mComposingTextStart; private int mComposingTextEnd; private int mSelectedTextStart = 0; private int mSelectedTextEnd = 0; private void sendChar(int c) { try { mapAndSend(c); } catch (IOException ex) { } } private void sendText(CharSequence text) { int n = text.length(); try { for(int i = 0; i < n; i++) { char c = text.charAt(i); mapAndSend(c); } mTermOut.flush(); } catch (IOException e) { Log.e(TAG, "error writing ", e); } } private void mapAndSend(int c) throws IOException { int result = mKeyListener.mapControlChar(c); if (result < TermKeyListener.KEYCODE_OFFSET) { // Log.v("SpartacusRex","EMVIEW : 1) mapAndSend "+c+" "+result); //Check for ALT //if(mAl) mTermOut.write(result); } else { int code = result - TermKeyListener.KEYCODE_OFFSET; // Log.v("SpartacusRex","EMVIEW : 2) mapAndSend "+c+" "+code); mKeyListener.handleKeyCode(result - TermKeyListener.KEYCODE_OFFSET, mTermOut, getKeypadApplicationMode()); } } public boolean beginBatchEdit() { if (TermDebug.LOG_IME) { Log.w(TAG, "beginBatchEdit"); } setImeBuffer(""); mCursor = 0; mComposingTextStart = 0; mComposingTextEnd = 0; mInBatchEdit = true; return true; } public boolean clearMetaKeyStates(int arg0) { if (TermDebug.LOG_IME) { Log.w(TAG, "clearMetaKeyStates " + arg0); } return false; } public boolean commitCompletion(CompletionInfo arg0) { if (TermDebug.LOG_IME) { Log.w(TAG, "commitCompletion " + arg0); } return false; } public boolean endBatchEdit() { if (TermDebug.LOG_IME) { Log.w(TAG, "endBatchEdit"); } mInBatchEdit = false; return true; } public boolean finishComposingText() { if (TermDebug.LOG_IME) { Log.w(TAG, "finishComposingText"); } sendText(mImeBuffer); setImeBuffer(""); mComposingTextStart = 0; mComposingTextEnd = 0; mCursor = 0; return true; } public int getCursorCapsMode(int arg0) { if (TermDebug.LOG_IME) { Log.w(TAG, "getCursorCapsMode(" + arg0 + ")"); } return 0; } public ExtractedText getExtractedText(ExtractedTextRequest arg0, int arg1) { if (TermDebug.LOG_IME) { Log.w(TAG, "getExtractedText" + arg0 + "," + arg1); } return null; } public CharSequence getTextAfterCursor(int n, int flags) { if (TermDebug.LOG_IME) { Log.w(TAG, "getTextAfterCursor(" + n + "," + flags + ")"); } int len = Math.min(n, mImeBuffer.length() - mCursor); if (len <= 0 || mCursor < 0 || mCursor >= mImeBuffer.length()) { return ""; } return mImeBuffer.substring(mCursor, mCursor + len); } public CharSequence getTextBeforeCursor(int n, int flags) { if (TermDebug.LOG_IME) { Log.w(TAG, "getTextBeforeCursor(" + n + "," + flags + ")"); } int len = Math.min(n, mCursor); if (len <= 0 || mCursor < 0 || mCursor >= mImeBuffer.length()) { return ""; } return mImeBuffer.substring(mCursor-len, mCursor); } public boolean performContextMenuAction(int arg0) { if (TermDebug.LOG_IME) { Log.w(TAG, "performContextMenuAction" + arg0); } return true; } public boolean performPrivateCommand(String arg0, Bundle arg1) { if (TermDebug.LOG_IME) { Log.w(TAG, "performPrivateCommand" + arg0 + "," + arg1); } return true; } public boolean reportFullscreenMode(boolean arg0) { if (TermDebug.LOG_IME) { Log.w(TAG, "reportFullscreenMode" + arg0); } return true; } public boolean commitCorrection (CorrectionInfo correctionInfo) { if (TermDebug.LOG_IME) { Log.w(TAG, "commitCorrection"); } return true; } public boolean commitText(CharSequence text, int newCursorPosition) { if (TermDebug.LOG_IME) { Log.w(TAG, "commitText(\"" + text + "\", " + newCursorPosition + ")"); } clearComposingText(); sendText(text); setImeBuffer(""); mCursor = 0; return true; } private void clearComposingText() { setImeBuffer(mImeBuffer.substring(0, mComposingTextStart) + mImeBuffer.substring(mComposingTextEnd)); if (mCursor < mComposingTextStart) { // do nothing } else if (mCursor < mComposingTextEnd) { mCursor = mComposingTextStart; } else { mCursor -= mComposingTextEnd - mComposingTextStart; } mComposingTextEnd = mComposingTextStart = 0; } public boolean deleteSurroundingText(int leftLength, int rightLength) { if (TermDebug.LOG_IME) { Log.w(TAG, "deleteSurroundingText(" + leftLength + "," + rightLength + ")"); } if (leftLength > 0) { for (int i = 0; i < leftLength; i++) { sendKeyEvent( new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); } } else if ((leftLength == 0) && (rightLength == 0)) { // Delete key held down / repeating sendKeyEvent( new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL)); } // TODO: handle forward deletes. return true; } public boolean performEditorAction(int actionCode) { if (TermDebug.LOG_IME) { Log.w(TAG, "performEditorAction(" + actionCode + ")"); } if (actionCode == EditorInfo.IME_ACTION_UNSPECIFIED) { // The "return" key has been pressed on the IME. sendText("\n"); } return true; } public boolean sendKeyEvent(KeyEvent event) { if (TermDebug.LOG_IME) { Log.w(TAG, "sendKeyEvent(" + event + ")"); } // Some keys are sent here rather than to commitText. // In particular, del and the digit keys are sent here. // (And I have reports that the HTC Magic also sends Return here.) // As a bit of defensive programming, handle every key. dispatchKeyEvent(event); return true; } public boolean setComposingText(CharSequence text, int newCursorPosition) { if (TermDebug.LOG_IME) { Log.w(TAG, "setComposingText(\"" + text + "\", " + newCursorPosition + ")"); } setImeBuffer(mImeBuffer.substring(0, mComposingTextStart) + text + mImeBuffer.substring(mComposingTextEnd)); mComposingTextEnd = mComposingTextStart + text.length(); mCursor = newCursorPosition > 0 ? mComposingTextEnd + newCursorPosition - 1 : mComposingTextStart - newCursorPosition; return true; } public boolean setSelection(int start, int end) { if (TermDebug.LOG_IME) { Log.w(TAG, "setSelection" + start + "," + end); } int length = mImeBuffer.length(); if (start == end && start > 0 && start < length) { mSelectedTextStart = mSelectedTextEnd = 0; mCursor = start; } else if (start < end && start > 0 && end < length) { mSelectedTextStart = start; mSelectedTextEnd = end; mCursor = start; } return true; } public boolean setComposingRegion(int start, int end) { if (TermDebug.LOG_IME) { Log.w(TAG, "setComposingRegion " + start + "," + end); } if (start < end && start > 0 && end < mImeBuffer.length()) { clearComposingText(); mComposingTextStart = start; mComposingTextEnd = end; } return true; } public CharSequence getSelectedText(int flags) { try { if (TermDebug.LOG_IME) { Log.w(TAG, "getSelectedText " + flags); } if (mImeBuffer.length() < 1) { return ""; } return mImeBuffer.substring(mSelectedTextStart, mSelectedTextEnd + 1); } catch (Exception e) { } return ""; } }; } private void setImeBuffer(String buffer) { if (!buffer.equals(mImeBuffer)) { invalidate(); } mImeBuffer = buffer; } public boolean getKeypadApplicationMode() { return mEmulator.getKeypadApplicationMode(); } private void commonConstructor(TermSession session, TermViewFlipper viewFlipper) { mTextRenderer = null; mCursorPaint = new Paint(); mCursorPaint.setARGB(255,128,128,128); mBackgroundPaint = new Paint(); mTopRow = 0; mLeftColumn = 0; mGestureDetector = new GestureDetector(this); // mGestureDetector.setIsLongpressEnabled(false); /* mGestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() { public boolean onSingleTapConfirmed(MotionEvent arg0) { return true; } public boolean onDoubleTap(MotionEvent arg0) { //Toggle the Soft Keyboard.. InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0); return true; } public boolean onDoubleTapEvent(MotionEvent arg0) { return true; } }); */ setVerticalScrollBarEnabled(true); setFocusable(true); setFocusableInTouchMode(true); initialize(session, viewFlipper); } @Override protected int computeVerticalScrollRange() { return mTranscriptScreen.getActiveRows(); } @Override protected int computeVerticalScrollExtent() { return mRows; } @Override protected int computeVerticalScrollOffset() { return mTranscriptScreen.getActiveRows() + mTopRow - mRows; } /** * Call this to initialize the view. * * @param session The terminal session this view will be displaying */ private void initialize(TermSession session, TermViewFlipper viewFlipper) { mTermSession = session; mTranscriptScreen = session.getTranscriptScreen(); mEmulator = session.getEmulator(); mTermOut = session.getTermOut(); mViewFlipper = viewFlipper; mKeyListener = new TermKeyListener(); mTextSize = 10; mForeground = TermSettings.WHITE; mBackground = TermSettings.BLACK; updateText(); requestFocus(); } public TermSession getTermSession() { return mTermSession; } /** * Page the terminal view (scroll it up or down by delta screenfulls.) * * @param delta the number of screens to scroll. Positive means scroll down, * negative means scroll up. */ public void page(int delta) { mTopRow = Math.min(0, Math.max(-(mTranscriptScreen .getActiveTranscriptRows()), mTopRow + mRows * delta)); invalidate(); } /** * Page the terminal view horizontally. * * @param deltaColumns the number of columns to scroll. Positive scrolls to * the right. */ public void pageHorizontal(int deltaColumns) { mLeftColumn = Math.max(0, Math.min(mLeftColumn + deltaColumns, mColumns - mVisibleColumns)); invalidate(); } /** * Sets the text size, which in turn sets the number of rows and columns * * @param fontSize the new font size, in pixels. */ public void setTextSize(int fontSize) { mTextSize = fontSize; updateText(); } public void setCursorStyle(int style, int blink) { mCursorStyle = style; if (blink != 0 && mCursorBlink == 0) { mHandler.postDelayed(mBlinkCursor, CURSOR_BLINK_PERIOD); } else if (blink == 0 && mCursorBlink != 0) { mHandler.removeCallbacks(mBlinkCursor); } mCursorBlink = blink; } public void setUseCookedIME(boolean useCookedIME) { mUseCookedIme = useCookedIME; } // Begin GestureDetector.OnGestureListener methods public boolean onSingleTapUp(MotionEvent e) { return true; } public void onLongPress(MotionEvent e) { showContextMenu(); } public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { distanceY += mScrollRemainder; int deltaRows = (int) (distanceY / mCharacterHeight); mScrollRemainder = distanceY - deltaRows * mCharacterHeight; mTopRow = Math.min(0, Math.max(-(mTranscriptScreen .getActiveTranscriptRows()), mTopRow + deltaRows)); invalidate(); return true; } public void onSingleTapConfirmed(MotionEvent e) { } public boolean onJumpTapDown(MotionEvent e1, MotionEvent e2) { // Scroll to bottom mTopRow = 0; invalidate(); return true; } public boolean onJumpTapUp(MotionEvent e1, MotionEvent e2) { // Scroll to top mTopRow = -mTranscriptScreen.getActiveTranscriptRows(); invalidate(); return true; } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return true; /* if (Math.abs(velocityX) > Math.abs(velocityY)) { // Assume user wanted side to side movement if (velocityX > 0) { mViewFlipper.setOutAnimation(mAnimRightOut); mViewFlipper.setInAnimation(mAnimLeftIn); // Left to right swipe -- previous window mViewFlipper.showPrevious(); } else { mViewFlipper.setOutAnimation(mAnimLeftOut); mViewFlipper.setInAnimation(mAnimRightIn); // Right to left swipe -- next window mViewFlipper.showNext(); } } else { // TODO: add animation man's (non animated) fling mScrollRemainder = 0.0f; onScroll(e1, e2, 2 * velocityX, -2 * velocityY); } return true; */ } public void onShowPress(MotionEvent e) { } public boolean onDown(MotionEvent e) { mScrollRemainder = 0.0f; return true; } // End GestureDetector.OnGestureListener methods @Override public boolean onTouchEvent(MotionEvent ev) { if (mIsSelectingText) { return onTouchEventWhileSelectingText(ev); } else { return mGestureDetector.onTouchEvent(ev); } } private boolean onTouchEventWhileSelectingText(MotionEvent ev) { int action = ev.getAction(); int cx = (int)(ev.getX() / mCharacterWidth); int cy = Math.max(0, (int)((ev.getY() + SELECT_TEXT_OFFSET_Y * mScaledDensity) / mCharacterHeight) + mTopRow); switch (action) { case MotionEvent.ACTION_DOWN: mSelXAnchor = cx; mSelYAnchor = cy; mSelX1 = cx; mSelY1 = cy; mSelX2 = mSelX1; mSelY2 = mSelY1; break; case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_UP: int minx = Math.min(mSelXAnchor, cx); int maxx = Math.max(mSelXAnchor, cx); int miny = Math.min(mSelYAnchor, cy); int maxy = Math.max(mSelYAnchor, cy); mSelX1 = minx; mSelY1 = miny; mSelX2 = maxx; mSelY2 = maxy; if (action == MotionEvent.ACTION_UP) { ClipboardManager clip = (ClipboardManager) getContext().getApplicationContext() .getSystemService(Context.CLIPBOARD_SERVICE); clip.setText(getSelectedText().trim()); toggleSelectingText(); } invalidate(); break; default: toggleSelectingText(); invalidate(); break; } return true; } @Override public boolean onKeyDown(int zKeyCode, KeyEvent event) { if (LOG_KEY_EVENTS) { Log.v("Terminal IDE", "EmulatorView onKeyDown TOP EVENT code:"+zKeyCode); } //Could be scanning.. TermService.keyLoggerKey(zKeyCode); //Check with HardKey Mappings..! KeyEvent newevent = handleKeyCodeMapper(event.getAction(), zKeyCode); if(newevent == null){ //Function press.. return true; } //The new Key Code int keyCode = newevent.getKeyCode(); if (handleControlKey(keyCode, true)) { return true; } else if (handleFnKey(keyCode, true)) { //Send the escape key try { mKeyListener.keyDown(TermKeyListener.KEYCODE_ESCAPE, newevent, mTermOut, getKeypadApplicationMode()); } catch (IOException iOException) { } return true; } else if (isSystemKey(keyCode, newevent) && keyCode!=122 && keyCode!=123 && keyCode!=92 && keyCode!=93) { // Don't intercept the system keys And the HOME /END / PGUP / PGDOWN KEYS return super.onKeyDown(keyCode, newevent); } try { mKeyListener.keyDown(keyCode, newevent, mTermOut,getKeypadApplicationMode()); } catch (IOException e) { // Ignore I/O exceptions } return true; } @Override public boolean onKeyUp(int zKeyCode, KeyEvent event) { if (LOG_KEY_EVENTS) { Log.w(TAG, "onKeyUp " + zKeyCode); } //Check with HardKey Mappings..! KeyEvent newevent = handleKeyCodeMapper(event.getAction(), zKeyCode); if(newevent == null){ //Function press.. return true; } //The new Key Code int keyCode = newevent.getKeyCode(); if (handleControlKey(keyCode, false)) { return true; } else if (handleFnKey(keyCode, false)) { mKeyListener.keyUp(TermKeyListener.KEYCODE_ESCAPE); return true; } else if (isSystemKey(keyCode, newevent)) { // Don't intercept the system keys return super.onKeyUp(keyCode, newevent); } mKeyListener.keyUp(keyCode); return true; } private KeyEvent handleKeyCodeMapper(int zAction, int zKeyCode){ //Check with HardKey Mappings..! KeyEvent newevent = new KeyEvent(zAction, zKeyCode); if(TermService.isHardKeyEnabled()){ int hardmap = TermService.isSpecialKeyCode(zKeyCode); //Valid.. ? if(hardmap != -1){ //Its a special key code.. if(hardmap == hardkeymappings.HARDKEY_CTRL_LEFT || hardmap == hardkeymappings.HARDKEY_CTRL_RIGHT){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_CTRL_LEFT); }else if(hardmap == hardkeymappings.HARDKEY_ALT_LEFT || hardmap == hardkeymappings.HARDKEY_ALT_RIGHT){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_ALT_LEFT); }else if(hardmap == hardkeymappings.HARDKEY_ESCAPE){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_ESCAPE); }else if(hardmap == hardkeymappings.HARDKEY_FUNCTION){ //Just Update the Function Key Settings mKeyListener.handleFunctionKey(false); return null; }else if(hardmap == hardkeymappings.HARDKEY_TAB){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_TAB); }else if(hardmap == hardkeymappings.HARDKEY_LSHIFT || hardmap == hardkeymappings.HARDKEY_RSHIFT){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_SHIFT_LEFT); }else if(hardmap == hardkeymappings.HARDKEY_SPACE){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_SPACE); }else if(hardmap == hardkeymappings.HARDKEY_ENTER){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_ENTER); }else if(hardmap == hardkeymappings.HARDKEY_DELETE){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_FORWARD_DEL); }else if(hardmap == hardkeymappings.HARDKEY_BACKSPACE){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_DEL); }else if(hardmap == hardkeymappings.HARDKEY_UP){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_DPAD_UP); }else if(hardmap == hardkeymappings.HARDKEY_DOWN){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_DPAD_DOWN); }else if(hardmap == hardkeymappings.HARDKEY_LEFT){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_DPAD_LEFT); }else if(hardmap == hardkeymappings.HARDKEY_RIGHT){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_DPAD_RIGHT); }else if(hardmap == hardkeymappings.HARDKEY_PGUP){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_PAGE_UP); }else if(hardmap == hardkeymappings.HARDKEY_PGDOWN){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_PAGE_DOWN); }else if(hardmap == hardkeymappings.HARDKEY_HOME){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_MOVE_HOME); }else if(hardmap == hardkeymappings.HARDKEY_END){ newevent = new KeyEvent(zAction, TermKeyListener.KEYCODE_MOVE_END); } } } return newevent; } private boolean handleControlKey(int keyCode, boolean down) { if (keyCode == mSettings.getControlKeyCode()) { if (LOG_KEY_EVENTS) { Log.w(TAG, "handleControlKey " + keyCode); } mKeyListener.handleControlKey(down); return true; } return false; } private boolean handleFnKey(int keyCode, boolean down) { if (keyCode == mSettings.getFnKeyCode()) { if (LOG_KEY_EVENTS) { Log.w(TAG, "handleFnKey " + keyCode); } //if(down){ //Send the escape sequence.. //} //mKeyListener.handleFnKey(down); return true; } return false; } private boolean handleFunctionKey(boolean down) { if (LOG_KEY_EVENTS) { Log.w(TAG, "handleFunctionKey "); } mKeyListener.handleFunctionKey(down); return true; } private boolean isSystemKey(int keyCode, KeyEvent event) { return event.isSystem(); } private void updateText() { if (mTextSize > 0) { mTextRenderer = new PaintRenderer(mTextSize, mForeground, mBackground); } else { mTextRenderer = new Bitmap4x8FontRenderer(getResources(), mForeground, mBackground); } mBackgroundPaint.setColor(mBackground); mCharacterWidth = mTextRenderer.getCharacterWidth(); mCharacterHeight = mTextRenderer.getCharacterHeight(); updateSize(true); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { boolean oldKnownSize = mKnownSize; if (!mKnownSize) { mKnownSize = true; } updateSize(false); } private void updateSize(int w, int h) { mColumns = Math.max(1, (int) (((float) w) / mCharacterWidth)); mRows = Math.max(1, h / mCharacterHeight); mVisibleColumns = (int) (((float) mVisibleWidth) / mCharacterWidth); mTermSession.updateSize(mColumns, mRows); // Reset our paging: mTopRow = 0; mLeftColumn = 0; invalidate(); } public void updateSize(boolean force) { if (mKnownSize) { getWindowVisibleDisplayFrame(mVisibleRect); int w = mVisibleRect.width(); int h = mVisibleRect.height(); // Log.w("Term", "(" + w + ", " + h + ")"); if (force || w != mVisibleWidth || h != mVisibleHeight) { mVisibleWidth = w; mVisibleHeight = h; updateSize(mVisibleWidth, mVisibleHeight); } } } @Override protected void onDraw(Canvas canvas) { updateSize(false); int w = getWidth(); int h = getHeight(); canvas.drawRect(0, 0, w, h, mBackgroundPaint); float x = -mLeftColumn * mCharacterWidth; float y = mCharacterHeight; int endLine = mTopRow + mRows; int cx = mEmulator.getCursorCol(); int cy = mEmulator.getCursorRow(); for (int i = mTopRow; i < endLine; i++) { int cursorX = -1; if (i == cy && mCursorVisible) { cursorX = cx; } int selx1 = -1; int selx2 = -1; if ( i >= mSelY1 && i <= mSelY2 ) { if ( i == mSelY1 ) { selx1 = mSelX1; } if ( i == mSelY2 ) { selx2 = mSelX2; } else { selx2 = mColumns; } } mTranscriptScreen.drawText(i, canvas, x, y, mTextRenderer, cursorX, selx1, selx2, mImeBuffer); y += mCharacterHeight; } } private void ensureCursorVisible() { mTopRow = 0; if (mVisibleColumns > 0) { int cx = mEmulator.getCursorCol(); int visibleCursorX = mEmulator.getCursorCol() - mLeftColumn; if (visibleCursorX < 0) { mLeftColumn = cx; } else if (visibleCursorX >= mVisibleColumns) { mLeftColumn = (cx - mVisibleColumns) + 1; } } } public void toggleSelectingText() { mIsSelectingText = ! mIsSelectingText; setVerticalScrollBarEnabled( ! mIsSelectingText ); if ( ! mIsSelectingText ) { mSelX1 = -1; mSelY1 = -1; mSelX2 = -1; mSelY2 = -1; } } public boolean getSelectingText() { return mIsSelectingText; } public String getSelectedText() { return mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2); } } abstract class BaseTextRenderer implements TextRenderer { protected int[] mForePaint = { 0xff000000, // Black 0xffff0000, // Red 0xff00ff00, // green 0xffffff00, // yellow 0xff0000ff, // blue 0xffff00ff, // magenta 0xff00ffff, // cyan 0xffffffff // white -- is overridden by constructor }; protected int[] mBackPaint = { 0xff000000, // Black -- is overridden by constructor 0xffcc0000, // Red 0xff00cc00, // green 0xffcccc00, // yellow 0xff0000cc, // blue 0xffff00cc, // magenta 0xff00cccc, // cyan 0xffffffff // white }; protected final static int mCursorPaint = 0xff808080; public BaseTextRenderer(int forePaintColor, int backPaintColor) { mForePaint[7] = forePaintColor; mBackPaint[0] = backPaintColor; } } class Bitmap4x8FontRenderer extends BaseTextRenderer { private final static int kCharacterWidth = 4; private final static int kCharacterHeight = 8; private Bitmap mFont; private int mCurrentForeColor; private int mCurrentBackColor; private float[] mColorMatrix; private Paint mPaint; private static final float BYTE_SCALE = 1.0f / 255.0f; public Bitmap4x8FontRenderer(Resources resources, int forePaintColor, int backPaintColor) { super(forePaintColor, backPaintColor); mFont = BitmapFactory.decodeResource(resources, R.drawable.atari_small); mPaint = new Paint(); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); } public float getCharacterWidth() { return kCharacterWidth; } public int getCharacterHeight() { return kCharacterHeight; } public void drawTextRun(Canvas canvas, float x, float y, int lineOffset, char[] text, int index, int count, boolean cursor, int foreColor, int backColor) { setColorMatrix(mForePaint[foreColor & 7], cursor ? mCursorPaint : mBackPaint[backColor & 7]); int destX = (int) x + kCharacterWidth * lineOffset; int destY = (int) y; Rect srcRect = new Rect(); Rect destRect = new Rect(); destRect.top = (destY - kCharacterHeight); destRect.bottom = destY; for(int i = 0; i < count; i++) { char c = text[i + index]; if ((cursor || (c != 32)) && (c < 128)) { int cellX = c & 31; int cellY = (c >> 5) & 3; int srcX = cellX * kCharacterWidth; int srcY = cellY * kCharacterHeight; srcRect.set(srcX, srcY, srcX + kCharacterWidth, srcY + kCharacterHeight); destRect.left = destX; destRect.right = destX + kCharacterWidth; canvas.drawBitmap(mFont, srcRect, destRect, mPaint); } destX += kCharacterWidth; } } private void setColorMatrix(int foreColor, int backColor) { if ((foreColor != mCurrentForeColor) || (backColor != mCurrentBackColor) || (mColorMatrix == null)) { mCurrentForeColor = foreColor; mCurrentBackColor = backColor; if (mColorMatrix == null) { mColorMatrix = new float[20]; mColorMatrix[18] = 1.0f; // Just copy Alpha } for (int component = 0; component < 3; component++) { int rightShift = (2 - component) << 3; int fore = 0xff & (foreColor >> rightShift); int back = 0xff & (backColor >> rightShift); int delta = back - fore; mColorMatrix[component * 6] = delta * BYTE_SCALE; mColorMatrix[component * 5 + 4] = fore; } mPaint.setColorFilter(new ColorMatrixColorFilter(mColorMatrix)); } } } class PaintRenderer extends BaseTextRenderer { public PaintRenderer(int fontSize, int forePaintColor, int backPaintColor) { super(forePaintColor, backPaintColor); mTextPaint = new Paint(); // our own TTF font String fontfile = Environment.getExternalStorageDirectory().toString() + "/ZShaolin/" + "Font.ttf"; File file = new File(fontfile); if(file.exists()) { Typeface _font = Typeface.createFromFile(fontfile); mTextPaint.setTypeface(_font); } else mTextPaint.setTypeface(Typeface.MONOSPACE); mTextPaint.setAntiAlias(true); mTextPaint.setTextSize(fontSize); mCharHeight = (int) Math.ceil(mTextPaint.getFontSpacing()); mCharAscent = (int) Math.ceil(mTextPaint.ascent()); mCharDescent = mCharHeight + mCharAscent; mCharWidth = mTextPaint.measureText(EXAMPLE_CHAR, 0, 1); } public void drawTextRun(Canvas canvas, float x, float y, int lineOffset, char[] text, int index, int count, boolean cursor, int foreColor, int backColor) { if (cursor) { mTextPaint.setColor(mCursorPaint); } else { mTextPaint.setColor(mBackPaint[backColor & 0x7]); } float left = x + lineOffset * mCharWidth; canvas.drawRect(left, y + mCharAscent, left + count * mCharWidth, y + mCharDescent, mTextPaint); boolean bold = ( foreColor & 0x8 ) != 0; boolean underline = (backColor & 0x8) != 0; if (bold) { mTextPaint.setFakeBoldText(true); } if (underline) { mTextPaint.setUnderlineText(true); } mTextPaint.setColor(mForePaint[foreColor & 0x7]); canvas.drawText(text, index, count, left, y, mTextPaint); if (bold) { mTextPaint.setFakeBoldText(false); } if (underline) { mTextPaint.setUnderlineText(false); } } public int getCharacterHeight() { return mCharHeight; } public float getCharacterWidth() { return mCharWidth; } private Paint mTextPaint; private float mCharWidth; private int mCharHeight; private int mCharAscent; private int mCharDescent; private static final char[] EXAMPLE_CHAR = {'X'}; } /** * An ASCII key listener. Supports control characters and escape. Keeps track of * the current state of the alt, shift, and control keys. */ class TermKeyListener { /** * Android key codes that are defined in the Android 2.3 API. * We want to recognize these codes, because they will be sent to our * app when we run on Android 2.3 systems. * But we don't want to accidentally use 2.3-specific APIs. * So we compile against the Android 1.6 APIs, and have a copy of the codes here. */ /** Key code constant: Unknown key code. */ public static final int KEYCODE_UNKNOWN = 0; /** Key code constant: Soft Left key. * Usually situated below the display on phones and used as a multi-function * feature key for selecting a software defined function shown on the bottom left * of the display. */ public static final int KEYCODE_SOFT_LEFT = 1; /** Key code constant: Soft Right key. * Usually situated below the display on phones and used as a multi-function * feature key for selecting a software defined function shown on the bottom right * of the display. */ public static final int KEYCODE_SOFT_RIGHT = 2; /** Key code constant: Home key. * This key is handled by the framework and is never delivered to applications. */ public static final int KEYCODE_HOME = 3; /** Key code constant: Back key. */ public static final int KEYCODE_BACK = 4; /** Key code constant: Call key. */ public static final int KEYCODE_CALL = 5; /** Key code constant: End Call key. */ public static final int KEYCODE_ENDCALL = 6; /** Key code constant: '0' key. */ public static final int KEYCODE_0 = 7; /** Key code constant: '1' key. */ public static final int KEYCODE_1 = 8; /** Key code constant: '2' key. */ public static final int KEYCODE_2 = 9; /** Key code constant: '3' key. */ public static final int KEYCODE_3 = 10; /** Key code constant: '4' key. */ public static final int KEYCODE_4 = 11; /** Key code constant: '5' key. */ public static final int KEYCODE_5 = 12; /** Key code constant: '6' key. */ public static final int KEYCODE_6 = 13; /** Key code constant: '7' key. */ public static final int KEYCODE_7 = 14; /** Key code constant: '8' key. */ public static final int KEYCODE_8 = 15; /** Key code constant: '9' key. */ public static final int KEYCODE_9 = 16; /** Key code constant: '*' key. */ public static final int KEYCODE_STAR = 17; /** Key code constant: '#' key. */ public static final int KEYCODE_POUND = 18; /** Key code constant: Directional Pad Up key. * May also be synthesized from trackball motions. */ public static final int KEYCODE_DPAD_UP = 19; /** Key code constant: Directional Pad Down key. * May also be synthesized from trackball motions. */ public static final int KEYCODE_DPAD_DOWN = 20; /** Key code constant: Directional Pad Left key. * May also be synthesized from trackball motions. */ public static final int KEYCODE_DPAD_LEFT = 21; /** Key code constant: Directional Pad Right key. * May also be synthesized from trackball motions. */ public static final int KEYCODE_DPAD_RIGHT = 22; /** Key code constant: Directional Pad Center key. * May also be synthesized from trackball motions. */ public static final int KEYCODE_DPAD_CENTER = 23; /** Key code constant: Volume Up key. * Adjusts the speaker volume up. */ public static final int KEYCODE_VOLUME_UP = 24; /** Key code constant: Volume Down key. * Adjusts the speaker volume down. */ public static final int KEYCODE_VOLUME_DOWN = 25; /** Key code constant: Power key. */ public static final int KEYCODE_POWER = 26; /** Key code constant: Camera key. * Used to launch a camera application or take pictures. */ public static final int KEYCODE_CAMERA = 27; /** Key code constant: Clear key. */ public static final int KEYCODE_CLEAR = 28; /** Key code constant: 'A' key. */ public static final int KEYCODE_A = 29; /** Key code constant: 'B' key. */ public static final int KEYCODE_B = 30; /** Key code constant: 'C' key. */ public static final int KEYCODE_C = 31; /** Key code constant: 'D' key. */ public static final int KEYCODE_D = 32; /** Key code constant: 'E' key. */ public static final int KEYCODE_E = 33; /** Key code constant: 'F' key. */ public static final int KEYCODE_F = 34; /** Key code constant: 'G' key. */ public static final int KEYCODE_G = 35; /** Key code constant: 'H' key. */ public static final int KEYCODE_H = 36; /** Key code constant: 'I' key. */ public static final int KEYCODE_I = 37; /** Key code constant: 'J' key. */ public static final int KEYCODE_J = 38; /** Key code constant: 'K' key. */ public static final int KEYCODE_K = 39; /** Key code constant: 'L' key. */ public static final int KEYCODE_L = 40; /** Key code constant: 'M' key. */ public static final int KEYCODE_M = 41; /** Key code constant: 'N' key. */ public static final int KEYCODE_N = 42; /** Key code constant: 'O' key. */ public static final int KEYCODE_O = 43; /** Key code constant: 'P' key. */ public static final int KEYCODE_P = 44; /** Key code constant: 'Q' key. */ public static final int KEYCODE_Q = 45; /** Key code constant: 'R' key. */ public static final int KEYCODE_R = 46; /** Key code constant: 'S' key. */ public static final int KEYCODE_S = 47; /** Key code constant: 'T' key. */ public static final int KEYCODE_T = 48; /** Key code constant: 'U' key. */ public static final int KEYCODE_U = 49; /** Key code constant: 'V' key. */ public static final int KEYCODE_V = 50; /** Key code constant: 'W' key. */ public static final int KEYCODE_W = 51; /** Key code constant: 'X' key. */ public static final int KEYCODE_X = 52; /** Key code constant: 'Y' key. */ public static final int KEYCODE_Y = 53; /** Key code constant: 'Z' key. */ public static final int KEYCODE_Z = 54; /** Key code constant: ',' key. */ public static final int KEYCODE_COMMA = 55; /** Key code constant: '.' key. */ public static final int KEYCODE_PERIOD = 56; /** Key code constant: Left Alt modifier key. */ public static final int KEYCODE_ALT_LEFT = 57; /** Key code constant: Right Alt modifier key. */ public static final int KEYCODE_ALT_RIGHT = 58; /** Key code constant: Left Shift modifier key. */ public static final int KEYCODE_SHIFT_LEFT = 59; /** Key code constant: Right Shift modifier key. */ public static final int KEYCODE_SHIFT_RIGHT = 60; /** Key code constant: Tab key. */ public static final int KEYCODE_TAB = 61; /** Key code constant: Space key. */ public static final int KEYCODE_SPACE = 62; /** Key code constant: Symbol modifier key. * Used to enter alternate symbols. */ public static final int KEYCODE_SYM = 63; /** Key code constant: Explorer special function key. * Used to launch a browser application. */ public static final int KEYCODE_EXPLORER = 64; /** Key code constant: Envelope special function key. * Used to launch a mail application. */ public static final int KEYCODE_ENVELOPE = 65; /** Key code constant: Enter key. */ public static final int KEYCODE_ENTER = 66; /** Key code constant: Backspace key. * Deletes characters before the insertion point, unlike {@link #KEYCODE_FORWARD_DEL}. */ public static final int KEYCODE_DEL = 67; /** Key code constant: '`' (backtick) key. */ public static final int KEYCODE_GRAVE = 68; /** Key code constant: '-'. */ public static final int KEYCODE_MINUS = 69; /** Key code constant: '=' key. */ public static final int KEYCODE_EQUALS = 70; /** Key code constant: '[' key. */ public static final int KEYCODE_LEFT_BRACKET = 71; /** Key code constant: ']' key. */ public static final int KEYCODE_RIGHT_BRACKET = 72; /** Key code constant: '\' key. */ public static final int KEYCODE_BACKSLASH = 73; /** Key code constant: ';' key. */ public static final int KEYCODE_SEMICOLON = 74; /** Key code constant: ''' (apostrophe) key. */ public static final int KEYCODE_APOSTROPHE = 75; /** Key code constant: '/' key. */ public static final int KEYCODE_SLASH = 76; /** Key code constant: '@' key. */ public static final int KEYCODE_AT = 77; /** Key code constant: Number modifier key. * Used to enter numeric symbols. * This key is not Num Lock; it is more like {@link #KEYCODE_ALT_LEFT} and is * interpreted as an ALT key by {@link android.text.method.MetaKeyKeyListener}. */ public static final int KEYCODE_NUM = 78; /** Key code constant: Headset Hook key. * Used to hang up calls and stop media. */ public static final int KEYCODE_HEADSETHOOK = 79; /** Key code constant: Camera Focus key. * Used to focus the camera. */ public static final int KEYCODE_FOCUS = 80; // *Camera* focus /** Key code constant: '+' key. */ public static final int KEYCODE_PLUS = 81; /** Key code constant: Menu key. */ public static final int KEYCODE_MENU = 82; /** Key code constant: Notification key. */ public static final int KEYCODE_NOTIFICATION = 83; /** Key code constant: Search key. */ public static final int KEYCODE_SEARCH = 84; /** Key code constant: Play/Pause media key. */ public static final int KEYCODE_MEDIA_PLAY_PAUSE= 85; /** Key code constant: Stop media key. */ public static final int KEYCODE_MEDIA_STOP = 86; /** Key code constant: Play Next media key. */ public static final int KEYCODE_MEDIA_NEXT = 87; /** Key code constant: Play Previous media key. */ public static final int KEYCODE_MEDIA_PREVIOUS = 88; /** Key code constant: Rewind media key. */ public static final int KEYCODE_MEDIA_REWIND = 89; /** Key code constant: Fast Forward media key. */ public static final int KEYCODE_MEDIA_FAST_FORWARD = 90; /** Key code constant: Mute key. * Mutes the microphone, unlike {@link #KEYCODE_VOLUME_MUTE}. */ public static final int KEYCODE_MUTE = 91; /** Key code constant: Page Up key. */ public static final int KEYCODE_PAGE_UP = 92; /** Key code constant: Page Down key. */ public static final int KEYCODE_PAGE_DOWN = 93; /** Key code constant: Picture Symbols modifier key. * Used to switch symbol sets (Emoji, Kao-moji). */ public static final int KEYCODE_PICTSYMBOLS = 94; // switch symbol-sets (Emoji,Kao-moji) /** Key code constant: Switch Charset modifier key. * Used to switch character sets (Kanji, Katakana). */ public static final int KEYCODE_SWITCH_CHARSET = 95; // switch char-sets (Kanji,Katakana) /** Key code constant: A Button key. * On a game controller, the A button should be either the button labeled A * or the first button on the upper row of controller buttons. */ public static final int KEYCODE_BUTTON_A = 96; /** Key code constant: B Button key. * On a game controller, the B button should be either the button labeled B * or the second button on the upper row of controller buttons. */ public static final int KEYCODE_BUTTON_B = 97; /** Key code constant: C Button key. * On a game controller, the C button should be either the button labeled C * or the third button on the upper row of controller buttons. */ public static final int KEYCODE_BUTTON_C = 98; /** Key code constant: X Button key. * On a game controller, the X button should be either the button labeled X * or the first button on the lower row of controller buttons. */ public static final int KEYCODE_BUTTON_X = 99; /** Key code constant: Y Button key. * On a game controller, the Y button should be either the button labeled Y * or the second button on the lower row of controller buttons. */ public static final int KEYCODE_BUTTON_Y = 100; /** Key code constant: Z Button key. * On a game controller, the Z button should be either the button labeled Z * or the third button on the lower row of controller buttons. */ public static final int KEYCODE_BUTTON_Z = 101; /** Key code constant: L1 Button key. * On a game controller, the L1 button should be either the button labeled L1 (or L) * or the top left trigger button. */ public static final int KEYCODE_BUTTON_L1 = 102; /** Key code constant: R1 Button key. * On a game controller, the R1 button should be either the button labeled R1 (or R) * or the top right trigger button. */ public static final int KEYCODE_BUTTON_R1 = 103; /** Key code constant: L2 Button key. * On a game controller, the L2 button should be either the button labeled L2 * or the bottom left trigger button. */ public static final int KEYCODE_BUTTON_L2 = 104; /** Key code constant: R2 Button key. * On a game controller, the R2 button should be either the button labeled R2 * or the bottom right trigger button. */ public static final int KEYCODE_BUTTON_R2 = 105; /** Key code constant: Left Thumb Button key. * On a game controller, the left thumb button indicates that the left (or only) * joystick is pressed. */ public static final int KEYCODE_BUTTON_THUMBL = 106; /** Key code constant: Right Thumb Button key. * On a game controller, the right thumb button indicates that the right * joystick is pressed. */ public static final int KEYCODE_BUTTON_THUMBR = 107; /** Key code constant: Start Button key. * On a game controller, the button labeled Start. */ public static final int KEYCODE_BUTTON_START = 108; /** Key code constant: Select Button key. * On a game controller, the button labeled Select. */ public static final int KEYCODE_BUTTON_SELECT = 109; /** Key code constant: Mode Button key. * On a game controller, the button labeled Mode. */ public static final int KEYCODE_BUTTON_MODE = 110; /** Key code constant: Escape key. */ public static final int KEYCODE_ESCAPE = 111; /** Key code constant: Forward Delete key. * Deletes characters ahead of the insertion point, unlike {@link #KEYCODE_DEL}. */ public static final int KEYCODE_FORWARD_DEL = 112; /** Key code constant: Left Control modifier key. */ public static final int KEYCODE_CTRL_LEFT = 113; /** Key code constant: Right Control modifier key. */ public static final int KEYCODE_CTRL_RIGHT = 114; /** Key code constant: Caps Lock modifier key. */ public static final int KEYCODE_CAPS_LOCK = 115; /** Key code constant: Scroll Lock key. */ public static final int KEYCODE_SCROLL_LOCK = 116; /** Key code constant: Left Meta modifier key. */ public static final int KEYCODE_META_LEFT = 117; /** Key code constant: Right Meta modifier key. */ public static final int KEYCODE_META_RIGHT = 118; /** Key code constant: Function modifier key. */ public static final int KEYCODE_FUNCTION = 119; /** Key code constant: System Request / Print Screen key. */ public static final int KEYCODE_SYSRQ = 120; /** Key code constant: Break / Pause key. */ public static final int KEYCODE_BREAK = 121; /** Key code constant: Home Movement key. * Used for scrolling or moving the cursor around to the start of a line * or to the top of a list. */ public static final int KEYCODE_MOVE_HOME = 122; /** Key code constant: End Movement key. * Used for scrolling or moving the cursor around to the end of a line * or to the bottom of a list. */ public static final int KEYCODE_MOVE_END = 123; /** Key code constant: Insert key. * Toggles insert / overwrite edit mode. */ public static final int KEYCODE_INSERT = 124; /** Key code constant: Forward key. * Navigates forward in the history stack. Complement of {@link #KEYCODE_BACK}. */ public static final int KEYCODE_FORWARD = 125; /** Key code constant: Play media key. */ public static final int KEYCODE_MEDIA_PLAY = 126; /** Key code constant: Pause media key. */ public static final int KEYCODE_MEDIA_PAUSE = 127; /** Key code constant: Close media key. * May be used to close a CD tray, for example. */ public static final int KEYCODE_MEDIA_CLOSE = 128; /** Key code constant: Eject media key. * May be used to eject a CD tray, for example. */ public static final int KEYCODE_MEDIA_EJECT = 129; /** Key code constant: Record media key. */ public static final int KEYCODE_MEDIA_RECORD = 130; /** Key code constant: F1 key. */ public static final int KEYCODE_F1 = 131; /** Key code constant: F2 key. */ public static final int KEYCODE_F2 = 132; /** Key code constant: F3 key. */ public static final int KEYCODE_F3 = 133; /** Key code constant: F4 key. */ public static final int KEYCODE_F4 = 134; /** Key code constant: F5 key. */ public static final int KEYCODE_F5 = 135; /** Key code constant: F6 key. */ public static final int KEYCODE_F6 = 136; /** Key code constant: F7 key. */ public static final int KEYCODE_F7 = 137; /** Key code constant: F8 key. */ public static final int KEYCODE_F8 = 138; /** Key code constant: F9 key. */ public static final int KEYCODE_F9 = 139; /** Key code constant: F10 key. */ public static final int KEYCODE_F10 = 140; /** Key code constant: F11 key. */ public static final int KEYCODE_F11 = 141; /** Key code constant: F12 key. */ public static final int KEYCODE_F12 = 142; /** Key code constant: Num Lock modifier key. * This is the Num Lock key; it is different from {@link #KEYCODE_NUM}. * This key generally modifies the behavior of other keys on the numeric keypad. */ public static final int KEYCODE_NUM_LOCK = 143; /** Key code constant: Numeric keypad '0' key. */ public static final int KEYCODE_NUMPAD_0 = 144; /** Key code constant: Numeric keypad '1' key. */ public static final int KEYCODE_NUMPAD_1 = 145; /** Key code constant: Numeric keypad '2' key. */ public static final int KEYCODE_NUMPAD_2 = 146; /** Key code constant: Numeric keypad '3' key. */ public static final int KEYCODE_NUMPAD_3 = 147; /** Key code constant: Numeric keypad '4' key. */ public static final int KEYCODE_NUMPAD_4 = 148; /** Key code constant: Numeric keypad '5' key. */ public static final int KEYCODE_NUMPAD_5 = 149; /** Key code constant: Numeric keypad '6' key. */ public static final int KEYCODE_NUMPAD_6 = 150; /** Key code constant: Numeric keypad '7' key. */ public static final int KEYCODE_NUMPAD_7 = 151; /** Key code constant: Numeric keypad '8' key. */ public static final int KEYCODE_NUMPAD_8 = 152; /** Key code constant: Numeric keypad '9' key. */ public static final int KEYCODE_NUMPAD_9 = 153; /** Key code constant: Numeric keypad '/' key (for division). */ public static final int KEYCODE_NUMPAD_DIVIDE = 154; /** Key code constant: Numeric keypad '*' key (for multiplication). */ public static final int KEYCODE_NUMPAD_MULTIPLY = 155; /** Key code constant: Numeric keypad '-' key (for subtraction). */ public static final int KEYCODE_NUMPAD_SUBTRACT = 156; /** Key code constant: Numeric keypad '+' key (for addition). */ public static final int KEYCODE_NUMPAD_ADD = 157; /** Key code constant: Numeric keypad '.' key (for decimals or digit grouping). */ public static final int KEYCODE_NUMPAD_DOT = 158; /** Key code constant: Numeric keypad ',' key (for decimals or digit grouping). */ public static final int KEYCODE_NUMPAD_COMMA = 159; /** Key code constant: Numeric keypad Enter key. */ public static final int KEYCODE_NUMPAD_ENTER = 160; /** Key code constant: Numeric keypad '=' key. */ public static final int KEYCODE_NUMPAD_EQUALS = 161; /** Key code constant: Numeric keypad '(' key. */ public static final int KEYCODE_NUMPAD_LEFT_PAREN = 162; /** Key code constant: Numeric keypad ')' key. */ public static final int KEYCODE_NUMPAD_RIGHT_PAREN = 163; /** Key code constant: Volume Mute key. * Mutes the speaker, unlike {@link #KEYCODE_MUTE}. * This key should normally be implemented as a toggle such that the first press * mutes the speaker and the second press restores the original volume. */ public static final int KEYCODE_VOLUME_MUTE = 164; /** Key code constant: Info key. * Common on TV remotes to show additional information related to what is * currently being viewed. */ public static final int KEYCODE_INFO = 165; /** Key code constant: Channel up key. * On TV remotes, increments the television channel. */ public static final int KEYCODE_CHANNEL_UP = 166; /** Key code constant: Channel down key. * On TV remotes, decrements the television channel. */ public static final int KEYCODE_CHANNEL_DOWN = 167; /** Key code constant: Zoom in key. */ public static final int KEYCODE_ZOOM_IN = 168; /** Key code constant: Zoom out key. */ public static final int KEYCODE_ZOOM_OUT = 169; /** Key code constant: TV key. * On TV remotes, switches to viewing live TV. */ public static final int KEYCODE_TV = 170; /** Key code constant: Window key. * On TV remotes, toggles picture-in-picture mode or other windowing functions. */ public static final int KEYCODE_WINDOW = 171; /** Key code constant: Guide key. * On TV remotes, shows a programming guide. */ public static final int KEYCODE_GUIDE = 172; /** Key code constant: DVR key. * On some TV remotes, switches to a DVR mode for recorded shows. */ public static final int KEYCODE_DVR = 173; /** Key code constant: Bookmark key. * On some TV remotes, bookmarks content or web pages. */ public static final int KEYCODE_BOOKMARK = 174; /** Key code constant: Toggle captions key. * Switches the mode for closed-captioning text, for example during television shows. */ public static final int KEYCODE_CAPTIONS = 175; /** Key code constant: Settings key. * Starts the system settings activity. */ public static final int KEYCODE_SETTINGS = 176; /** Key code constant: TV power key. * On TV remotes, toggles the power on a television screen. */ public static final int KEYCODE_TV_POWER = 177; /** Key code constant: TV input key. * On TV remotes, switches the input on a television screen. */ public static final int KEYCODE_TV_INPUT = 178; /** Key code constant: Set-top-box power key. * On TV remotes, toggles the power on an external Set-top-box. */ public static final int KEYCODE_STB_POWER = 179; /** Key code constant: Set-top-box input key. * On TV remotes, switches the input mode on an external Set-top-box. */ public static final int KEYCODE_STB_INPUT = 180; /** Key code constant: A/V Receiver power key. * On TV remotes, toggles the power on an external A/V Receiver. */ public static final int KEYCODE_AVR_POWER = 181; /** Key code constant: A/V Receiver input key. * On TV remotes, switches the input mode on an external A/V Receiver. */ public static final int KEYCODE_AVR_INPUT = 182; /** Key code constant: Red "programmable" key. * On TV remotes, acts as a contextual/programmable key. */ public static final int KEYCODE_PROG_RED = 183; /** Key code constant: Green "programmable" key. * On TV remotes, actsas a contextual/programmable key. */ public static final int KEYCODE_PROG_GREEN = 184; /** Key code constant: Yellow "programmable" key. * On TV remotes, acts as a contextual/programmable key. */ public static final int KEYCODE_PROG_YELLOW = 185; /** Key code constant: Blue "programmable" key. * On TV remotes, acts as a contextual/programmable key. */ public static final int KEYCODE_PROG_BLUE = 186; private static final int LAST_KEYCODE = KEYCODE_PROG_BLUE; private String[] mKeyCodes = new String[256]; private String[] mCTRL_KeyCodes = new String[4]; private String[] mAppKeyCodes = new String[256]; private void initKeyCodes() { mKeyCodes[KEYCODE_DPAD_CENTER] = "\015"; mKeyCodes[KEYCODE_DPAD_UP] = "\033[A"; mKeyCodes[KEYCODE_DPAD_DOWN] = "\033[B"; mKeyCodes[KEYCODE_DPAD_RIGHT] = "\033[C"; mKeyCodes[KEYCODE_DPAD_LEFT] = "\033[D"; mCTRL_KeyCodes[0] = "\033[1;5A"; mCTRL_KeyCodes[1] = "\033[1;5B"; mCTRL_KeyCodes[2] = "\033[1;5C"; mCTRL_KeyCodes[3] = "\033[1;5D"; mKeyCodes[KEYCODE_F1] = "\033OP"; mKeyCodes[KEYCODE_F2] = "\033OQ"; mKeyCodes[KEYCODE_F3] = "\033OR"; mKeyCodes[KEYCODE_F4] = "\033OS"; // mKeyCodes[KEYCODE_F1] = "\033[11~"; // mKeyCodes[KEYCODE_F2] = "\033[12~"; // mKeyCodes[KEYCODE_F3] = "\033[13~"; // mKeyCodes[KEYCODE_F4] = "\033[14~"; mKeyCodes[KEYCODE_F5] = "\033[15~"; mKeyCodes[KEYCODE_F6] = "\033[17~"; mKeyCodes[KEYCODE_F7] = "\033[18~"; mKeyCodes[KEYCODE_F8] = "\033[19~"; mKeyCodes[KEYCODE_F9] = "\033[20~"; mKeyCodes[KEYCODE_F10] = "\033[21~"; mKeyCodes[KEYCODE_F11] = "\033[23~"; mKeyCodes[KEYCODE_F12] = "\033[24~"; mKeyCodes[KEYCODE_SYSRQ] = "\033[32~"; // Sys Request / Print // Is this Scroll lock? mKeyCodes[Cancel] = "\033[33~"; mKeyCodes[KEYCODE_BREAK] = "\033[34~"; // Pause/Break mKeyCodes[KEYCODE_TAB] = "\011"; mKeyCodes[KEYCODE_ENTER] = "\015"; mKeyCodes[KEYCODE_ESCAPE] = "\033"; mKeyCodes[KEYCODE_INSERT] = "\033[2~"; mKeyCodes[KEYCODE_FORWARD_DEL] = "\033[3~"; mKeyCodes[KEYCODE_MOVE_HOME] = "\033[1~"; mKeyCodes[KEYCODE_MOVE_END] = "\033[4~"; mKeyCodes[KEYCODE_PAGE_UP] = "\033[5~"; mKeyCodes[KEYCODE_PAGE_DOWN] = "\033[6~"; mKeyCodes[KEYCODE_DEL]= "\177"; mKeyCodes[KEYCODE_NUM_LOCK] = "\033OP"; mKeyCodes[KEYCODE_NUMPAD_DIVIDE] = "/"; mKeyCodes[KEYCODE_NUMPAD_MULTIPLY] = "*"; mKeyCodes[KEYCODE_NUMPAD_SUBTRACT] = "-"; mKeyCodes[KEYCODE_NUMPAD_ADD] = "+"; mKeyCodes[KEYCODE_NUMPAD_ENTER] = "\015"; mKeyCodes[KEYCODE_NUMPAD_EQUALS] = "="; mKeyCodes[KEYCODE_NUMPAD_DOT] = "."; mKeyCodes[KEYCODE_NUMPAD_COMMA] = ","; mKeyCodes[KEYCODE_NUMPAD_0] = "0"; mKeyCodes[KEYCODE_NUMPAD_1] = "1"; mKeyCodes[KEYCODE_NUMPAD_2] = "2"; mKeyCodes[KEYCODE_NUMPAD_3] = "3"; mKeyCodes[KEYCODE_NUMPAD_4] = "4"; mKeyCodes[KEYCODE_NUMPAD_5] = "5"; mKeyCodes[KEYCODE_NUMPAD_6] = "6"; mKeyCodes[KEYCODE_NUMPAD_7] = "7"; mKeyCodes[KEYCODE_NUMPAD_8] = "8"; mKeyCodes[KEYCODE_NUMPAD_9] = "9"; mAppKeyCodes[KEYCODE_DPAD_UP] = "\033OA"; mAppKeyCodes[KEYCODE_DPAD_DOWN] = "\033OB"; mAppKeyCodes[KEYCODE_DPAD_RIGHT] = "\033OC"; mAppKeyCodes[KEYCODE_DPAD_LEFT] = "\033OD"; mAppKeyCodes[KEYCODE_NUMPAD_DIVIDE] = "\033Oo"; mAppKeyCodes[KEYCODE_NUMPAD_MULTIPLY] = "\033Oj"; mAppKeyCodes[KEYCODE_NUMPAD_SUBTRACT] = "\033Om"; mAppKeyCodes[KEYCODE_NUMPAD_ADD] = "\033Ok"; mAppKeyCodes[KEYCODE_NUMPAD_ENTER] = "\033OM"; mAppKeyCodes[KEYCODE_NUMPAD_EQUALS] = "\033OX"; mAppKeyCodes[KEYCODE_NUMPAD_DOT] = "\033On"; mAppKeyCodes[KEYCODE_NUMPAD_COMMA] = "\033Ol"; mAppKeyCodes[KEYCODE_NUMPAD_0] = "\033Op"; mAppKeyCodes[KEYCODE_NUMPAD_1] = "\033Oq"; mAppKeyCodes[KEYCODE_NUMPAD_2] = "\033Or"; mAppKeyCodes[KEYCODE_NUMPAD_3] = "\033Os"; mAppKeyCodes[KEYCODE_NUMPAD_4] = "\033Ot"; mAppKeyCodes[KEYCODE_NUMPAD_5] = "\033Ou"; mAppKeyCodes[KEYCODE_NUMPAD_6] = "\033Ov"; mAppKeyCodes[KEYCODE_NUMPAD_7] = "\033Ow"; mAppKeyCodes[KEYCODE_NUMPAD_8] = "\033Ox"; mAppKeyCodes[KEYCODE_NUMPAD_9] = "\033Oy"; } /** * The state engine for a modifier key. Can be pressed, released, locked, * and so on. * */ private class ModifierKey { private int mState; private static final int UNPRESSED = 0; private static final int PRESSED = 1; private static final int RELEASED = 2; private static final int USED = 3; private static final int LOCKED = 4; private static final int ACTIVE = 5; private static final int OFF = 6; /** * Construct a modifier key. UNPRESSED by default. * */ public ModifierKey() { // mState = UNPRESSED; mState = OFF; } public void onPress() { /*switch (mState) { case PRESSED: // This is a repeat before use break; case RELEASED: mState = LOCKED; break; case USED: // This is a repeat after use break; case LOCKED: mState = UNPRESSED; break; default: mState = PRESSED; break; }*/ mState = ACTIVE; } public void onRelease() { /*switch (mState) { case USED: mState = UNPRESSED; break; case PRESSED: mState = RELEASED; break; default: // Leave state alone break; }*/ mState = OFF; } public void adjustAfterKeypress() { mState = OFF; /*switch (mState) { case PRESSED: mState = USED; break; case RELEASED: mState = UNPRESSED; break; default: // Leave state alone break; }*/ } public boolean isActive() { // return mState != UNPRESSED; return mState == ACTIVE; } } private ModifierKey mAltKey = new ModifierKey(); private ModifierKey mCapKey = new ModifierKey(); private ModifierKey mControlKey = new ModifierKey(); private ModifierKey mFnKey = new ModifierKey(); private ModifierKey mFunctionKey = new ModifierKey(); private boolean mCapsLock; static public final int KEYCODE_OFFSET = 1000; /** * Construct a term key listener. * */ public TermKeyListener() { initKeyCodes(); } public void handleControlKey(boolean down) { // Log.v("SpartacusRex","handleControlKey "+down); if (down) { mControlKey.onPress(); } else { mControlKey.onRelease(); } } public void handleFnKey(boolean down) { if (down) { //Send the ESC sequence mFnKey.onPress(); } else { mFnKey.onRelease(); } } public void handleFunctionKey(boolean down) { if (down) { //Send the ESC sequence mFunctionKey.onPress(); } else { mFunctionKey.onRelease(); } } public int mapControlChar(int ch) { int result = ch; if (mControlKey.isActive()) { // Log.v("SpartacusRex","mapControlChar CONTROL ON "); // Search is the control key. if (result >= 'a' && result <= 'z') { result = (char) (result - 'a' + '\001'); } else if (result >= 'A' && result <= 'Z') { result = (char) (result - 'A' + '\001'); } else if (result == ' ' || result == '2') { result = 0; } else if (result == '[' || result == '3') { result = 27; // ^[ (Esc) } else if (result == '\\' || result == '4') { result = 28; } else if (result == ']' || result == '5') { result = 29; } else if (result == '^' || result == '6') { result = 30; // control-^ } else if (result == '_' || result == '7') { result = 31; } else if (result == '8') { result = 127; // DEL } // else if (result == '9') { // result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_F11; // } else if (result == '0') { // result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_F12; // } //Check if this is a one off if(mCTRLfromMETA){ // Log.v("SpartacusRex","mapControlChar RELEASE CTRL from META"); mCTRLfromMETA = false; mControlKey.onRelease(); } } else if (mFunctionKey.isActive()) { if (result > '0' && result <= '9') { int offs = (int)'1'; result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_F1 + result - offs; } else if (result == '0') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_F10; }else if (result == 'o' || result == 'O') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_F11; }else if (result == 'p'|| result == 'P') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_F12; } } else if (mFnKey.isActive()) { // Log.v("SpartacusRex","mapControlChar mFnKey.isActive() "); /* if (result == 'w' || result == 'W') { result = KEYCODE_OFFSET + KeyEvent.KEYCODE_DPAD_UP; } else if (result == 'a' || result == 'A') { result = KEYCODE_OFFSET + KeyEvent.KEYCODE_DPAD_LEFT; } else if (result == 's' || result == 'S') { result = KEYCODE_OFFSET + KeyEvent.KEYCODE_DPAD_DOWN; } else if (result == 'd' || result == 'D') { result = KEYCODE_OFFSET + KeyEvent.KEYCODE_DPAD_RIGHT; } else if (result == 'p' || result == 'P') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_PAGE_UP; } else if (result == 'n' || result == 'N') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_PAGE_DOWN; } else if (result == 't' || result == 'T') { result = KEYCODE_OFFSET + KeyEvent.KEYCODE_TAB; } else if (result == 'l' || result == 'L') { result = '|'; } else if (result == 'u' || result == 'U') { result = '_'; } else if (result == 'e' || result == 'E') { result = 27; // ^[ (Esc) } else if (result == '.') { result = 28; // ^\ } else if (result > '0' && result <= '9') { // F1-F9 result = (char)(result + KEYCODE_OFFSET + TermKeyListener.KEYCODE_F1 - 1); } else if (result == '0') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_F10; } else if (result == 'i' || result == 'I') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_INSERT; } else if (result == 'x' || result == 'X') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_FORWARD_DEL; } else if (result == 'h' || result == 'H') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_MOVE_HOME; } else if (result == 'f' || result == 'F') { result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_MOVE_END; } */ } /*if (result > -1) { mAltKey.adjustAfterKeypress(); mCapKey.adjustAfterKeypress(); mControlKey.adjustAfterKeypress(); mFnKey.adjustAfterKeypress(); }*/ // Log.v("SpartacusRex","mapControlChar "+ch+" --> "+result); return result; } /** * Handle a keyDown event. * * @param keyCode the keycode of the keyDown event * */ public boolean mCTRLfromMETA = false; public void keyDown(int keyCode, KeyEvent event, OutputStream out, boolean appMode) throws IOException { // Log.v("SpartacusRex","EMVIEW : keyDown "+keyCode+ " meta:"+event.getMetaState()+" unicode:"+event.getUnicodeChar()); if (handleKeyCode(keyCode, out, appMode)) { // Log.v("SpartacusRex","EMVIEW : Easy handle.."); return; } boolean CTRL = (event.getMetaState() & 8) != 0; if(CTRL){ // Log.v("SpartacusRex","EMVIEW : CONTROL PRESSED AND META SET!"); mControlKey.onPress(); mCTRLfromMETA = true; }else if(mCTRLfromMETA){ mCTRLfromMETA = false; // Log.v("SpartacusRex","EMVIEW : NO CONTROL PRESSED AND META NOT SET!"); mControlKey.onRelease(); } int result = -1; switch (keyCode) { case -100: //it's a forward delete.. // Log.v("SpartacusRex","EMVIEW : FORW DELETE"); result = KEYCODE_OFFSET + TermKeyListener.KEYCODE_FORWARD_DEL; break; case -98: case KeyEvent.KEYCODE_ALT_RIGHT: case KeyEvent.KEYCODE_ALT_LEFT: // Log.v("SpartacusRex","EMVIEW : ALT ON"); mAltKey.onPress(); break; case KeyEvent.KEYCODE_SHIFT_LEFT: case KeyEvent.KEYCODE_SHIFT_RIGHT: mCapKey.onPress(); break; case -99: case KEYCODE_CTRL_LEFT: case KEYCODE_CTRL_RIGHT: // Log.v("SpartacusRex","EMVIEW : CTRL ON"); mControlKey.onPress(); break; case KEYCODE_CAPS_LOCK: if (event.getRepeatCount() == 0) { mCapsLock = !mCapsLock; } break; default: { // result = event.getUnicodeChar( // (mCapKey.isActive() || mCapsLock ? KeyEvent.META_SHIFT_ON : 0) | // (mAltKey.isActive() ? KeyEvent.META_ALT_ON : 0)); result = event.getUnicodeChar( (mCapKey.isActive() || mCapsLock ? KeyEvent.META_SHIFT_ON : 0) ); break; } } //Check for CTRL / FN key manipulation result = mapControlChar(result); if (result >= KEYCODE_OFFSET) { handleKeyCode(result - KEYCODE_OFFSET, out, appMode); } else if (result >= 0) { //Check if(mAltKey.isActive()){ //Send Escape First.. out.write(27); } // Log.v("SpartacusRex","TERM : write code:"+keyCode+" result:"+result); out.write(result); } } public boolean handleKeyCode(int keyCode, OutputStream out, boolean appMode) throws IOException { // Log.v("SpartacusRex","handleKeyCode "+keyCode); //Special handling -19 >> -22 String code = null; if(keyCode>=-22 && keyCode<=-19){ if(keyCode==-19){ code = mCTRL_KeyCodes[0]; }else if(keyCode==-20){ code = mCTRL_KeyCodes[1]; }else if(keyCode==-21){ code = mCTRL_KeyCodes[3]; }else if(keyCode==-22){ code = mCTRL_KeyCodes[2]; } int length = code.length(); for (int i = 0; i < length; i++) { char cc = code.charAt(i); out.write(cc); } return true; }else if (keyCode >= 0 && keyCode < mKeyCodes.length) { if (appMode) { code = mAppKeyCodes[keyCode]; } if (code == null) { code = mKeyCodes[keyCode]; } if (code != null) { int length = code.length(); for (int i = 0; i < length; i++) { char cc = code.charAt(i); // Log.v("SpartacusRex","TERM : handleKeyCode internal "+keyCode+" "+i+") "+(int)cc+" : "+cc); out.write(cc); } return true; } } return false; } /** * Handle a keyUp event. * * @param keyCode the keyCode of the keyUp event */ public void keyUp(int keyCode) { // Log.v("ZShaolin","EMVIEW : keyup "+keyCode); switch (keyCode) { case -98: case KeyEvent.KEYCODE_ALT_LEFT: case KeyEvent.KEYCODE_ALT_RIGHT: // Log.v("ZShaolin","EMVIEW : ALT OFF"); mAltKey.onRelease(); break; case KeyEvent.KEYCODE_SHIFT_LEFT: case KeyEvent.KEYCODE_SHIFT_RIGHT: mCapKey.onRelease(); break; case -99: case KEYCODE_CTRL_LEFT: case KEYCODE_CTRL_RIGHT: // Log.v("ZShaolin","EMVIEW : CTRL OFF"); mControlKey.onRelease(); break; default: // Ignore other keyUps break; } } }