手機(jī)遙控器要求有模擬鼠標(biāo)功能轧葛,之前別人做的模擬鼠標(biāo)是用service加上自己畫(huà)的圖標(biāo)來(lái)實(shí)現(xiàn)的,不能像真正鼠標(biāo)一樣方便,而且實(shí)現(xiàn)比較難例嘱。網(wǎng)上查找資料發(fā)現(xiàn)可以通過(guò)UInput來(lái)實(shí)現(xiàn)這個(gè)功能玛迄。
Uinput是一個(gè)虛擬的設(shè)備由境,使得可以在用戶控件處理input設(shè)備,一般來(lái)講uinput設(shè)備文件存在于/dev/input或者/dev/input/uinput目錄中蓖议。在Linux中一切都是文件虏杰,所以使用uinput也很簡(jiǎn)單只需要open這個(gè)設(shè)備就可以了
打開(kāi)設(shè)備:
extern "C"
JNIEXPORT int JNICALL
Java_com_remote_uinput_UInput_open(JNIEnv *env, jclass clazz) {
struct uinput_user_dev uidev;
//以只讀的方式打開(kāi)字符設(shè)備
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
// if (fd < 0) die("error: open ");
LOGD( "fd == %d", fd);
//打印出打開(kāi)設(shè)備失敗的原因,可以看看是否因?yàn)闄?quán)限導(dǎo)致
LOGD("open %s fail, %s\n", "/dev/uinput", strerror(errno));
if (fd<0) {
LOGD( "fd == %d", fd);
return -1;
}
//config uinput working mode, mouse or touchscreen? relative coordinates or absolute coordinate?
if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) //support key button
die("error: ioctl UI_SET_EVBIT");
if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0) //support mouse left key
die("error: ioctl UI_SET_KEYBIT");
if (ioctl(fd, UI_SET_KEYBIT, BTN_RIGHT) < 0) //support mouse right key
die("error: ioctl UI_SET_KEYBIT");
if (ioctl(fd, UI_SET_EVBIT, EV_REL) < 0) //uinput use relative coordinates
die("error: ioctl UI_SET_EVBIT");
if (ioctl(fd, UI_SET_RELBIT, REL_X) < 0) //uinput use x coordinates
die("error: ioctl UI_SET_RELBIT REL_X");
if (ioctl(fd, UI_SET_RELBIT, REL_Y) < 0) //uinput use y coordinates
die("error: ioctl REL_Y");
memset(&uidev, 0,
sizeof(uidev)); //creat an virtul input device node in /dev/input/***
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-sample");//配置設(shè)備名稱
uidev.id.bustype = BUS_USB;//配置設(shè)備類型
uidev.id.vendor = 0x1;//配置設(shè)備vendor
uidev.id.product = 0x1;//配置設(shè)備product
uidev.id.version = 1;//配置設(shè)備version
//將配置寫(xiě)到uinput中
if (write(fd, &uidev, sizeof(uidev)) < 0){
die("error: write");
return -1;
}
//通過(guò)ioctl創(chuàng)建這個(gè)虛擬設(shè)備
if (ioctl(fd, UI_DEV_CREATE) < 0){
die("error: ioctl");
return -1;
}
return 1;
}
使用設(shè)備:
extern "C"
JNIEXPORT void JNICALL
Java_com_remote_uinput_UInput_simulateMouseMove(JNIEnv *env, jclass clazz, jint dx,
jint dy) {
struct input_event ev;//input_event 結(jié)構(gòu)體
//send input event to kernel input system
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_REL; //send x coordinates 事件類型 EV_REL相對(duì)事件勒虾, EV_KEY key事件纺阔, EV_ABS絕對(duì)事件
ev.code = REL_X;//鍵值
ev.value = dx;//key 1 表示按下,0表示釋放 鼠標(biāo)代表移動(dòng)距離
if (write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write");
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_REL; //send y coordinates
ev.code = REL_Y;
ev.value = dy;
if (write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write");
// memset(&ev, 0, sizeof(struct input_event));
// ev.type = EV_KEY; //mouse left key 左鍵
// ev.code = BTN_LEFT;
// ev.value = 1;
// if(write(fd, &ev, sizeof(struct input_event)) < 0)
// die("error: write");
//EV_SYN 同步 即執(zhí)行這個(gè)事件
memset(&ev, 0, sizeof(struct input_event));
ev.type = EV_SYN; // inform input system to process this input event
ev.code = 0;
ev.value = 0;
if (write(fd, &ev, sizeof(struct input_event)) < 0)
die("error: write");
}
銷毀:
extern "C"
JNIEXPORT void JNICALL
Java_com_ktc_remote_uinput_UInput_close(JNIEnv *env, jclass clazz) {
//銷毀這個(gè)設(shè)備
if (ioctl(fd, UI_DEV_DESTROY) < 0)
die("error: ioctl");
//關(guān)閉這個(gè)文件
close(fd);
}
這個(gè)方法不只是支持鼠標(biāo)模擬修然,包括按鍵模擬笛钝,觸摸屏模擬都可以實(shí)現(xiàn)质况,功能比較強(qiáng)大。
使用時(shí)需要注意玻靡,uinput這個(gè)文件不是可寫(xiě)的结榄,低版本的系統(tǒng)可以在應(yīng)用類修改文件權(quán)限,但是在高版本的Android中動(dòng)態(tài)修改權(quán)限會(huì)失敗囤捻,所以只能在系統(tǒng)初始化 init.rc中直接修改該文件為可讀寫(xiě)臼朗,其次需要修改selinux權(quán)限,否則會(huì)因?yàn)闄?quán)限不足無(wú)法創(chuàng)建設(shè)備蝎土。