在google remote中,android接收端接收socket發來的IR CODE,然後將IR CODE模擬出來發給系統處理,這就是google remote接收端的原理。
系統端怎樣模擬input event呢?
方法一:通過Instrumentation.sendKeyDownUpSync 實現,簡單使用但是問題在於sendKeyDownUpSync發出的event,無法運行到
interceptKeyBeforeDispatching,也就無法正常作用 HOME,VOL…
方法二:通過uinput橋接;原理是利用內核現有的uinput驅動,通過內核驅動uinput來發送input event,而且還容易使用kl,kcm 客制化;
經過比較方法二較優,下面就就給出方法二的測試代碼…
1、main函數,setup_uinput_device 完成設備的註冊,然後創建一個線程 VirtualInputDev_EventThread,該線程重復發出keycode;
int main() { printf("Enter process !!!! \n"); stVirtualInputDevData *pKpdData = (stVirtualInputDevData*) malloc(sizeof(stVirtualInputDevData)); pKpdData->min_keycode = umin_keycode; pKpdData->max_keycode = umax_keycode; if (setup_uinput_device(pKpdData) < 0) { printf("Unable to find uInput device\n"); free(pKpdData); return -1; } pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); if (0 != pthread_create(&keypad_EventThreadId, &attr, VirtualInputDev_EventThread, (void *)0)) { printf("Create KeypadEventThread Failed!!\n"); exit(1); } // Coverity server need set to ignore this. while (1) { usleep(1000000); // sleep 1 second } free(pKpdData); pKpdData = 0; // Destroy the device ioctl(uinp_fd, UI_DEV_DESTROY); close(uinp_fd); return 0; }
2、setup_uinput_device函數,完成設備註冊;可以看到是直接打開uinput節點,設置瞭虛擬設備的name,verdor,product,bustype,
最後通過ioctl(uinp_fd, UI_DEV_CREATE)註冊設備
int setup_uinput_device(stVirtualInputDevData* mstVirtualInputDevData) { struct uinput_user_dev uinp; // uInput device structure int i; // Open the input device uinp_fd = open("/dev/uinput", O_WRONLY | O_NDELAY); if (uinp_fd == 0) { printf("Unable to open /dev/uinput\n"); return -1; } // Intialize the uInput device to NULL memset(&uinp, 0x00, sizeof(uinp)); strncpy(uinp.name, "virtualinputdev", sizeof(uinp.name)-1); uinp.id.vendor = 0x1341; uinp.id.product = 0x0001; uinp.id.bustype = BUS_VIRTUAL; // Keyboard ioctl(uinp_fd, UI_SET_EVBIT, EV_KEY); for (i = mstVirtualInputDevData->min_keycode; i max_keycode; i++) { ioctl(uinp_fd, UI_SET_KEYBIT, i); } // Create input device into input sub-system if (write(uinp_fd, &uinp, sizeof(uinp)) != sizeof(uinp)) { printf("First write returned fail.\n"); return -1; } if (ioctl(uinp_fd, UI_DEV_CREATE)) { printf("ioctl UI_DEV_CREATE returned fail.\n"); return -1; } return 1; }
3、線程 VirtualInputDev_EventThread,隻是重復發key,發key是通過write_event_to_device來完成的
static void* VirtualInputDev_EventThread(void *driver_data) { unsigned char u8Keycode,i=umin_keycode; while (1) { u8Keycode = 0xff; /* sleep an interval time */ usleep(2000000);//sleep 5 s /* fill event to uinput device. */ write_event_to_device(i++, 0); if(i==4){ i = 0; } printf ("virtualinputdev thread ...\n"); //i %= umax_keycode; } printf ("virtualinputdev thread died\n"); pthread_exit(0); return 0; }
4、write_event_to_device 寫event到uinput節點
void write_event_to_device(unsigned char u8KeyCode, unsigned char u8Repeat) { struct input_event event; // Input device structure struct timespec s; s.tv_nsec = 5000000L; s.tv_sec = 0; memset(&event, 0x00, sizeof(event)); gettimeofday(&event.time, 0); event.type = EV_KEY; event.code = u8KeyCode; event.value = 1; write(uinp_fd, &event, sizeof(event)); memset(&event, 0x00, sizeof(event)); gettimeofday(&event.time, 0); event.type = EV_KEY; event.code = u8KeyCode; event.value = 0; write(uinp_fd, &event, sizeof(event)); memset(&event, 0x00, sizeof(event)); gettimeofday(&event.time, 0); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; write(uinp_fd, &event, sizeof(event)); }