一、驱动介绍
输入用户驱动程序为应用程序提供接口,向Android的输入管道注入事件。有了这个API,应用程序可以使用Peripheral I/O模拟一个人机界面的设备(HID)或者连接外部硬件到输入系统。比如说,我们可以使用开关按钮GPIO的信号输入,通过输入驱动API模拟呈键盘上按键的输入事件,下面我们会具体演示如何实现。
二、使用步骤
实现输入用户驱动,有如下步骤:
1.创建驱动:使用InputDriver.Builder和源类型SOURCE_CLASS_BUTTON创建一个新的输入驱动实例。
2.注册驱动:使用UserDriverManager的registerInputDriver()方法注册这个驱动。
4.注入事件:使用输入驱动的emit()方法向这个驱动中注入事件。
这里我们实现一个最简单的模拟键盘,通过两个开关按钮的GPIO信号输入,通过输入驱动API分别模拟键盘上a和b字母的输入。
1.硬件准备:
树莓派3开发板 1块
面包板 1块
按钮开关 2个
电阻 2个
杜邦线(母对公,公对公) 若干
广告时间咯:如果你还没有自己的开发板和元器件,到我们的“1024工场微店”来逛逛一逛吧(文章底部二维码),这里能一次性有买到你想要的!
2.电路搭建:
3.代码实现:
InputDemo\app\src\main\java\com\chengxiang\inputdemo\KeyDriverService.java
点击开关按钮,在输入框中会输入对应的A和B字母。
输入用户驱动程序为应用程序提供接口,向Android的输入管道注入事件。有了这个API,应用程序可以使用Peripheral I/O模拟一个人机界面的设备(HID)或者连接外部硬件到输入系统。比如说,我们可以使用开关按钮GPIO的信号输入,通过输入驱动API模拟呈键盘上按键的输入事件,下面我们会具体演示如何实现。
二、使用步骤
实现输入用户驱动,有如下步骤:
1.创建驱动:使用InputDriver.Builder和源类型SOURCE_CLASS_BUTTON创建一个新的输入驱动实例。
2.注册驱动:使用UserDriverManager的registerInputDriver()方法注册这个驱动。
public class TouchpadDriverService extends Service { // Driver parameters private static final String DRIVER_NAME = "Touchpad"; private static final int DRIVER_VERSION = 1; private InputDriver mDriver; @Override public void onCreate() { super.onCreate(); mDriver = InputDriver.builder(InputDevice.SOURCE_TOUCHPAD) .setName(DRIVER_NAME) .setVersion(DRIVER_VERSION) .setAbsMax(MotionEvent.AXIS_X, 255) .setAbsMax(MotionEvent.AXIS_Y, 255) .build(); UserDriverManager manager = UserDriverManager.getManager(); manager.registerInputDriver(mDriver); } }3.转换事件:当一个硬件事件发生,使用当前的事件代码和输入动作为每个状态改变构造一个新的KeyEvent。
4.注入事件:使用输入驱动的emit()方法向这个驱动中注入事件。
private void triggerEvent(boolean pressed) { int action = pressed ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP; KeyEvent[] events = new KeyEvent[] {new KeyEvent(action, KEY_CODE)}; if (!mDriver.emit(events)) { Log.w(TAG, "Unable to emit key event"); } }5.处理事件:在前台Activity通过实现onKeyDown()、onKeyUp()和onGenericMotionEvent()方法来获取相关事件,并处理。
public class HomeActivity extends Activity { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // Handle key pressed and repeated events return true; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // Handle key released events return true; } @Override public boolean onGenericMotionEvent(MotionEvent event) { // Handle motion input events return true; } }6.注销驱动:当你不在需要关键事件的时候注销驱动。
public class TouchpadDriverService extends Service { @Override public void onDestroy() { super.onDestroy(); UserDriverManager manager = UserDriverManager.getManager(); manager.unregisterInputDriver(mDriver); } }三、案例展示
1.硬件准备:
树莓派3开发板 1块
面包板 1块
按钮开关 2个
电阻 2个
杜邦线(母对公,公对公) 若干
广告时间咯:如果你还没有自己的开发板和元器件,到我们的“1024工场微店”来逛逛一逛吧(文章底部二维码),这里能一次性有买到你想要的!
2.电路搭建:
3.代码实现:
InputDemo\app\src\main\java\com\chengxiang\inputdemo\KeyDriverService.java
public class KeyDriverService extends Service { private static final String TAG = KeyDriverService.class.getSimpleName(); private static final String A_DRIVER_NAME = "Akey"; private static final int A_DRIVER_VERSION = 1; private static final int A_KEY_CODE = KeyEvent.KEYCODE_A; private static final String B_DRIVER_NAME = "Bkey"; private static final int B_DRIVER_VERSION = 1; private static final int B_KEY_CODE = KeyEvent.KEYCODE_B; private static final String A_GPIO_NAME = "BCM5"; private static final String B_GPIO_NAME = "BCM6"; private UserDriverManager mUserDriverManager; private InputDriver mADriver; private InputDriver mBDriver; private Gpio mAGpio; private Gpio mBGpio; private GpioCallback mGpioCallback = new GpioCallback() { @Override public boolean onGpioEdge(Gpio gpio) { Log.d(TAG, "onGpioEdge"); try { //获取开关按键的信号输入后,转换成A和B按键的输入事件 if (gpio == mAGpio) { triggerEvent(mADriver, gpio.getValue(), A_KEY_CODE); } else if (gpio == mBGpio) { triggerEvent(mBDriver, gpio.getValue(), B_KEY_CODE); } } catch (IOException e) { e.printStackTrace(); } return true; } @Override public void onGpioError(Gpio gpio, int error) { Log.w(TAG, gpio + ": Error event " + error); } }; public KeyDriverService() { } @Override public void onCreate() { super.onCreate(); PeripheralManagerService manager = new PeripheralManagerService(); try { mAGpio = manager.openGpio(A_GPIO_NAME); mAGpio.setDirection(Gpio.DIRECTION_IN); mAGpio.setActiveType(Gpio.ACTIVE_LOW); mAGpio.setEdgeTriggerType(Gpio.EDGE_BOTH); mAGpio.registerGpioCallback(mGpioCallback); mBGpio = manager.openGpio(B_GPIO_NAME); mBGpio.setDirection(Gpio.DIRECTION_IN); mBGpio.setActiveType(Gpio.ACTIVE_LOW); mBGpio.setEdgeTriggerType(Gpio.EDGE_BOTH); mBGpio.registerGpioCallback(mGpioCallback); } catch (IOException e) { e.printStackTrace(); } //分别创建A字母按键和B字母按键输入驱动实例 mADriver = InputDriver.builder(InputDevice.SOURCE_CLASS_BUTTON).setName(A_DRIVER_NAME) .setVersion(A_DRIVER_VERSION).setKeys(new int[]{A_KEY_CODE}).build(); mBDriver = InputDriver.builder(InputDevice.SOURCE_CLASS_BUTTON).setName(B_DRIVER_NAME) .setVersion(B_DRIVER_VERSION).setKeys(new int[]{B_KEY_CODE}).build(); //注册A字母按键和B字母按键输入驱动 mUserDriverManager = UserDriverManager.getManager(); mUserDriverManager.registerInputDriver(mADriver); mUserDriverManager.registerInputDriver(mBDriver); } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onDestroy() { super.onDestroy(); if (mAGpio != null) { try { mAGpio.unregisterGpioCallback(mGpioCallback); mAGpio.close(); mAGpio = null; } catch (IOException e) { Log.w(TAG, "Unable to close GPIO", e); } } if (mBGpio != null) { try { mBGpio.unregisterGpioCallback(mGpioCallback); mBGpio.close(); mBGpio = null; } catch (IOException e) { Log.w(TAG, "Unable to close GPIO", e); } } //当你不在需要关键事件的时候注销驱动 mUserDriverManager.unregisterInputDriver(mADriver); mUserDriverManager.unregisterInputDriver(mBDriver); } private void triggerEvent(InputDriver inputDriver, boolean pressed, int keyCode) { int action = pressed ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP; KeyEvent[] events = new KeyEvent[]{new KeyEvent(action, keyCode)}; //使用emit()方法转换成Android事件 if (!inputDriver.emit(events)) { Log.w(TAG, "Unable to emit key event"); } } }InputDemo\app\src\main\java\com\chengxiang\inputdemo\MainActivity.java
public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); private EditText mEditText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mEditText = (EditText) findViewById(R.id.edittext); //这里我们将输入焦点放在输入框中,故按下开关按钮会输入A和B字母 mEditText.requestFocus(); } //在前台Activity通过实现onKeyDown()、onKeyUp()和onGenericMotionEvent()方法来获取相关事件 @Override public boolean onKeyUp(int keyCode, KeyEvent event) { Log.d(TAG,"onKeyUp:" + keyCode); return true; } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { Log.d(TAG,"onKeyDown:" + keyCode); return true; } public void toNext(View view) { Intent intent = new Intent(this,NextActivity.class); startActivity(intent); } }4.运行结果:
点击开关按钮,在输入框中会输入对应的A和B字母。
作者:p106786860 发表于2017/3/22 1:14:00 原文链接
阅读:63 评论:0 查看评论