package tw.kenshinn.keyboardTerm; import java.io.IOException; import com.roiding.rterm.util.TerminalManager; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.Paint.Style; import android.preference.PreferenceManager; import android.util.AttributeSet; import android.util.Log; import android.view.Display; import android.view.GestureDetector; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.WindowManager; import android.widget.SimpleAdapter.ViewBinder; public class GestureView extends View implements View.OnLongClickListener, View.OnClickListener{ private final String TAG = "GestureView"; private Point lastTouchedPoint; private Point startPoint; private Bitmap footprintBitmap; private final Paint footprintPaint; private Canvas footprintCanvas; private int footprintColor = Color.RED; private int footprintWidth = 5; private Bitmap textBitmap; private final Paint textPaint; private Canvas textCanvas; private int textBgColor = Color.BLUE; private int textColor = Color.WHITE; private final Rect mRect = new Rect(); private OnGestureListener mOnGestureListener; private boolean magnifierOn = false; private boolean fingerOnScreen = false; private int MAGNIFIER_HEIGHT = 100; private int MAGNIFIER_WIDTH = 200; private int MAGNIFIER_MARGIN = 50; private int MAGNIFIER_FOCUS_HEIGHT = 50; private int MAGNIFIER_FOCUS_WIDTH = 100; // by kenshinn for move function private boolean mIsMoveMode = false; private boolean mIsClick = false; private Point mClickPoint; private final static int DOUBLE_CLICK_TIME = 300; // double click avalible time private static final int MOVE_CURSOR_TIME = 100; // in move mode , touch move time private float mTouchY; private int mMoveCursorY; private boolean mAvaliableDoubleClick; private static final int DOUBLE_CLICK_AVALIABLE_TIME = 100; private Object mSend_inList; private Object mSend_inReading; private Paint mMovePaint; private TerminalActivity terminalActivity; public void setTerminalActivity(TerminalActivity terminalActivity) { this.terminalActivity = terminalActivity; } public OnGestureListener getOnGestureListener() { return mOnGestureListener; } public void setOnGestureListener(OnGestureListener onGestureListener) { this.mOnGestureListener = onGestureListener; } public GestureView(Context c, AttributeSet attrs) { super(c, attrs); mMovePaint = new Paint(); mMovePaint.setColor(Color.argb(128, 0, 255, 0)); footprintPaint = new Paint(); footprintPaint.setAntiAlias(true); footprintPaint.setColor(footprintColor); footprintPaint.setStyle(Paint.Style.STROKE); footprintPaint.setStrokeWidth(footprintWidth); textPaint = new Paint(); textPaint.setAntiAlias(true); textPaint.setTextSize(15); textPaint.setTypeface(Typeface.MONOSPACE); setOnLongClickListener(this); setOnClickListener(this); SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this.getContext()); String send_key_in_list = pref.getString("settings_send_key_in_list", "ENTER"); String send_key_in_reading = pref.getString("settings_send_key_in_reading", "SPACE"); mSend_inList = ArrowKeyView.getKeyTag(send_key_in_list); mSend_inReading = ArrowKeyView.getKeyTag(send_key_in_reading); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); footprintBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_4444); footprintCanvas = new Canvas(); footprintCanvas.setBitmap(footprintBitmap); textBitmap = Bitmap.createBitmap(w, 20, Bitmap.Config.ARGB_4444); textCanvas = new Canvas(); textCanvas.setBitmap(textBitmap); } public void setMagnifierParms(int fwidth, int fheight, int zoom){ // At the time parms set, view is not measured yet final Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); /* we map zoom value(0~100) to 1x~4x */ final float rate = 1 + (zoom/100f)*3; if((TerminalActivity.termActFlags & TerminalActivity.FLAG_MAGNIFIER_FULLSCREEN) !=0){ MAGNIFIER_WIDTH = display.getWidth(); MAGNIFIER_HEIGHT = display.getHeight(); MAGNIFIER_FOCUS_WIDTH = Math.round(MAGNIFIER_WIDTH / rate); MAGNIFIER_FOCUS_HEIGHT = Math.round(MAGNIFIER_HEIGHT / rate); }else{ MAGNIFIER_FOCUS_WIDTH = (int) ((float)fwidth / 100 * display.getWidth()); MAGNIFIER_FOCUS_HEIGHT = (int) ((float)fheight / 100 * display.getHeight()); MAGNIFIER_WIDTH = (int)Math.ceil(rate * MAGNIFIER_FOCUS_WIDTH); MAGNIFIER_HEIGHT = (int)Math.ceil(rate * MAGNIFIER_FOCUS_HEIGHT); } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(magnifierOn && (fingerOnScreen || (TerminalActivity.termActFlags & TerminalActivity.FLLAG_LONG_PRESS_ACTIVATE) !=0)){ Rect magnifier = new Rect(); Paint mPaint = new Paint(); if((TerminalActivity.termActFlags & TerminalActivity.FLAG_MAGNIFIER_FULLSCREEN) !=0){ magnifier.set(0, 0, MAGNIFIER_WIDTH, MAGNIFIER_HEIGHT); }else{ /* Place magnifier on top on finger if possible */ magnifier.top = lastTouchedPoint.y - MAGNIFIER_HEIGHT - MAGNIFIER_MARGIN; magnifier.left = lastTouchedPoint.x - MAGNIFIER_WIDTH/2; if(magnifier.top<0){ /* if no space left on top, place it right */ magnifier.top = lastTouchedPoint.y - MAGNIFIER_HEIGHT/2; if(magnifier.top<0) magnifier.top = 0; magnifier.left = lastTouchedPoint.x + MAGNIFIER_MARGIN; /* if no place at right, put it left */ if(magnifier.left+MAGNIFIER_WIDTH>getWidth()) magnifier.left = lastTouchedPoint.x - MAGNIFIER_WIDTH - MAGNIFIER_MARGIN; } if(magnifier.left < 0) magnifier.left = 0; magnifier.right = magnifier.left + MAGNIFIER_WIDTH; magnifier.bottom = magnifier.top + MAGNIFIER_HEIGHT; if(magnifier.right > getWidth()) magnifier.right = getWidth(); mPaint.setColor(Color.WHITE); canvas.drawRect(magnifier.left - 1, magnifier.top -1, magnifier.right+1, magnifier.bottom +1, mPaint); //Draw border } /* clean magnifier area */ mPaint.setColor(Color.BLACK); canvas.drawRect(magnifier, mPaint); RectF focus = new RectF( lastTouchedPoint.x - MAGNIFIER_FOCUS_WIDTH/2, lastTouchedPoint.y - MAGNIFIER_FOCUS_HEIGHT/2,0,0); focus.right = focus.left + MAGNIFIER_FOCUS_WIDTH; focus.bottom = focus.top + MAGNIFIER_FOCUS_HEIGHT; //Check Bounds if(focus.left<0){ focus.left =0; focus.right = focus.left + MAGNIFIER_FOCUS_WIDTH; }else if(focus.right > getWidth()){ focus.right = getWidth(); focus.left = focus.right - MAGNIFIER_FOCUS_WIDTH; } if(focus.top<0){ focus.top = 0; focus.bottom = focus.top + MAGNIFIER_FOCUS_HEIGHT; }else if(focus.bottom > getHeight()){ focus.bottom = getHeight(); focus.top = focus.bottom - MAGNIFIER_FOCUS_HEIGHT; } /////////////////////////// // Uncomment these to debug focus area // Paint testPaint = new Paint();testPaint.setStyle(Style.STROKE); testPaint.setColor(Color.BLUE); // canvas.drawRect(focus, testPaint); /////////////////////////// TerminalView view = terminalActivity.getCurrentTerminalView(); if(view == null) return; view.renderMagnifier(canvas, magnifier, focus); }else{ if(!mIsMoveMode) canvas.drawBitmap(footprintBitmap, 0, 0, null); canvas.drawBitmap(textBitmap, 0, 0, null); } if(mIsMoveMode) { // move mode draw int touchCurY = -1; TerminalView view = terminalActivity .getCurrentTerminalView(); if(view == null) return; if(mTouchY > 0) { touchCurY = (int)(mTouchY/view.CHAR_HEIGHT); } canvas.drawRect(0, touchCurY * view.CHAR_HEIGHT, this.getWidth(), (touchCurY+1) * view.CHAR_HEIGHT , mMovePaint); } } private int distance(Point start,Point end){ return (int)Math.pow(Math.pow(start.x-end.x, 2) + Math.pow(start.y-end.y,2),0.5); } // change manifer to double click public void onClick(View v) { //Log.v("Kenshinn", "OnClick: " + mIsClick); if(mIsClick) { mIsClick = false; mAvaliableDoubleClick = false; if(distance(mClickPoint,lastTouchedPoint) < minGestureDistance) { if((TerminalActivity.termActFlags & TerminalActivity.FLAG_NO_MAGNIFIER) != 0) return; toggleMagnifer(); } else if(magnifierOn) toggleMagnifer(); return; } if(distance(startPoint,lastTouchedPoint) < minGestureDistance) { /* this is not a long press */ mClickPoint = startPoint; mIsClick = true; if((TerminalActivity.termActFlags & TerminalActivity.FLAG_NO_MAGNIFIER) != 0) this.post(mClickRunnable); // delay for double click else this.postDelayed(mClickRunnable, DOUBLE_CLICK_TIME); // delay for double click } } private Runnable mClickRunnable = new Runnable() { public void run() { mIsClick = false; if(magnifierOn) return; TerminalView view = terminalActivity .getCurrentTerminalView(); if(view == null) return; if(view.buffer.getCursorColumn() < 78) { // list if(mSend_inList != null && mSend_inList instanceof KeyEvent) terminalActivity.pressKey(((KeyEvent)mSend_inList).getKeyCode()); } else { // reading if(mSend_inReading != null && mSend_inReading instanceof KeyEvent) terminalActivity.pressKey(((KeyEvent)mSend_inReading).getKeyCode()); } } }; public boolean onLongClick(View v){ //Log.v(TAG, "onLongClick, mIsClick: " + mIsClick); if(mUrlHandled) return false; if(magnifierOn) { return false; } if(distance(startPoint,lastTouchedPoint) > minGestureDistance) /* this is not a long press */ return false; this.post(mMoveCursorRunnable); return true; } private Runnable mMoveCursorRunnable = new Runnable() { public void run() { // TODO Auto-generated method stub int touchCurY = -1; TerminalView view = terminalActivity .getCurrentTerminalView(); if(view == null) return; Log.v(TAG, "mMoveCursorRunnable, cursor Column: " + view.buffer.getCursorColumn()); if(mTouchY > 0) { touchCurY = (int)(mTouchY/view.CHAR_HEIGHT); if(mMoveCursorY == touchCurY) return; mMoveCursorY = touchCurY; } else return; int move = view.buffer.getCursorRow() - touchCurY; if(view.buffer.getCursorColumn() < 78) { Log.v(TAG,"move mode On"); mIsMoveMode = true; try { if(move < 0) { while(move != 0) { view.write(new byte[] { 27, '[', 'B'}); move++; } } else if(move > 0) { while(move != 0) { view.write(new byte[] { 27, '[', 'A'}); move--; } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; private void toggleMagnifer() { //Log.v("Kenshinn", "toggleMagnifer"); /* long press actions: * FLAG_NO_MAGNIFIER: do nothing * FLLAG_LONG_PRESS_ACTIVATE: enable/disable magnifier * FLLAG_LONG_PRESS_MODE_SWITCH: enable/disable magnifier * FLLAG_LONG_PRESS_SHOW: enable magnifier */ if(magnifierOn){ magnifierOn = false; } else if(currentGesture.length()==0){ footprintBitmap.eraseColor(0); textBitmap.eraseColor(0); magnifierOn = true; //Log.v("Kenshinn","magnifier on"); } invalidate(); } public static final char GESTURE_LEFT = 'L'; public static final char GESTURE_RIGHT = 'R'; public static final char GESTURE_UP = 'U'; public static final char GESTURE_DOWN = 'D'; //private int minGestureDistance = 50; private int minGestureDistance = 80; // for correctly gesture private String currentGesture = ""; private void recognize(char e) { Log.d("Gesture", "computeGesture:" + currentGesture + "#" + e); if (currentGesture.length() > 0) { if (currentGesture.charAt(currentGesture.length() - 1) != e) { currentGesture = currentGesture + ("," + e); Log.d("Gesture", "Gesture:" + currentGesture); drawText(); } } else { currentGesture = currentGesture + e; drawText(); } } private void clear() { if (currentGesture.length() > 0) { mOnGestureListener.onGestureEvent(currentGesture); } currentGesture = ""; footprintBitmap.eraseColor(0); textBitmap.eraseColor(0); Log.v(TAG,"move mode Off"); mIsMoveMode = false; invalidate(); } private void drawLine(Point p1, Point p2) { if (footprintBitmap == null) return; footprintCanvas.drawLine(p1.x, p1.y, p2.x, p2.y, footprintPaint); int x1 = Math.min(p1.x, p2.x) - 10; int y1 = Math.min(p1.y, p2.y) - 10; int x2 = Math.max(p1.x, p2.x) + 10; int y2 = Math.max(p1.y, p2.y) + 10; mRect.set(x1, y1, x2, y2); invalidate(mRect); } private void drawText() { if (textBitmap == null) return; String desc = mOnGestureListener.getGestureText(currentGesture); textBitmap.eraseColor(0); textPaint.setColor(textBgColor); textCanvas.drawRect(0, 0, desc.length() * 9, textBitmap.getHeight(), textPaint); textPaint.setColor(textColor); textCanvas.drawText(desc.toString(), 0, 15, textPaint); textBitmap.getWidth(); mRect.set(0, 0, textBitmap.getWidth(), textBitmap.getWidth()); invalidate(mRect); } private float dx = 0; private float dy = 0; private Runnable mCancleDoubleClickRunnable = new Runnable() { public void run() { mAvaliableDoubleClick = false; } }; private boolean mUrlHandled = false; @Override public boolean onTouchEvent(MotionEvent ev) { Log.v(TAG, "onTouchEvent...action=" + ev.getAction()); //Log.v("Kenshinn", "onTouchEvent...action=" + ev.getAction()); mTouchY = ev.getY(); Point evPoint = new Point((int) ev.getX(),(int) ev.getY()); if(magnifierOn){ if (ev.getAction() == MotionEvent.ACTION_UP){ if((TerminalActivity.termActFlags & TerminalActivity.FLLAG_LONG_PRESS_SHOW) != 0){ /* deactivate magnifier */ magnifierOn = false; Log.v(TAG,"magnifier off"); } } if(ev.getAction() == MotionEvent.ACTION_DOWN) { if((TerminalActivity.termActFlags & TerminalActivity.FLAG_NO_MAGNIFIER) == 0) { this.removeCallbacks(mClickRunnable); if(mIsClick) mAvaliableDoubleClick = true; postDelayed(mCancleDoubleClickRunnable, DOUBLE_CLICK_AVALIABLE_TIME); // double click check } } invalidate(); //we will paint magnifier in onDraw if(mIsClick && !mAvaliableDoubleClick) { return false; } }else { //Perform gesture if (mOnGestureListener == null) Log.e(TAG, "there is no gesture listener"); if(!mIsMoveMode && !mIsClick && !mUrlHandled) mGestureDetector.onTouchEvent(ev); if(ev.getAction() == MotionEvent.ACTION_DOWN) { mMoveCursorY = -1; mUrlHandled = false; if((TerminalActivity.termActFlags & TerminalActivity.FLAG_NO_MAGNIFIER) == 0) { this.removeCallbacks(mClickRunnable); if(mIsClick) mAvaliableDoubleClick = true; } TerminalView view = terminalActivity .getCurrentTerminalView(); if(view == null) { super.onTouchEvent(ev); return true; } if(view.checkUrlClick(ev)) { mUrlHandled = true; } if((TerminalActivity.termActFlags & TerminalActivity.FLAG_NO_MAGNIFIER) == 0) { postDelayed(mCancleDoubleClickRunnable, DOUBLE_CLICK_AVALIABLE_TIME); } } if(ev.getAction() == MotionEvent.ACTION_MOVE && mIsMoveMode) { this.removeCallbacks(mMoveCursorRunnable); this.postDelayed(mMoveCursorRunnable, MOVE_CURSOR_TIME); invalidate(); } if (ev.getAction() != MotionEvent.ACTION_DOWN && !mIsMoveMode && !mIsClick ) drawLine(lastTouchedPoint, evPoint); if (ev.getAction() == MotionEvent.ACTION_UP) { removeCallbacks(mMoveCursorRunnable); if(mIsClick && !mAvaliableDoubleClick) { clear(); mIsClick = false; fingerOnScreen = false; return false; } clear(); if(mUrlHandled) return true; } } if( ev.getAction() == MotionEvent.ACTION_DOWN){ startPoint = evPoint; fingerOnScreen = true; }else if(ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) fingerOnScreen = false; lastTouchedPoint = evPoint; super.onTouchEvent(ev); return true; } GestureDetector mGestureDetector = new GestureDetector( new GestureDetector.SimpleOnGestureListener() { @Override public boolean onSingleTapConfirmed(MotionEvent e) { TerminalView view = terminalActivity .getCurrentTerminalView(); if (view != null) return view.onTouchEvent(e); else return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.d("Gesture", "onScroll:" + distanceX + "," + distanceY); if (Math.max(Math.abs(dx), Math.abs(dy)) >= minGestureDistance) { char g = GESTURE_LEFT; if (Math.abs(dx) > Math.abs(dy)) { if (dx < 0) g = GESTURE_RIGHT; else g = GESTURE_LEFT; } else { if (dy < 0) g = GESTURE_DOWN; else g = GESTURE_UP; } recognize(g); dx = dy = 0; } else { dx = dx + distanceX; dy = dy + distanceY; } return true; } }); }