20090826 Android上使用觸控面板(TouchScreen)模擬KeyEvent (三)
最後就是模擬Key的部份了,其實比讀取還簡單,這都得歸功於Input Subsystem的設計,Service只要呼叫EventReader.SimulateKey(KeyboardFD, code); 這裡的KeyboardFD 就是/dev/input/eventX,而Code則是可以去看 KernelSource/include/linux/input.h 裡面有提到 Backspace = 14,
下面是c的code
1: JNIEXPORT jint JNICALL Java_ITRI_MTube_EventReader_SimulateKey(JNIEnv *env, jclass c, jstring KbdFD, jshort code)
2: {
3: struct input_event event;
4: int fd;
5: const jbyte *FD;
6: FD = (*env)->GetStringUTFChars(env, KbdFD, NULL);
7: if (FD == NULL) {
8: return NULL; /* OutOfMemoryError already thrown */
9: }
10:
11: if ((fd = open(FD, O_RDWR)) < 0) {
12: (*env)->ReleaseStringUTFChars(env, KbdFD, FD);
13: return -1;
14: }
15:
16: (*env)->ReleaseStringUTFChars(env, KbdFD, FD);
17: event.type = EV_KEY;
18: event.code = code;
19: //keydown
20: event.value = 1;
21: if (write(fd, &event, sizeof(event)) < 0){
22: return -2;
23: }
24: //keyup
25: event.value = 0;
26: if (write(fd, &event, sizeof(event)) < 0){
27: return -2;
28: }
29: close(fd);
30: return 0;
31: }
最後,上面還有一個地方忘記講,KbdFD按照道理來說應該是沒東西的,因為我們只有一個輸入裝置,也就是觸控面板(TouchScreen),所以/dev/input/下面應該只會有一個 event0,所以我在probe裡面又仿照了另一個input_device出來,關於Keyboard Device的初始化可以抄 KernelSource/drivers/hid/usbhid/usbkbd.c裡面,其他部分就抄原本的 Touch Device的初始化,比較特殊的是 open & close這兩個function pointer我做了兩個空的函式來:
1: static int keytouch_open(struct input_dev *input)
2: {
3: return 0;
4: }
5:
6: static void keytouch_close(struct input_dev *input)
7: {}
8:
其實根據我印象中看Input Subsystem的 code,這裡不建立另一個Event Device也可以,因為User Level把模擬按鍵送下去的時候,就會直接轉給Input_handler了,完全不會到input_device,也就是我們的touch driver。
最後,再貼一下,Android上面的Service的寫法,
1: boolean IsServiceStarted=false;
2: @Override
3: public void onCreate(Bundle savedInstanceState) {
4: super.onCreate(savedInstanceState);
5: setContentView(R.layout.main);
6: Intent intent=new Intent(this, TaskbarLauncherService.class);
7: Bundle b= new Bundle();
8: b.putString("TouchScreenFD", "/dev/input/event0");
9: b.putString("KeyboardFD", "/dev/input/event1");
10: intent.putExtras(b);
11: intent.putExtra("TouchScreenFD", "/dev/input/event0");
12: intent.putExtra("KeyboardFD", "/dev/input/event1");
13:
14: this.startService(intent);
15:
16: IsServiceStarted=true;
17:
18: //this.startService(new Intent("ITRI.MTube.TaskbarLauncherService"));
19:
20: }
21:
而在TaskbarLauncherService.java裡面則是
1: @Override
2: public void onStart(Intent intent, int startId)
3: {
4: super.onStart(intent, startId);
5: PointHistory = new ArrayList<Point>();
6: Thread thCheckEvent = new Thread(doCheckEvent, "CheckEvent");
7: thCheckEvent.start();
8: }
9:
10: private Runnable doCheckEvent = new Runnable()
11: {
12: public void run()
13: {
14: while (true)
15: {
16: boolean DuplicatePoint = false;
17: // EventReader er=new EventReader();
18: // long i=er.Add(10, 60000);
19: // Log.i(TAG, "Start Reading Event!");
20: // event0 is for the TouchScreen Evdev
21: int RetCode = EventReader.ReadPointer(TouchScreenFD);
22: // Log.i(TAG, "RetCode:" + Integer.toString(RetCode));
23: if (RetCode > 0)
24: { //event happen
25:
26: //read Pointer Data
27: }
28: }
29: }
30: }
31:
Manifest則要加上才能使用Service & 開機自動執行
<receiver android:name=".TaskbarLauncherServiceInitiator" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name=".TaskbarLauncherService">
<intent-filter>
<action android:name="ITRI.MTube.TaskbarLauncherService" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
留言