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>

Sample Source Download

留言

這個網誌中的熱門文章

好貴的東元冷氣維修--馬達啟動電容

台大醫院 婁培人 耳鼻喉科 就診

機車無法充電之整流器壞掉--$650