Android 模拟按键事件(KeyEvent)

新换的手机,屏幕有点大,操作起来有点费劲,找了一些虚拟按键类的软件,都不是很简洁,最后想写个虚拟返回按钮。

 

 

Instrumentation inst=new Instrumentation();
inst.sendKeyDownUpSync(KeyCode);

 这段代码在非UI线程调用可以达到返回键的效果,但是不能跨进程(怒!不能跨进程要你何用)。严格来讲不是不能,而是比较麻烦。

 

http://www.cnblogs.com/TerryBlog/archive/2012/06/07/2539866.html  这篇帖子看似给出方案。用ndk封装的方式忽略。第二种修改为系统进程的方式需要源码环,拿到公钥等,除了自己编译的rom,其他的rom不可能拿到这些。

 

还有一种方式是:

private void sendKeyEvent(int keyCode) {  
    int eventCode = keyCode;  
    long now = SystemClock.uptimeMillis();  
    try {  
        KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, eventCode, 0);  
        KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, eventCode, 0);  
        (IWindowManager.Stub  
            .asInterface(ServiceManager.getService("window")))  
            .injectInputEventNoWait(down);  
        (IWindowManager.Stub  
            .asInterface(ServiceManager.getService("window")))  
            .injectInputEventNoWait(up);  
    } catch (RemoteException e) {  
        Log.i(TAG, "DeadOjbectException");  
    }  
}  

 这种方式在1.6版本以后就被放弃了删掉了,新版系统源码中根本就没有这个类

 

最终的解决办法:

上述帖子三楼给出了模拟系统协议的方式。这种方式可以跨进程,但是需要root

大部分虚拟按键类软件都是这么做的。

这个开源项目就是一个很好的例子:国人开发的

 

https://code.google.com/p/assistivetouch/

 

提取其中关键类和代码 如下:

 

RootContext.java

package com.leon.assistivetouch.main.util;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import android.content.Context;

/** 
 * 类名      RootContext.java
 * 说明  获取root权限
 * 创建日期 2012-8-21
 * 作者  LiWenLong
 * Email [email protected]
 * 更新时间  $Date$
 * 最后更新者 $Author$
*/
public class RootContext {
	private static RootContext instance = null;
	private static Object mLock = new Object();
	String mShell;
	OutputStream o;
	Process p;

	private RootContext(String cmd) throws Exception {
		this.mShell = cmd;
		init();
	}
	
	public static RootContext getInstance() {
		if (instance != null) {
			return instance;
		}
		synchronized (mLock) {
			try {
				instance = new RootContext("su");
			} catch (Exception e) {
				while (true)
					try {
						instance = new RootContext("/system/xbin/su");
					} catch (Exception e2) {
						try {
							instance = new RootContext("/system/bin/su");
						} catch (Exception e3) {
							e3.printStackTrace();
						}
					}
			}
			return instance;
		}
	}

	private void init() throws Exception {
		if ((this.p != null) && (this.o != null)) {
			this.o.flush();
			this.o.close();
			this.p.destroy();
		}
		this.p = Runtime.getRuntime().exec(this.mShell);
		this.o = this.p.getOutputStream();
		system("LD_LIBRARY_PATH=/vendor/lib:/system/lib ");
	}

	private void system(String cmd) {
		try {
			this.o.write((cmd + "\n").getBytes("ASCII"));
			return;
		} catch (Exception e) {
			while (true)
				try {
					init();
				} catch (Exception e1) {
					e1.printStackTrace();
				}
		}
	}

	public void runCommand(String cmd) {
		system(cmd);
	}

	/**
	 * 判断是否已经root了 
	 * */
	public static boolean hasRootAccess(Context ctx) {
		final StringBuilder res = new StringBuilder();
		try {
			if (runCommandAsRoot(ctx, "exit 0", res) == 0)
				return true;
		} catch (Exception e) {
		}
		return false;
	}

	/**
	 * 以root的权限运行命令
	 * */
	public static int runCommandAsRoot(Context ctx, String script,
			StringBuilder res) {
		final File file = new File(ctx.getCacheDir(), "secopt.sh");
		final ScriptRunner runner = new ScriptRunner(file, script, res);
		runner.start();
		try {
			runner.join(40000);
			if (runner.isAlive()) {
				runner.interrupt();
				runner.join(150);
				runner.destroy();
				runner.join(50);
			}
		} catch (InterruptedException ex) {
		}
		return runner.exitcode;
	}

	private static final class ScriptRunner extends Thread {
		private final File file;
		private final String script;
		private final StringBuilder res;
		public int exitcode = -1;
		private Process exec;

		public ScriptRunner(File file, String script, StringBuilder res) {
			this.file = file;
			this.script = script;
			this.res = res;
		}

		@Override
		public void run() {
			try {
				file.createNewFile();
				final String abspath = file.getAbsolutePath();
				Runtime.getRuntime().exec("chmod 777 " + abspath).waitFor();
				final OutputStreamWriter out = new OutputStreamWriter(
						new FileOutputStream(file));
				if (new File("/system/bin/sh").exists()) {
					out.write("#!/system/bin/sh\n");
				}
				out.write(script);
				if (!script.endsWith("\n"))
					out.write("\n");
				out.write("exit\n");
				out.flush();
				out.close();

				exec = Runtime.getRuntime().exec("su");
				DataOutputStream os = new DataOutputStream(exec.getOutputStream());
				os.writeBytes(abspath);
				os.flush();
				os.close();

				InputStreamReader r = new InputStreamReader(
						exec.getInputStream());
				final char buf[] = new char[1024];
				int read = 0;
				while ((read = r.read(buf)) != -1) {
					if (res != null)
						res.append(buf, 0, read);
				}

				r = new InputStreamReader(exec.getErrorStream());
				read = 0;
				while ((read = r.read(buf)) != -1) {
					if (res != null)
						res.append(buf, 0, read);
				}

				if (exec != null)
					this.exitcode = exec.waitFor();
			} catch (InterruptedException ex) {
				if (res != null)
					res.append("\nOperation timed-out");
			} catch (Exception ex) {
				if (res != null)
					res.append("\n" + ex);
			} finally {
				destroy();
			}
		}

		public synchronized void destroy() {
			if (exec != null)
				exec.destroy();
			exec = null;
		}
	}
}

 

模拟按键指令:

RootContext.getInstance().runCommand("input keyevent " + KeyEvent.KEYCODE_BACK);

 

ps:缺点,反应慢。想想这也是市面上找不到像样的虚拟按键类软件的原因吧,体验太差。

最后的最后,放弃了。凑合着用吧。

 

你可能感兴趣的:(android)