`
jianweicao
  • 浏览: 120531 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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 lendylongli@gmail.com
 * 更新时间  $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 跨进程模拟按键(KeyEvent )实例详解

    本文将详细讲解如何实现Android跨进程模拟按键(KeyEvent)。 首先,我们来看一个基本的发送按键事件的代码片段: ```java public static void simulateKeystroke(final int keyCode) { new Thread(new Runnable...

    Android代码模拟按键事件

    在Android开发中,有时我们需要在程序中模拟按键事件,例如在自动化测试、游戏控制或特殊功能实现时。本文将深入探讨如何在Android代码中模拟按键事件,以按数字键1为例,并扩展到如何响应电源键事件使系统进入待机...

    android模拟按键发送消息

    在Android平台上,有...总的来说,Android模拟按键是一个技术性较强的话题,涉及到事件处理、权限控制以及可能的无障碍服务实现。开发者需要理解这些概念,并在合法和安全的前提下,合理地利用它们来增强应用的功能。

    android客户端模拟按键

    总之,Android平台提供了多种方式来模拟按键控制,包括使用`KeyEvent`处理按键事件,通过`MotionEvent`模拟触摸操作,以及利用`Instrumentation`和`UiAutomation`进行自动化测试。理解和熟练掌握这些方法对于Android...

    安卓模拟系统发送返回键值(KEYCODE_BACK)(csdn)————程序.pdf

    在实际应用中,如果需要在代码中触发返回操作,通常会调用`finish()`方法来关闭当前Activity,而不是模拟按键事件。 关于权限`<uses-permission android:name="android.permission.INJECT_EVENTS" />`,这是注入...

    android shell 模拟事件

    在Android Shell中模拟事件是调试和测试应用程序的一种常见方法,特别是对于那些需要手动触发特定用户输入行为的场景。本文将详细介绍如何使用Android Shell来模拟各种输入事件,包括长按、单击和滑动。 1. **基本...

    Android本地注入事件

    在Android系统中,"本地注入事件"是一种技术,允许应用程序模拟用户输入,如触摸屏点击、按键等。这种技术在进行自动化测试、调试或者特殊应用需求时非常有用。Android是基于Linux内核构建的,因此它继承了Linux的...

    android测试键值apk(一个测试键值的apk,将apk安装到系统,操作键盘或者遥控器,可打出相应键值).zip

    这些框架允许编写测试脚本来模拟按键事件,提高测试效率和覆盖率。 总的来说,"android测试键值apk"是一个实用的工具,它简化了开发者对Android应用按键事件测试的过程,确保应用在各种输入设备上都能提供一致且...

    android 媒体键监听 以及 媒体键模拟

    在Android中,可以使用`KeyEvent`类来创建和发送模拟的媒体键事件。以下是一个简单的例子,模拟按下播放/暂停键: ```java Activity activity = ...; // 获取当前活动 activity.runOnUiThread(new Runnable() { @...

    android添加外部按键

    在开发过程中,你可能需要模拟外部按键事件来测试你的应用程序。这时,可以使用如`adb`命令行工具,发送按键事件到设备或模拟器。例如,发送按键码为33(`KeyEvent.KEYCODE_X`)的按下和释放事件: ```bash adb ...

    安卓 adb shell input keyevent 按键大全.txt

    ADB Shell Input Keyevent命令用于发送虚拟按键事件到Android设备上,这可以模拟用户的键盘输入行为。下面将详细介绍各种类型的按键代码及其功能: #### 基本功能键 - **KEYCODE_CALL** (5):模拟拨打电话。 - **...

    Android-通过简单的代码控制手机的屏幕和物理按键

    - 模拟按键可能需要`<uses-permission android:name="android.permission.INJECT_EVENTS" />`权限,但这个权限通常只对系统应用开放,普通应用可能无法使用。 4. **注意事项**: - 不恰当的屏幕控制和按键模拟...

    SimulateKey:Simulate Android KeyEvent,Android按键模拟器

    在Java中,我们可以通过发送`KeyEvent`对象到系统的输入管道来模拟按键行为。`KeyEvent`主要有两个构造函数,一个用于创建新事件,另一个用于复制已有事件。通常,我们需要指定事件的类型(如ACTION_DOWN或ACTION_UP...

    Android键盘监控源码,检测按键

    在Android中,键盘事件通常以KeyEvent对象的形式传递。每个KeyEvent包含事件类型(ACTION_DOWN或ACTION_UP)、键码(如KEYCODE_A、KEYCODE_B等)和修饰符(如MetaKeys,如Ctrl、Alt)。通过解析这些信息,我们可以...

    android 全局悬浮按钮实现key事件

    `dispatchKeyEvent()`方法用于向系统发送自定义的按键事件。 要注意的是,直接处理key事件可能会影响到系统的正常行为,因此在实际应用中,通常会通过其他方式来实现类似的功能,例如使用意图(Intent)或者自定义...

    安卓Android源码——按键的处理.zip

    这份“安卓Android源码——按键的处理.zip”压缩包可能包含了关于Android系统如何管理和响应硬件按键以及软件模拟按键的源代码分析。让我们深入探讨一下这个主题。 首先,Android系统的按键处理主要分为两个层次:...

    利用monkey注入事件原理实现Android 事件注入

    在Android开发领域, Monkey工具是一种常用的自动化测试工具,它能够模拟用户随机的触摸、按键行为,帮助开发者检测应用的稳定性。本主题将深入探讨“利用monkey注入事件原理实现Android事件注入”的过程,以及如何...

    android命令行模拟输入事件(文字、按键、触摸等)

    2. **模拟按键**:`input keyevent <event_code>` - 这个命令可以模拟按下或释放指定的按键。按键代码(`event_code`)可以在Android的`KeyEvent`类中找到,例如: ```bash # 模拟按下返回键 adb shell input ...

    android_test.sh.zip_adb 测试_android_android shell_android模拟点击

    6. **按键模拟**:利用`adb shell input keyevent`模拟按键事件,如`input keyevent KEYCODE_ENTER`模拟回车键。 7. **日志收集**:通过`adb logcat`命令获取设备的日志信息,用于后期分析和调试。 8. **测试结束**...

    Android中三种注入事件方法比较

    在Android系统中,有时我们需要模拟用户输入事件,例如在自动化测试或者特定功能实现时。本文主要探讨了三种在Android中注入事件的方法:使用内部APIs、使用`Instrumentation`对象以及直接向设备的`/dev/input/...

Global site tag (gtag.js) - Google Analytics