Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * 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 jackpal.androidterm.emulatorview;
- import java.io.IOException;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.os.Build;
- import android.os.Bundle;
- import android.os.Handler;
- import android.text.ClipboardManager;
- import android.util.AttributeSet;
- 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.inputmethod.BaseInputConnection;
- 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.widget.Scroller;
- /**
- * A view on a {@link TermSession}. Displays the terminal emulator's screen,
- * provides access to its scrollback buffer, and passes input through to the
- * terminal emulator.
- * <p>
- * If this view is inflated from an XML layout, you need to call {@link
- * #attachSession attachSession} and {@link #setDensity setDensity} before using
- * the view. If creating this view from code, use the {@link
- * #EmulatorView(Context, TermSession, DisplayMetrics)} constructor, which will
- * take care of this for you.
- */
- public class EmulatorView extends View implements GestureDetector.OnGestureListener {
- private final String TAG = "EmulatorView";
- private final boolean LOG_KEY_EVENTS = false;
- private final boolean LOG_IME = false;
- /**
- * 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;
- // Set if initialization was deferred because a TermSession wasn't attached
- private boolean mDeferInit = false;
- private int mVisibleWidth;
- private int mVisibleHeight;
- 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;
- /**
- * Top-of-screen margin
- */
- private int mTopOfScreenMargin;
- /**
- * Used to render text
- */
- private TextRenderer mTextRenderer;
- /**
- * Text size. Zero means 4 x 8 font.
- */
- private int mTextSize = 10;
- private int mCursorStyle;
- private int mCursorBlink;
- /**
- * Color scheme (default foreground/background colors).
- */
- private ColorScheme mColorScheme = BaseTextRenderer.defaultColorScheme;
- /**
- * Used to paint the cursor
- */
- private Paint mCursorPaint;
- private Paint mForegroundPaint;
- 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;
- private static final int CURSOR_BLINK_PERIOD = 1000;
- private boolean mCursorVisible = true;
- private boolean mIsSelectingText = false;
- private boolean mBackKeySendsCharacter = false;
- private int mControlKeyCode;
- private int mFnKeyCode;
- private boolean mIsControlKeySent = false;
- private boolean mIsFnKeySent = 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;
- private boolean mIsActive = false;
- /**
- * Routing alt and meta keyCodes away from the IME allows Alt key processing to work on
- * the Asus Transformer TF101.
- * It doesn't seem to harm anything else, but it also doesn't seem to be
- * required on other platforms.
- *
- * This test should be refined as we learn more.
- */
- private final static boolean sTrapAltAndMeta = Build.MODEL.contains("Transformer TF101");
- 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 GestureDetector.OnGestureListener mExtGestureListener;
- private Scroller mScroller;
- private Runnable mFlingRunner = new Runnable() {
- public void run() {
- if (mScroller.isFinished()) {
- return;
- }
- boolean more = mScroller.computeScrollOffset();
- int newTopRow = mScroller.getCurrY();
- if (newTopRow != mTopRow) {
- mTopRow = newTopRow;
- invalidate();
- }
- if (more) {
- post(this);
- }
- }
- };
- private float mScrollRemainder;
- private TermKeyListener mKeyListener;
- private String mImeBuffer = "";
- /**
- * Our message handler class. Implements a periodic callback.
- */
- private final Handler mHandler = new Handler();
- /**
- * 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();
- }
- };
- /**
- * Create an <code>EmulatorView</code> for a {@link TermSession}.
- *
- * @param context The {@link Context} for the view.
- * @param session The {@link TermSession} this view will be displaying.
- * @param metrics The {@link DisplayMetrics} of the screen on which the view
- * will be displayed.
- */
- public EmulatorView(Context context, TermSession session, DisplayMetrics metrics) {
- super(context);
- attachSession(session);
- setDensity(metrics);
- commonConstructor(context);
- }
- /**
- * Constructor called when inflating this view from XML.
- * <p>
- * You should call {@link #attachSession attachSession} and {@link
- * #setDensity setDensity} before using an <code>EmulatorView</code> created
- * using this constructor.
- */
- public EmulatorView(Context context, AttributeSet attrs) {
- super(context, attrs);
- commonConstructor(context);
- }
- /**
- * Constructor called when inflating this view from XML with a
- * default style set.
- * <p>
- * You should call {@link #attachSession attachSession} and {@link
- * #setDensity setDensity} before using an <code>EmulatorView</code> created
- * using this constructor.
- */
- public EmulatorView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- commonConstructor(context);
- }
- private void commonConstructor(Context context) {
- // TODO: See if we want to use the API level 11 constructor to get new flywheel feature.
- mScroller = new Scroller(context);
- }
- /**
- * Attach a {@link TermSession} to this view.
- *
- * @param session The {@link TermSession} this view will be displaying.
- */
- public void attachSession(TermSession session) {
- mTextRenderer = null;
- mCursorPaint = new Paint();
- mCursorPaint.setARGB(255,128,128,128);
- mForegroundPaint = new Paint();
- mBackgroundPaint = new Paint();
- mTopRow = 0;
- mLeftColumn = 0;
- mGestureDetector = new GestureDetector(this);
- // mGestureDetector.setIsLongpressEnabled(false);
- setVerticalScrollBarEnabled(true);
- setFocusable(true);
- setFocusableInTouchMode(true);
- mTermSession = session;
- mKeyListener = new TermKeyListener(session);
- // Do init now if it was deferred until a TermSession was attached
- if (mDeferInit) {
- mDeferInit = false;
- mKnownSize = true;
- initialize();
- }
- }
- /**
- * Update the screen density for the screen on which the view is displayed.
- *
- * @param metrics The {@link DisplayMetrics} of the screen.
- */
- public void setDensity(DisplayMetrics metrics) {
- if (mDensity == 0) {
- // First time we've known the screen density, so update font size
- mTextSize = (int) (mTextSize * metrics.density);
- }
- mDensity = metrics.density;
- mScaledDensity = metrics.scaledDensity;
- }
- /**
- * Inform the view that it is now visible on screen.
- */
- public void onResume() {
- mIsActive = true;
- updateSize(false);
- if (mCursorBlink != 0) {
- mHandler.postDelayed(mBlinkCursor, CURSOR_BLINK_PERIOD);
- }
- }
- /**
- * Inform the view that it is no longer visible on the screen.
- */
- public void onPause() {
- if (mCursorBlink != 0) {
- mHandler.removeCallbacks(mBlinkCursor);
- }
- mIsActive = false;
- }
- /**
- * Set this <code>EmulatorView</code>'s color scheme.
- *
- * @param scheme The {@link ColorScheme} to use (use null for the default
- * scheme).
- * @see TermSession#setColorScheme
- * @see ColorScheme
- */
- public void setColorScheme(ColorScheme scheme) {
- if (scheme == null) {
- mColorScheme = BaseTextRenderer.defaultColorScheme;
- } else {
- mColorScheme = scheme;
- }
- updateText();
- }
- @Override
- public boolean onCheckIsTextEditor() {
- return true;
- }
- @Override
- public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
- outAttrs.inputType = mUseCookedIme ?
- EditorInfo.TYPE_CLASS_TEXT :
- EditorInfo.TYPE_NULL;
- return new BaseInputConnection(this, true) {
- /**
- * Used to handle composing text requests
- */
- private int mCursor;
- private int mComposingTextStart;
- private int mComposingTextEnd;
- private int mSelectedTextStart;
- private int mSelectedTextEnd;
- private void sendText(CharSequence text) {
- int n = text.length();
- char c;
- try {
- for(int i = 0; i < n; i++) {
- c = text.charAt(i);
- if (Character.isHighSurrogate(c)) {
- int codePoint;
- if (++i < n) {
- codePoint = Character.toCodePoint(c, text.charAt(i));
- } else {
- // Unicode Replacement Glyph, aka white question mark in black diamond.
- codePoint = '\ufffd';
- }
- mapAndSend(codePoint);
- } else {
- mapAndSend(c);
- }
- }
- } 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) {
- mTermSession.write(result);
- } else {
- mKeyListener.handleKeyCode(result - TermKeyListener.KEYCODE_OFFSET, getKeypadApplicationMode());
- }
- clearSpecialKeyStatus();
- }
- public boolean beginBatchEdit() {
- if (LOG_IME) {
- Log.w(TAG, "beginBatchEdit");
- }
- setImeBuffer("");
- mCursor = 0;
- mComposingTextStart = 0;
- mComposingTextEnd = 0;
- return true;
- }
- public boolean clearMetaKeyStates(int arg0) {
- if (LOG_IME) {
- Log.w(TAG, "clearMetaKeyStates " + arg0);
- }
- return false;
- }
- public boolean commitCompletion(CompletionInfo arg0) {
- if (LOG_IME) {
- Log.w(TAG, "commitCompletion " + arg0);
- }
- return false;
- }
- public boolean endBatchEdit() {
- if (LOG_IME) {
- Log.w(TAG, "endBatchEdit");
- }
- return true;
- }
- public boolean finishComposingText() {
- if (LOG_IME) {
- Log.w(TAG, "finishComposingText");
- }
- sendText(mImeBuffer);
- setImeBuffer("");
- mComposingTextStart = 0;
- mComposingTextEnd = 0;
- mCursor = 0;
- return true;
- }
- public int getCursorCapsMode(int arg0) {
- if (LOG_IME) {
- Log.w(TAG, "getCursorCapsMode(" + arg0 + ")");
- }
- return 0;
- }
- public ExtractedText getExtractedText(ExtractedTextRequest arg0,
- int arg1) {
- if (LOG_IME) {
- Log.w(TAG, "getExtractedText" + arg0 + "," + arg1);
- }
- return null;
- }
- public CharSequence getTextAfterCursor(int n, int flags) {
- if (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 (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 (LOG_IME) {
- Log.w(TAG, "performContextMenuAction" + arg0);
- }
- return true;
- }
- public boolean performPrivateCommand(String arg0, Bundle arg1) {
- if (LOG_IME) {
- Log.w(TAG, "performPrivateCommand" + arg0 + "," + arg1);
- }
- return true;
- }
- public boolean reportFullscreenMode(boolean arg0) {
- if (LOG_IME) {
- Log.w(TAG, "reportFullscreenMode" + arg0);
- }
- return true;
- }
- public boolean commitCorrection (CorrectionInfo correctionInfo) {
- if (LOG_IME) {
- Log.w(TAG, "commitCorrection");
- }
- return true;
- }
- public boolean commitText(CharSequence text, int newCursorPosition) {
- if (LOG_IME) {
- Log.w(TAG, "commitText(\"" + text + "\", " + newCursorPosition + ")");
- }
- clearComposingText();
- sendText(text);
- setImeBuffer("");
- mCursor = 0;
- return true;
- }
- private void clearComposingText() {
- int len = mImeBuffer.length();
- if (mComposingTextStart > len || mComposingTextEnd > len) {
- mComposingTextEnd = mComposingTextStart = 0;
- return;
- }
- 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 (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 (LOG_IME) {
- Log.w(TAG, "performEditorAction(" + actionCode + ")");
- }
- if (actionCode == EditorInfo.IME_ACTION_UNSPECIFIED) {
- // The "return" key has been pressed on the IME.
- sendText("\r");
- }
- return true;
- }
- public boolean sendKeyEvent(KeyEvent event) {
- if (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 (LOG_IME) {
- Log.w(TAG, "setComposingText(\"" + text + "\", " + newCursorPosition + ")");
- }
- int len = mImeBuffer.length();
- if (mComposingTextStart > len || mComposingTextEnd > len) {
- return false;
- }
- 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 (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 (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) {
- if (LOG_IME) {
- Log.w(TAG, "getSelectedText " + flags);
- }
- int len = mImeBuffer.length();
- if (mSelectedTextEnd >= len || mSelectedTextStart > mSelectedTextEnd) {
- return "";
- }
- return mImeBuffer.substring(mSelectedTextStart, mSelectedTextEnd+1);
- }
- };
- }
- private void setImeBuffer(String buffer) {
- if (!buffer.equals(mImeBuffer)) {
- invalidate();
- }
- mImeBuffer = buffer;
- }
- /**
- * Get the terminal emulator's keypad application mode.
- */
- public boolean getKeypadApplicationMode() {
- return mEmulator.getKeypadApplicationMode();
- }
- /**
- * Set a {@link android.view.GestureDetector.OnGestureListener
- * GestureDetector.OnGestureListener} to receive gestures performed on this
- * view. Can be used to implement additional
- * functionality via touch gestures or override built-in gestures.
- *
- * @param listener The {@link
- * android.view.GestureDetector.OnGestureListener
- * GestureDetector.OnGestureListener} which will receive
- * gestures.
- */
- public void setExtGestureListener(GestureDetector.OnGestureListener listener) {
- mExtGestureListener = listener;
- }
- /**
- * Compute the vertical range that the vertical scrollbar represents.
- */
- @Override
- protected int computeVerticalScrollRange() {
- return mTranscriptScreen.getActiveRows();
- }
- /**
- * Compute the vertical extent of the horizontal scrollbar's thumb within
- * the vertical range. This value is used to compute the length of the thumb
- * within the scrollbar's track.
- */
- @Override
- protected int computeVerticalScrollExtent() {
- return mRows;
- }
- /**
- * Compute the vertical offset of the vertical scrollbar's thumb within the
- * horizontal range. This value is used to compute the position of the thumb
- * within the scrollbar's track.
- */
- @Override
- protected int computeVerticalScrollOffset() {
- return mTranscriptScreen.getActiveRows() + mTopRow - mRows;
- }
- /**
- * Call this to initialize the view.
- */
- private void initialize() {
- TermSession session = mTermSession;
- updateText();
- mTranscriptScreen = session.getTranscriptScreen();
- mEmulator = session.getEmulator();
- session.setUpdateCallback(mUpdateNotify);
- requestFocus();
- }
- /**
- * Get the {@link TermSession} corresponding to this view.
- *
- * @return The {@link TermSession} object for this view.
- */
- public TermSession getTermSession() {
- return mTermSession;
- }
- /**
- * Get the width of the visible portion of this view.
- *
- * @return The width of the visible portion of this view, in pixels.
- */
- public int getVisibleWidth() {
- return mVisibleWidth;
- }
- /**
- * Get the height of the visible portion of this view.
- *
- * @return The height of the visible portion of this view, in pixels.
- */
- public int getVisibleHeight() {
- return mVisibleHeight;
- }
- /**
- * Page the terminal view (scroll it up or down by <code>delta</code>
- * screenfuls).
- *
- * @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 density-independent pixels.
- */
- public void setTextSize(int fontSize) {
- mTextSize = (int) (fontSize * mDensity);
- updateText();
- }
- /**
- * Sets style information about the cursor.
- *
- * @param style The style of the cursor.
- * @param blink Whether the cursor should blink.
- */
- 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;
- }
- /**
- * Sets the IME mode ("cooked" or "raw").
- *
- * @param useCookedIME Whether the IME should be used in cooked mode.
- */
- public void setUseCookedIME(boolean useCookedIME) {
- mUseCookedIme = useCookedIME;
- }
- // Begin GestureDetector.OnGestureListener methods
- public boolean onSingleTapUp(MotionEvent e) {
- if (mExtGestureListener != null && mExtGestureListener.onSingleTapUp(e)) {
- return true;
- }
- requestFocus();
- return true;
- }
- public void onLongPress(MotionEvent e) {
- // XXX hook into external gesture listener
- showContextMenu();
- }
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- if (mExtGestureListener != null && mExtGestureListener.onScroll(e1, e2, distanceX, distanceY)) {
- return true;
- }
- 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) {
- if (mExtGestureListener != null && mExtGestureListener.onFling(e1, e2, velocityX, velocityY)) {
- return true;
- }
- float SCALE = 0.25f;
- mScroller.fling(0, mTopRow,
- -(int) (velocityX * SCALE), -(int) (velocityY * SCALE),
- 0, 0,
- -mTranscriptScreen.getActiveTranscriptRows(), 0);
- mScrollRemainder = 0.0f;
- // onScroll(e1, e2, 0.1f * velocityX, -0.1f * velocityY);
- post(mFlingRunner);
- return true;
- }
- public void onShowPress(MotionEvent e) {
- if (mExtGestureListener != null) {
- mExtGestureListener.onShowPress(e);
- }
- }
- public boolean onDown(MotionEvent e) {
- if (mExtGestureListener != null && mExtGestureListener.onDown(e)) {
- return true;
- }
- 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);
- }
- }
- @SuppressWarnings("deprecation")
- 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;
- }
- /**
- * Called when a key is pressed in the view.
- *
- * @param keyCode The keycode of the key which was pressed.
- * @param event A {@link KeyEvent} describing the event.
- * @return Whether the event was handled.
- */
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (LOG_KEY_EVENTS) {
- Log.w(TAG, "onKeyDown " + keyCode);
- }
- if (handleControlKey(keyCode, true)) {
- return true;
- } else if (handleFnKey(keyCode, true)) {
- return true;
- } else if (isSystemKey(keyCode, event)) {
- if (! isInterceptedSystemKey(keyCode) ) {
- // Don't intercept the system keys
- return super.onKeyDown(keyCode, event);
- }
- }
- // Translate the keyCode into an ASCII character.
- try {
- mKeyListener.keyDown(keyCode, event, getKeypadApplicationMode(),
- TermKeyListener.isEventFromToggleDevice(event));
- } catch (IOException e) {
- // Ignore I/O exceptions
- }
- return true;
- }
- /** Do we want to intercept this system key? */
- private boolean isInterceptedSystemKey(int keyCode) {
- return keyCode == KeyEvent.KEYCODE_BACK && mBackKeySendsCharacter;
- }
- /**
- * Called when a key is released in the view.
- *
- * @param keyCode The keycode of the key which was released.
- * @param event A {@link KeyEvent} describing the event.
- * @return Whether the event was handled.
- */
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (LOG_KEY_EVENTS) {
- Log.w(TAG, "onKeyUp " + keyCode);
- }
- if (handleControlKey(keyCode, false)) {
- return true;
- } else if (handleFnKey(keyCode, false)) {
- return true;
- } else if (isSystemKey(keyCode, event)) {
- // Don't intercept the system keys
- if ( ! isInterceptedSystemKey(keyCode) ) {
- return super.onKeyUp(keyCode, event);
- }
- }
- mKeyListener.keyUp(keyCode, event);
- clearSpecialKeyStatus();
- return true;
- }
- @Override
- public boolean onKeyPreIme(int keyCode, KeyEvent event) {
- if (sTrapAltAndMeta) {
- boolean altEsc = mKeyListener.getAltSendsEsc();
- boolean altOn = (event.getMetaState() & KeyEvent.META_ALT_ON) != 0;
- boolean metaOn = (event.getMetaState() & KeyEvent.META_META_ON) != 0;
- boolean altPressed = (keyCode == KeyEvent.KEYCODE_ALT_LEFT)
- || (keyCode == KeyEvent.KEYCODE_ALT_RIGHT);
- boolean altActive = mKeyListener.isAltActive();
- if (altEsc && (altOn || altPressed || altActive || metaOn)) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- return onKeyDown(keyCode, event);
- } else {
- return onKeyUp(keyCode, event);
- }
- }
- }
- return super.onKeyPreIme(keyCode, event);
- };
- private boolean handleControlKey(int keyCode, boolean down) {
- if (keyCode == mControlKeyCode) {
- 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 == mFnKeyCode) {
- if (LOG_KEY_EVENTS) {
- Log.w(TAG, "handleFnKey " + keyCode);
- }
- mKeyListener.handleFnKey(down);
- return true;
- }
- return false;
- }
- private boolean isSystemKey(int keyCode, KeyEvent event) {
- return event.isSystem();
- }
- private void clearSpecialKeyStatus() {
- if (mIsControlKeySent) {
- mIsControlKeySent = false;
- mKeyListener.handleControlKey(false);
- }
- if (mIsFnKeySent) {
- mIsFnKeySent = false;
- mKeyListener.handleFnKey(false);
- }
- }
- private void updateText() {
- ColorScheme scheme = mColorScheme;
- if (mTextSize > 0) {
- mTextRenderer = new PaintRenderer(mTextSize, scheme);
- }
- else {
- mTextRenderer = new Bitmap4x8FontRenderer(getResources(), scheme);
- }
- mForegroundPaint.setColor(scheme.getForeColor());
- mBackgroundPaint.setColor(scheme.getBackColor());
- mCharacterWidth = mTextRenderer.getCharacterWidth();
- mCharacterHeight = mTextRenderer.getCharacterHeight();
- updateSize(true);
- }
- /**
- * This is called during layout when the size of this view has changed. If
- * you were just added to the view hierarchy, you're called with the old
- * values of 0.
- */
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- if (mTermSession == null) {
- // Not ready, defer until TermSession is attached
- mDeferInit = true;
- return;
- }
- if (!mKnownSize) {
- mKnownSize = true;
- initialize();
- } else {
- updateSize(false);
- }
- }
- private void updateSize(int w, int h) {
- mColumns = Math.max(1, (int) (((float) w) / mCharacterWidth));
- mVisibleColumns = (int) (((float) mVisibleWidth) / mCharacterWidth);
- mTopOfScreenMargin = mTextRenderer.getTopMargin();
- mRows = Math.max(1, (h - mTopOfScreenMargin) / mCharacterHeight);
- mTermSession.updateSize(mColumns, mRows);
- // Reset our paging:
- mTopRow = 0;
- mLeftColumn = 0;
- invalidate();
- }
- /**
- * Update the view's idea of its size.
- *
- * @param force Whether a size adjustment should be performed even if the
- * view's size has not changed.
- */
- public void updateSize(boolean force) {
- if (mKnownSize) {
- int w = getWidth();
- int h = getHeight();
- // Log.w("Term", "(" + w + ", " + h + ")");
- if (force || w != mVisibleWidth || h != mVisibleHeight) {
- mVisibleWidth = w;
- mVisibleHeight = h;
- updateSize(mVisibleWidth, mVisibleHeight);
- }
- }
- }
- /**
- * Draw the view to the provided {@link Canvas}.
- *
- * @param canvas The {@link Canvas} to draw the view to.
- */
- @Override
- protected void onDraw(Canvas canvas) {
- updateSize(false);
- if (mEmulator == null) {
- // Not ready yet
- return;
- }
- int w = getWidth();
- int h = getHeight();
- boolean reverseVideo = mEmulator.getReverseVideo();
- mTextRenderer.setReverseVideo(reverseVideo);
- Paint backgroundPaint =
- reverseVideo ? mForegroundPaint : mBackgroundPaint;
- canvas.drawRect(0, 0, w, h, backgroundPaint);
- float x = -mLeftColumn * mCharacterWidth;
- float y = mCharacterHeight + mTopOfScreenMargin;
- 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;
- }
- }
- }
- /**
- * Toggle text selection mode in the view.
- */
- public void toggleSelectingText() {
- mIsSelectingText = ! mIsSelectingText;
- setVerticalScrollBarEnabled( ! mIsSelectingText );
- if ( ! mIsSelectingText ) {
- mSelX1 = -1;
- mSelY1 = -1;
- mSelX2 = -1;
- mSelY2 = -1;
- }
- }
- /**
- * Whether the view is currently in text selection mode.
- */
- public boolean getSelectingText() {
- return mIsSelectingText;
- }
- /**
- * Get selected text.
- *
- * @return A {@link String} with the selected text.
- */
- public String getSelectedText() {
- return mEmulator.getSelectedText(mSelX1, mSelY1, mSelX2, mSelY2);
- }
- /**
- * Send a Ctrl key event to the terminal.
- */
- public void sendControlKey() {
- mIsControlKeySent = true;
- mKeyListener.handleControlKey(true);
- }
- /**
- * Send an Fn key event to the terminal. The Fn modifier key can be used to
- * generate various special characters and escape codes.
- */
- public void sendFnKey() {
- mIsFnKeySent = true;
- mKeyListener.handleFnKey(true);
- }
- /**
- * Set the key code to be sent when the Back key is pressed.
- */
- public void setBackKeyCharacter(int keyCode) {
- mKeyListener.setBackKeyCharacter(keyCode);
- mBackKeySendsCharacter = (keyCode != 0);
- }
- /**
- * Set whether to prepend the ESC keycode to the character when when pressing
- * the ALT Key.
- * @param flag
- */
- public void setAltSendsEsc(boolean flag) {
- mKeyListener.setAltSendsEsc(flag);
- }
- /**
- * Set the keycode corresponding to the Ctrl key.
- */
- public void setControlKeyCode(int keyCode) {
- mControlKeyCode = keyCode;
- }
- /**
- * Set the keycode corresponding to the Fn key.
- */
- public void setFnKeyCode(int keyCode) {
- mFnKeyCode = keyCode;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement