/* * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ // // CanvasView is the Activity for showing VNC Desktop. // package android.androidVNC; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import com.antlersoft.android.bc.BCFactory; import com.antlersoft.android.zoomer.ZoomControls; import com.cgcl.cloudesk.cloudeskmain.screens.act.R; import ClouDesk.AppConnection; import android.app.Activity; import android.app.Dialog; import android.content.ContentValues; import android.content.DialogInterface; import android.content.Intent; import android.content.DialogInterface.OnDismissListener; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.PointF; import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; import android.widget.AdapterView.OnItemClickListener; import android.view.inputmethod.InputMethodManager; import android.content.Context; public class VncCanvasActivity extends Activity { /** * @author Michael A. MacDonald */ /* * 调整linux应用的界面 */ public static boolean isLinux = false; public static int deltaX = 135; public static boolean LoadingIsDone = false; class ZoomInputHandler extends AbstractGestureInputHandler { /** * In drag mode (entered with long press) you process mouse events * without sending them through the gesture detector */ private boolean dragMode; /** * Key handler delegate that handles DPad-based mouse motion */ private DPadMouseKeyHandler keyHandler; /** * @param c */ ZoomInputHandler() { super(VncCanvasActivity.this); keyHandler = new DPadMouseKeyHandler(VncCanvasActivity.this,vncCanvas.handler); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getHandlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getString( R.string.input_mode_touch_pan_zoom_mouse); //R.string.input_mode_mouse); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return TOUCH_ZOOM_MODE; } /* * (non-Javadoc) * * @see android.androidVNC.VncCanvasActivity.ZoomInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { return keyHandler.onKeyDown(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.VncCanvasActivity.ZoomInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { return keyHandler.onKeyUp(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return trackballMouse(evt); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onDown(android.view.MotionEvent) */ @Override public boolean onDown(MotionEvent e) { panner.stop(); return true; } /** * Divide stated fling velocity by this amount to get initial velocity * per pan interval */ static final float FLING_FACTOR = 8; /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onFling(android.view.MotionEvent, * android.view.MotionEvent, float, float) */ @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { showZoomer(false); panner.start(-(velocityX / FLING_FACTOR), -(velocityY / FLING_FACTOR), new Panner.VelocityUpdater() { /* * (non-Javadoc) * * @see android.androidVNC.Panner.VelocityUpdater#updateVelocity(android.graphics.Point, * long) */ @Override public boolean updateVelocity(PointF p, long interval) { double scale = Math.pow(0.8, interval / 50.0); p.x *= scale; p.y *= scale; return (Math.abs(p.x) > 0.5 || Math.abs(p.y) > 0.5); } }); return true; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractGestureInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent e) { if (dragMode) { vncCanvas.changeTouchCoordinatesToFullFrame(e); if (e.getAction() == MotionEvent.ACTION_UP) dragMode = false; return vncCanvas.processPointerEvent(e, true); } else return super.onTouchEvent(e); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onLongPress(android.view.MotionEvent) */ @Override public void onLongPress(MotionEvent e) { showZoomer(true); BCFactory.getInstance().getBCHaptic().performLongPressHaptic( vncCanvas); dragMode = true; vncCanvas.processPointerEvent(vncCanvas .changeTouchCoordinatesToFullFrame(e), true); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onScroll(android.view.MotionEvent, * android.view.MotionEvent, float, float) */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (inScaling) return false; showZoomer(false); return vncCanvas.pan((int) distanceX, (int) distanceY); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onSingleTapConfirmed(android.view.MotionEvent) */ @Override public boolean onSingleTapConfirmed(MotionEvent e) { vncCanvas.changeTouchCoordinatesToFullFrame(e); vncCanvas.processPointerEvent(e, true); e.setAction(MotionEvent.ACTION_UP); return vncCanvas.processPointerEvent(e, false); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onDoubleTap(android.view.MotionEvent) */ @Override public boolean onDoubleTap(MotionEvent e) { vncCanvas.changeTouchCoordinatesToFullFrame(e); vncCanvas.processPointerEvent(e, true, true); e.setAction(MotionEvent.ACTION_UP); return vncCanvas.processPointerEvent(e, false, true); } } public class TouchpadInputHandler extends AbstractGestureInputHandler { /** * In drag mode (entered with long press) you process mouse events * without sending them through the gesture detector */ private boolean dragMode; float dragX, dragY; /** * Key handler delegate that handles DPad-based mouse motion */ private DPadMouseKeyHandler keyHandler; TouchpadInputHandler() { super(VncCanvasActivity.this); keyHandler = new DPadMouseKeyHandler(VncCanvasActivity.this,vncCanvas.handler); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getHandlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getString( R.string.input_mode_touchpad); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return TOUCHPAD_MODE; } /* * (non-Javadoc) * * @see android.androidVNC.VncCanvasActivity.ZoomInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { return keyHandler.onKeyDown(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.VncCanvasActivity.ZoomInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { return keyHandler.onKeyUp(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return trackballMouse(evt); } /** * scale down delta when it is small. This will allow finer control * when user is making a small movement on touch screen. * Scale up delta when delta is big. This allows fast mouse movement when * user is flinging. * @param deltaX * @return */ private float fineCtrlScale(float delta) { float sign = (delta>0) ? 1 : -1; delta = Math.abs(delta); if (delta>=1 && delta <=3) { delta = 1; }else if (delta <= 10) { delta *= 0.34; } else if (delta <= 30 ) { delta *= delta/30; } else if (delta <= 90) { delta *= (delta/30); } else { delta *= 3.0; } return sign * delta; } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onLongPress(android.view.MotionEvent) */ @Override public void onLongPress(MotionEvent e) { showZoomer(true); BCFactory.getInstance().getBCHaptic().performLongPressHaptic( vncCanvas); dragMode = true; dragX = e.getX(); dragY = e.getY(); // send a mouse down event to the remote without moving the mouse. remoteMouseStayPut(e); vncCanvas.processPointerEvent(e, true); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onScroll(android.view.MotionEvent, * android.view.MotionEvent, float, float) */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { if (BCFactory.getInstance().getBCMotionEvent().getPointerCount(e2) > 1) { if (inScaling) return false; showZoomer(false); return vncCanvas.pan((int) distanceX, (int) distanceY); } else { // compute the relative movement offset on the remote screen. float deltaX = -distanceX *vncCanvas.getScale(); float deltaY = -distanceY *vncCanvas.getScale(); deltaX = fineCtrlScale(deltaX); deltaY = fineCtrlScale(deltaY); // compute the absolution new mouse pos on the remote site. float newRemoteX = vncCanvas.mouseX + deltaX; float newRemoteY = vncCanvas.mouseY + deltaY; if (dragMode) { if (e2.getAction() == MotionEvent.ACTION_UP) dragMode = false; dragX = e2.getX(); dragY = e2.getY(); e2.setLocation(newRemoteX, newRemoteY); return vncCanvas.processPointerEvent(e2, true); } else { e2.setLocation(newRemoteX, newRemoteY); vncCanvas.processPointerEvent(e2, false); } } return true; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractGestureInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent e) { if (dragMode) { // compute the relative movement offset on the remote screen. float deltaX = (e.getX() - dragX) *vncCanvas.getScale(); float deltaY = (e.getY() - dragY) *vncCanvas.getScale(); dragX = e.getX(); dragY = e.getY(); deltaX = fineCtrlScale(deltaX); deltaY = fineCtrlScale(deltaY); // compute the absolution new mouse pos on the remote site. float newRemoteX = vncCanvas.mouseX + deltaX; float newRemoteY = vncCanvas.mouseY + deltaY; if (e.getAction() == MotionEvent.ACTION_UP) dragMode = false; e.setLocation(newRemoteX, newRemoteY); return vncCanvas.processPointerEvent(e, true); } else return super.onTouchEvent(e); } /** * Modify the event so that it does not move the mouse on the * remote server. * @param e */ private void remoteMouseStayPut(MotionEvent e) { e.setLocation(vncCanvas.mouseX, vncCanvas.mouseY); } /* * (non-Javadoc) * confirmed single tap: do a single mouse click on remote without moving the mouse. * @see android.view.GestureDetector.SimpleOnGestureListener#onSingleTapConfirmed(android.view.MotionEvent) */ @Override public boolean onSingleTapConfirmed(MotionEvent e) { boolean multiTouch = (BCFactory.getInstance().getBCMotionEvent().getPointerCount(e) > 1); remoteMouseStayPut(e); vncCanvas.processPointerEvent(e, true, multiTouch||vncCanvas.cameraButtonDown); e.setAction(MotionEvent.ACTION_UP); return vncCanvas.processPointerEvent(e, false, multiTouch||vncCanvas.cameraButtonDown); } /* * (non-Javadoc) * double tap: do two left mouse right mouse clicks on remote without moving the mouse. * @see android.view.GestureDetector.SimpleOnGestureListener#onDoubleTap(android.view.MotionEvent) */ @Override public boolean onDoubleTap(MotionEvent e) { remoteMouseStayPut(e); vncCanvas.processPointerEvent(e, true, true); e.setAction(MotionEvent.ACTION_UP); return vncCanvas.processPointerEvent(e, false, true); } /* * (non-Javadoc) * * @see android.view.GestureDetector.SimpleOnGestureListener#onDown(android.view.MotionEvent) */ @Override public boolean onDown(MotionEvent e) { panner.stop(); return true; } } private final static String TAG = "VncCanvasActivity"; AbstractInputHandler inputHandler; VncCanvas vncCanvas; VncDatabase database; private MenuItem[] inputModeMenuItems; private AbstractInputHandler inputModeHandlers[]; private ConnectionBean connection; private boolean trackballButtonDown; private static final int inputModeIds[] = { R.id.itemInputFitToScreen, R.id.itemInputTouchpad, R.id.itemInputMouse, R.id.itemInputPan, R.id.itemInputTouchPanTrackballMouse, R.id.itemInputDPadPanTouchMouse, R.id.itemInputTouchPanZoomMouse }; ZoomControls zoomer; Panner panner; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); AppConnection.getInstance().setActivity(this); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); database = new VncDatabase(this); Intent i = getIntent(); if (i.getStringExtra("appType") != null && i.getStringExtra("appType").equals("linux")) isLinux = true; else isLinux = false; connection = new ConnectionBean(); Uri data = i.getData(); if ((data != null) && (data.getScheme().equals("vnc"))) { String host = data.getHost(); // This should not happen according to Uri contract, but bug introduced in Froyo (2.2) // has made this parsing of host necessary int index = host.indexOf(':'); int port; if (index != -1) { try { port = Integer.parseInt(host.substring(index + 1)); } catch (NumberFormatException nfe) { port = 0; } host = host.substring(0,index); } else { port = data.getPort(); } if (host.equals(VncConstants.CONNECTION)) { if (connection.Gen_read(database.getReadableDatabase(), port)) { MostRecentBean bean = androidVNC.getMostRecent(database.getReadableDatabase()); if (bean != null) { bean.setConnectionId(connection.get_Id()); bean.Gen_update(database.getWritableDatabase()); } } } else { connection.setAddress(host); connection.setNickname(connection.getAddress()); connection.setPort(port); List<String> path = data.getPathSegments(); if (path.size() >= 1) { connection.setColorModel(path.get(0)); } if (path.size() >= 2) { connection.setPassword(path.get(1)); } connection.save(database.getWritableDatabase()); } } else { Bundle extras = i.getExtras(); if (extras != null) { connection.Gen_populate((ContentValues) extras .getParcelable(VncConstants.CONNECTION)); } if (connection.getPort() == 0) connection.setPort(5900); // Parse a HOST:PORT entry String host = connection.getAddress(); if (host.indexOf(':') > -1) { String p = host.substring(host.indexOf(':') + 1); try { connection.setPort(Integer.parseInt(p)); } catch (Exception e) { } connection.setAddress(host.substring(0, host.indexOf(':'))); } } setContentView(R.layout.canvas); vncCanvas = (VncCanvas) findViewById(R.id.vnc_canvas); //多点触控打开键盘 /* * vncCanvas.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub int j = event.getPointerCount(); if (event.getPointerCount() >= 3) { VncCanvasActivity.this.runOnUiThread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub InputMethodManager imm = (InputMethodManager)VncCanvasActivity.this.getSystemService(INPUT_METHOD_SERVICE); } }); } return false; } }); */ zoomer = (ZoomControls) findViewById(R.id.zoomer); vncCanvas.initializeVncCanvas(connection, new Runnable() { public void run() { setModes(); } }); zoomer.hide(); zoomer.setOnZoomInClickListener(new View.OnClickListener() { /* * (non-Javadoc) * * @see android.view.View.OnClickListener#onClick(android.view.View) */ @Override public void onClick(View v) { showZoomer(true); vncCanvas.scaling.zoomIn(VncCanvasActivity.this); } }); zoomer.setOnZoomOutClickListener(new View.OnClickListener() { /* * (non-Javadoc) * * @see android.view.View.OnClickListener#onClick(android.view.View) */ @Override public void onClick(View v) { showZoomer(true); vncCanvas.scaling.zoomOut(VncCanvasActivity.this); } }); zoomer.setOnZoomKeyboardClickListener(new View.OnClickListener() { /* * (non-Javadoc) * * @see android.view.View.OnClickListener#onClick(android.view.View) */ @Override public void onClick(View v) { InputMethodManager inputMgr = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); inputMgr.toggleSoftInput(0, 0); } }); panner = new Panner(this, vncCanvas.handler); inputHandler = getInputHandlerById(R.id.itemInputTouchPanZoomMouse); inputHandler = getInputHandlerById(R.id.itemInputFitToScreen); } /** * Set modes on start to match what is specified in the ConnectionBean; * color mode (already done) scaling, input mode */ void setModes() { AbstractInputHandler handler = getInputHandlerByName(connection .getInputMode()); AbstractScaling.getByScaleType(connection.getScaleMode()) .setScaleTypeForActivity(this); this.inputHandler = handler; showPanningState(); } ConnectionBean getConnection() { return connection; } /* * (non-Javadoc) * * @see android.app.Activity#onCreateDialog(int) */ @Override protected Dialog onCreateDialog(int id) { switch (id) { case R.layout.entertext: return new EnterTextDialog(this); } // Default to meta key dialog return new MetaKeyDialog(this); } /* * (non-Javadoc) * * @see android.app.Activity#onPrepareDialog(int, android.app.Dialog) */ @Override protected void onPrepareDialog(int id, Dialog dialog) { super.onPrepareDialog(id, dialog); if (dialog instanceof ConnectionSettable) ((ConnectionSettable) dialog).setConnection(connection); } @Override public void onConfigurationChanged(Configuration newConfig) { // ignore orientation/keyboard change super.onConfigurationChanged(newConfig); } @Override protected void onStop() { vncCanvas.disableRepaints(); super.onStop(); } @Override protected void onRestart() { vncCanvas.enableRepaints(); super.onRestart(); } /** {@inheritDoc} */ @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.vnccanvasactivitymenu, menu); if (vncCanvas.scaling != null) menu.findItem(vncCanvas.scaling.getId()).setChecked(true); Menu inputMenu = menu.findItem(R.id.itemInputMode).getSubMenu(); inputModeMenuItems = new MenuItem[inputModeIds.length]; for (int i = 0; i < inputModeIds.length; i++) { inputModeMenuItems[i] = inputMenu.findItem(inputModeIds[i]); } updateInputMenu(); menu.findItem(R.id.itemFollowMouse).setChecked( connection.getFollowMouse()); menu.findItem(R.id.itemFollowPan).setChecked(connection.getFollowPan()); return true; } /** * Change the input mode sub-menu to reflect change in scaling */ void updateInputMenu() { if (inputModeMenuItems == null || vncCanvas.scaling == null) { return; } for (MenuItem item : inputModeMenuItems) { item.setEnabled(vncCanvas.scaling .isValidInputMode(item.getItemId())); if (getInputHandlerById(item.getItemId()) == inputHandler) item.setChecked(true); } } /** * If id represents an input handler, return that; otherwise return null * * @param id * @return */ AbstractInputHandler getInputHandlerById(int id) { if (inputModeHandlers == null) { inputModeHandlers = new AbstractInputHandler[inputModeIds.length]; } for (int i = 0; i < inputModeIds.length; ++i) { if (inputModeIds[i] == id) { if (inputModeHandlers[i] == null) { switch (id) { case R.id.itemInputFitToScreen: inputModeHandlers[i] = new FitToScreenMode(); break; case R.id.itemInputPan: inputModeHandlers[i] = new PanMode(); break; case R.id.itemInputMouse: inputModeHandlers[i] = new MouseMode(); break; case R.id.itemInputTouchPanTrackballMouse: inputModeHandlers[i] = new TouchPanTrackballMouse(); break; case R.id.itemInputDPadPanTouchMouse: inputModeHandlers[i] = new DPadPanTouchMouseMode(); break; case R.id.itemInputTouchPanZoomMouse: inputModeHandlers[i] = new ZoomInputHandler(); break; case R.id.itemInputTouchpad: inputModeHandlers[i] = new TouchpadInputHandler(); break; } } return inputModeHandlers[i]; } } return null; } AbstractInputHandler getInputHandlerByName(String name) { AbstractInputHandler result = null; for (int id : inputModeIds) { AbstractInputHandler handler = getInputHandlerById(id); if (handler.getName().equals(name)) { result = handler; break; } } if (result == null) { //result = getInputHandlerById(R.id.itemInputTouchPanZoomMouse); result = getInputHandlerById(R.id.itemInputMouse); } return result; } int getModeIdFromHandler(AbstractInputHandler handler) { for (int id : inputModeIds) { if (handler == getInputHandlerById(id)) return id; } //return R.id.itemInputTouchPanZoomMouse; return R.id.itemInputMouse; } @Override public boolean onOptionsItemSelected(MenuItem item) { vncCanvas.afterMenu = true; switch (item.getItemId()) { case R.id.itemInfo: vncCanvas.showConnectionInfo(); return true; case R.id.itemSpecialKeys: showDialog(R.layout.metakey); return true; case R.id.itemColorMode: selectColorModel(); return true; // Following sets one of the scaling options case R.id.itemZoomable: case R.id.itemOneToOne: case R.id.itemFitToScreen: AbstractScaling.getById(item.getItemId()).setScaleTypeForActivity( this); item.setChecked(true); showPanningState(); return true; case R.id.itemCenterMouse: vncCanvas.warpMouse(vncCanvas.absoluteXPosition + vncCanvas.getVisibleWidth() / 2, vncCanvas.absoluteYPosition + vncCanvas.getVisibleHeight() / 2); return true; case R.id.itemDisconnect: vncCanvas.closeConnection(); finish(); return true; case R.id.itemEnterText: showDialog(R.layout.entertext); return true; case R.id.itemCtrlAltDel: vncCanvas.sendMetaKey(MetaKeyBean.keyCtrlAltDel); return true; case R.id.itemFollowMouse: boolean newFollow = !connection.getFollowMouse(); item.setChecked(newFollow); connection.setFollowMouse(newFollow); if (newFollow) { vncCanvas.panToMouse(); } connection.save(database.getWritableDatabase()); return true; case R.id.itemFollowPan: boolean newFollowPan = !connection.getFollowPan(); item.setChecked(newFollowPan); connection.setFollowPan(newFollowPan); connection.save(database.getWritableDatabase()); return true; case R.id.itemArrowLeft: vncCanvas.sendMetaKey(MetaKeyBean.keyArrowLeft); return true; case R.id.itemArrowUp: vncCanvas.sendMetaKey(MetaKeyBean.keyArrowUp); return true; case R.id.itemArrowRight: vncCanvas.sendMetaKey(MetaKeyBean.keyArrowRight); return true; case R.id.itemArrowDown: vncCanvas.sendMetaKey(MetaKeyBean.keyArrowDown); return true; case R.id.itemSendKeyAgain: sendSpecialKeyAgain(); return true; case R.id.itemOpenDoc: Utils.showDocumentation(this); return true; default: AbstractInputHandler input = getInputHandlerById(item.getItemId()); if (input != null) { inputHandler = input; connection.setInputMode(input.getName()); if (input.getName().equals(TOUCHPAD_MODE)) connection.setFollowMouse(true); item.setChecked(true); showPanningState(); connection.save(database.getWritableDatabase()); return true; } } return super.onOptionsItemSelected(item); } //added by dhm Fix PPt Bug public void setConnectionInputMode(int id) { vncCanvas.afterMenu = true; AbstractInputHandler input = getInputHandlerById(id); if (input != null) { inputHandler = input; connection.setInputMode(input.getName()); if (input.getName().equals(TOUCHPAD_MODE)) connection.setFollowMouse(true); showPanningState(); connection.save(database.getWritableDatabase()); } } private MetaKeyBean lastSentKey; private void sendSpecialKeyAgain() { if (lastSentKey == null || lastSentKey.get_Id() != connection.getLastMetaKeyId()) { ArrayList<MetaKeyBean> keys = new ArrayList<MetaKeyBean>(); Cursor c = database.getReadableDatabase().rawQuery( MessageFormat.format("SELECT * FROM {0} WHERE {1} = {2}", MetaKeyBean.GEN_TABLE_NAME, MetaKeyBean.GEN_FIELD__ID, connection .getLastMetaKeyId()), MetaKeyDialog.EMPTY_ARGS); MetaKeyBean.Gen_populateFromCursor(c, keys, MetaKeyBean.NEW); c.close(); if (keys.size() > 0) { lastSentKey = keys.get(0); } else { lastSentKey = null; } } if (lastSentKey != null) vncCanvas.sendMetaKey(lastSentKey); } @Override protected void onDestroy() { super.onDestroy(); if (isFinishing()) { vncCanvas.closeConnection(); vncCanvas.onDestroy(); database.close(); } } @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { if (keyCode == KeyEvent.KEYCODE_MENU) return super.onKeyDown(keyCode, evt); if(keyCode == KeyEvent.KEYCODE_BACK){ System.out.println("KeyCodeBack"); AppConnection.getInstance().requestCloseWindow(); System.out.println("-------------------"); return true; } return inputHandler.onKeyDown(keyCode, evt); } @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { if (keyCode == KeyEvent.KEYCODE_MENU) return super.onKeyUp(keyCode, evt); return inputHandler.onKeyUp(keyCode, evt); } public void showPanningState() { // Toast.makeText(this,inputHandler.getHandlerDescription(), // Toast.LENGTH_SHORT).show(); } /* * (non-Javadoc) * * @see android.app.Activity#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: trackballButtonDown = true; break; case MotionEvent.ACTION_UP: trackballButtonDown = false; break; } return inputHandler.onTrackballEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { return inputHandler.onTouchEvent(event); } private void selectColorModel() { // Stop repainting the desktop // because the display is composited! vncCanvas.disableRepaints(); String[] choices = new String[COLORMODEL.values().length]; int currentSelection = -1; for (int i = 0; i < choices.length; i++) { COLORMODEL cm = COLORMODEL.values()[i]; choices[i] = cm.toString(); if (vncCanvas.isColorModel(cm)) currentSelection = i; } final Dialog dialog = new Dialog(this); dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); ListView list = new ListView(this); list.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_checked, choices)); list.setChoiceMode(ListView.CHOICE_MODE_SINGLE); list.setItemChecked(currentSelection, true); list.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { dialog.dismiss(); COLORMODEL cm = COLORMODEL.values()[arg2]; vncCanvas.setColorModel(cm); connection.setColorModel(cm.nameString()); connection.save(database.getWritableDatabase()); //Toast.makeText(VncCanvasActivity.this, //"Updating Color Model to " + cm.toString(), //Toast.LENGTH_SHORT).show(); } }); dialog.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss(DialogInterface arg0) { Log.i(TAG, "Color Model Selector dismissed"); // Restore desktop repaints vncCanvas.enableRepaints(); } }); dialog.setContentView(list); dialog.show(); } float panTouchX, panTouchY; /** * Pan based on touch motions * * @param event */ private boolean pan(MotionEvent event) { float curX = event.getX(); float curY = event.getY(); int dX = (int) (panTouchX - curX); int dY = (int) (panTouchY - curY); return vncCanvas.pan(dX, dY); } boolean defaultKeyDownHandler(int keyCode, KeyEvent evt) { if (vncCanvas.processLocalKeyEvent(keyCode, evt)) return true; return super.onKeyDown(keyCode, evt); } boolean defaultKeyUpHandler(int keyCode, KeyEvent evt) { if (vncCanvas.processLocalKeyEvent(keyCode, evt)) return true; return super.onKeyUp(keyCode, evt); } boolean touchPan(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: panTouchX = event.getX(); panTouchY = event.getY(); break; case MotionEvent.ACTION_MOVE: pan(event); panTouchX = event.getX(); panTouchY = event.getY(); break; case MotionEvent.ACTION_UP: pan(event); break; } return true; } private static int convertTrackballDelta(double delta) { return (int) Math.pow(Math.abs(delta) * 6.01, 2.5) * (delta < 0.0 ? -1 : 1); } boolean trackballMouse(MotionEvent evt) { int dx = convertTrackballDelta(evt.getX()); int dy = convertTrackballDelta(evt.getY()); evt.offsetLocation(vncCanvas.mouseX + dx - evt.getX(), vncCanvas.mouseY + dy - evt.getY()); if (vncCanvas.processPointerEvent(evt, trackballButtonDown)) { return true; } return VncCanvasActivity.super.onTouchEvent(evt); } long hideZoomAfterMs; static final long ZOOM_HIDE_DELAY_MS = 2500; HideZoomRunnable hideZoomInstance = new HideZoomRunnable(); private void showZoomer(boolean force) { if (force || zoomer.getVisibility() != View.VISIBLE) { zoomer.show(); hideZoomAfterMs = SystemClock.uptimeMillis() + ZOOM_HIDE_DELAY_MS; vncCanvas.handler .postAtTime(hideZoomInstance, hideZoomAfterMs + 10); } } private class HideZoomRunnable implements Runnable { public void run() { if (SystemClock.uptimeMillis() >= hideZoomAfterMs) { zoomer.hide(); } } } /** * Touches and dpad (trackball) pan the screen * * @author Michael A. MacDonald * */ class PanMode implements AbstractInputHandler { /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { // DPAD KeyDown events are move MotionEvents in Panning Mode final int dPos = 100; boolean result = false; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: result = true; break; case KeyEvent.KEYCODE_DPAD_LEFT: onTouchEvent(MotionEvent .obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_MOVE, panTouchX + dPos, panTouchY, 0)); result = true; break; case KeyEvent.KEYCODE_DPAD_RIGHT: onTouchEvent(MotionEvent .obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_MOVE, panTouchX - dPos, panTouchY, 0)); result = true; break; case KeyEvent.KEYCODE_DPAD_UP: onTouchEvent(MotionEvent .obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_MOVE, panTouchX, panTouchY + dPos, 0)); result = true; break; case KeyEvent.KEYCODE_DPAD_DOWN: onTouchEvent(MotionEvent .obtain(1, System.currentTimeMillis(), MotionEvent.ACTION_MOVE, panTouchX, panTouchY - dPos, 0)); result = true; break; default: result = defaultKeyDownHandler(keyCode, evt); break; } return result; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { // Ignore KeyUp events for DPAD keys in Panning Mode; trackball // button switches to mouse mode switch (keyCode) { case KeyEvent.KEYCODE_DPAD_CENTER: inputHandler = getInputHandlerById(R.id.itemInputMouse); connection.setInputMode(inputHandler.getName()); connection.save(database.getWritableDatabase()); updateInputMenu(); showPanningState(); return true; case KeyEvent.KEYCODE_DPAD_LEFT: return true; case KeyEvent.KEYCODE_DPAD_RIGHT: return true; case KeyEvent.KEYCODE_DPAD_UP: return true; case KeyEvent.KEYCODE_DPAD_DOWN: return true; } return defaultKeyUpHandler(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent event) { return touchPan(event); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText(R.string.input_mode_panning); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return "PAN_MODE"; } } /** * The touchscreen pans the screen; the trackball moves and clicks the * mouse. * * @author Michael A. MacDonald * */ public class TouchPanTrackballMouse implements AbstractInputHandler { private DPadMouseKeyHandler keyHandler = new DPadMouseKeyHandler(VncCanvasActivity.this, vncCanvas.handler); /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { return keyHandler.onKeyDown(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { return keyHandler.onKeyUp(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent evt) { return touchPan(evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return trackballMouse(evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText( R.string.input_mode_touchpad_pan_trackball_mouse); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return "TOUCH_PAN_TRACKBALL_MOUSE"; } } static final String FIT_SCREEN_NAME = "FIT_SCREEN"; /** Internal name for default input mode with Zoom scaling */ static final String TOUCH_ZOOM_MODE = "TOUCH_ZOOM_MODE"; static final String MOUSE_POINT = "MOUSE_POINT";//zdy add static final String TOUCHPAD_MODE = "TOUCHPAD_MODE"; /** * In fit-to-screen mode, no panning. Trackball and touchscreen work as * mouse. * * @author Michael A. MacDonald * */ public class FitToScreenMode implements AbstractInputHandler { private DPadMouseKeyHandler keyHandler = new DPadMouseKeyHandler(VncCanvasActivity.this, vncCanvas.handler); /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { return keyHandler.onKeyDown(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { return keyHandler.onKeyUp(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return trackballMouse(evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText(R.string.input_mode_fit_to_screen); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return FIT_SCREEN_NAME; } } /** * Touch screen controls, clicks the mouse. * * @author Michael A. MacDonald * */ class MouseMode implements AbstractInputHandler { /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) return true; return defaultKeyDownHandler(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { inputHandler = getInputHandlerById(R.id.itemInputPan); showPanningState(); connection.setInputMode(inputHandler.getName()); connection.save(database.getWritableDatabase()); updateInputMenu(); return true; } return defaultKeyUpHandler(keyCode, evt); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent event) { // Mouse Pointer Control Mode // Pointer event is absolute coordinates. int j = event.getPointerCount(); if (event.getPointerCount() >= 3) { InputMethodManager imm = (InputMethodManager)VncCanvasActivity.this.getSystemService(INPUT_METHOD_SERVICE); imm.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT); //vncCanvas.setFocusable(true); // imm.setInputMethod(vncCanvas.getWindowToken(), id) return true; } else{ vncCanvas.changeTouchCoordinatesToFullFrame(event); if (vncCanvas.processPointerEvent(event, true)) return true; return VncCanvasActivity.super.onTouchEvent(event); } } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText(R.string.input_mode_mouse); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { //return "MOUSE"; return MOUSE_POINT; } } /** * Touch screen controls, clicks the mouse. DPad pans the screen * * @author Michael A. MacDonald * */ class DPadPanTouchMouseMode implements AbstractInputHandler { private boolean isPanning; /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyDown(int, * android.view.KeyEvent) */ @Override public boolean onKeyDown(int keyCode, KeyEvent evt) { int xv = 0; int yv = 0; boolean result = true; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: xv = -1; break; case KeyEvent.KEYCODE_DPAD_RIGHT: xv = 1; break; case KeyEvent.KEYCODE_DPAD_UP: yv = -1; break; case KeyEvent.KEYCODE_DPAD_DOWN: yv = 1; break; default: result = defaultKeyDownHandler(keyCode, evt); break; } if ((xv != 0 || yv != 0) && !isPanning) { final int x = xv; final int y = yv; isPanning = true; panner.start(x, y, new Panner.VelocityUpdater() { /* * (non-Javadoc) * * @see android.androidVNC.Panner.VelocityUpdater#updateVelocity(android.graphics.Point, * long) */ @Override public boolean updateVelocity(PointF p, long interval) { double scale = (2.0 * (double) interval / 50.0); if (Math.abs(p.x) < 500) p.x += (int) (scale * x); if (Math.abs(p.y) < 500) p.y += (int) (scale * y); return true; } }); vncCanvas.pan(x, y); } return result; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onKeyUp(int, * android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent evt) { boolean result = false; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_DOWN: panner.stop(); isPanning = false; result = true; break; default: result = defaultKeyUpHandler(keyCode, evt); break; } return result; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTouchEvent(android.view.MotionEvent) */ @Override public boolean onTouchEvent(MotionEvent event) { // Mouse Pointer Control Mode // Pointer event is absolute coordinates. vncCanvas.changeTouchCoordinatesToFullFrame(event); if (vncCanvas.processPointerEvent(event, true)) return true; return VncCanvasActivity.super.onTouchEvent(event); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#onTrackballEvent(android.view.MotionEvent) */ @Override public boolean onTrackballEvent(MotionEvent evt) { return false; } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#handlerDescription() */ @Override public CharSequence getHandlerDescription() { return getResources().getText( R.string.input_mode_dpad_pan_touchpad_mouse); } /* * (non-Javadoc) * * @see android.androidVNC.AbstractInputHandler#getName() */ @Override public String getName() { return "DPAD_PAN_TOUCH_MOUSE"; } } }