说说android下TV版本UC浏览器模拟鼠标的实现
无意中下载了一个TV版本的UC浏览器安装到机顶盒上,顺便体验了一把。感觉吗还行,原先以为UC浏览器会针对Android下TV的遥控器操作浏览网页会做出一些优化或者对网页做出一些重新编码什么的,但是结果不是原来是通过遥控器控制然后在Android下TV端模拟鼠标操作。
说到Android下模拟鼠标操作,想到我以前也做过这么一个项目就是在手机端开发一个客户端然后模拟鼠标操作Android下的TV,这个也是类似于TV版本的UC浏览器的操作方式。实现该功能的原理就是通过在linux下模拟按键和鼠标
输入(因为Android是跑在linux下的所以该原理也是同样适合的)。至于原理我这里就不多介绍了,感兴趣的朋友可以到网上查找查找,我这里为了节约大家的时间贴出了一篇 http://blog.csdn.net/chenzhixin/article/details/2173530 。
现在进入正题,既然是通过在linux下模拟按键和鼠标输入,但是Android是java语言开发的怎么才能调用到linux层去呢,大家可能想到了我们可以通过JNI调用到底层啊。是的,我这里也是这么实现的。看来JNI确实是一个好东西啊!Android下对于JNI的注册有两种方法,一种是静态注册一种是动态注册,其中在Android的源码中采用的比较多的是动态注册。关于这两种注册方式我在这里就不多做罗列了。我这里采用的是第一种方法静态注册,先来看看我这里提供的本地方法,如下所示:
输入(因为Android是跑在linux下的所以该原理也是同样适合的)。至于原理我这里就不多介绍了,感兴趣的朋友可以到网上查找查找,我这里为了节约大家的时间贴出了一篇 http://blog.csdn.net/chenzhixin/article/details/2173530 。
现在进入正题,既然是通过在linux下模拟按键和鼠标输入,但是Android是java语言开发的怎么才能调用到linux层去呢,大家可能想到了我们可以通过JNI调用到底层啊。是的,我这里也是这么实现的。看来JNI确实是一个好东西啊!Android下对于JNI的注册有两种方法,一种是静态注册一种是动态注册,其中在Android的源码中采用的比较多的是动态注册。关于这两种注册方式我在这里就不多做罗列了。我这里采用的是第一种方法静态注册,先来看看我这里提供的本地方法,如下所示:
/ ****************************************
* @author Administrator
*功能:通过jni调用实现远程模拟鼠标功能
***************************************/
public class MouseUtils
{
public native void mouse_clck(int type, int code , int value);//鼠标点击
public native void mouse_move(int type, int code , int value);//鼠标点击
public native void mouse_open();//打开鼠标
public native void mouse_close();//关掉鼠标
}
那么接下来的重点就是通过C语言来实现这些本地方法了,至于在Android层何时调用这些方法那就是业务层的
事了,下面的代码就是我用C语言实现的上述本地方法了,其中的input.h和uinput.h可以在linux下找到,这里我就不放在上面了。
#include<stdio.h>
#include<jni.h>
#include"com.coship.coshare.domain.MouseUtils.h"
#include <android/log.h>
#include<malloc.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "input.h"
#include "uinput.h"
#define die(str, args...) do { perror(str); exit(EXIT_FAILURE); } while(0);
#define LOG_TAG "System.out.c"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
int fd;
struct uinput_user_dev uidev; // uInput device structure
JNIEXPORT void JNICALL Java_com_coship_coshare_domain_MouseUtils_mouse_1clck
(JNIEnv * env, jobject obj , jint type, jint code , jint value )
{
simulate_mousesingleclick(fd);
}
JNIEXPORT void JNICALL Java_com_coship_coshare_domain_MouseUtils_mouse_1move
(JNIEnv *env, jobject obj , jint type , jint value_x , jint value_y)
{
simulate_mouse(fd, value_x, value_y);
}
JNIEXPORT void JNICALL Java_com_coship_coshare_domain_MouseUtils_mouse_1open
(JNIEnv *env, jobject obj)
{
fd = setup_uinput_device();
if(fd <= 0)
{
LOGI("error open keyboard:\n");
return;
}
}
JNIEXPORT void JNICALL Java_com_coship_coshare_domain_MouseUtils_mouse_1close
(JNIEnv *env, jobject obj)
{
close_mouse_device();
}
void close_mouse_device()
{
close(fd);
}
void simulate_mouse(int fd, int value_x, int value_y)
{
struct input_event event;
memset(&event, 0, sizeof(event));
gettimeofday(&event.time, NULL);
event.type = EV_REL;
event.code = REL_X;
event.value = value_x;
write(fd, &event, sizeof(event));
event.type = EV_REL;
event.code = REL_Y;
event.value = value_y;
write(fd, &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write(fd, &event, sizeof(event));
}
/******************************************
模拟鼠标点击
*****************************************/
void simulate_mousesingleclick(int fd)
{
struct input_event event;
memset(&event, 0, sizeof(event));
gettimeofday(&event.time, NULL);
event.type = EV_KEY;
event.code = BTN_LEFT;
event.value = 1;
write(fd, &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write(fd, &event, sizeof(event));
event.type = EV_KEY;
event.code = BTN_LEFT;
event.value = 0;
write(fd, &event, sizeof(event));
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
write(fd, &event, sizeof(event));
}
/***************************
打开鼠标
***************************/
int setup_uinput_device()
{
int i=0;
// Open the input device
fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if(fd < 0)
{
die("error: open /dev/uinput");
}
memset(&uidev, 0, sizeof(uidev)); // Intialize the uInput device to NULL
snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-Openkk");
uidev.id.bustype = BUS_USB;
uidev.id.vendor = 0x1;
uidev.id.product = 0x1;
uidev.id.version = 1;
// Setup the driver I/O channels
ioctl(fd, UI_SET_EVBIT, EV_KEY);
ioctl(fd, UI_SET_KEYBIT, BTN_LEFT);
for (i=0; i < 256; i++)
{
ioctl(fd, UI_SET_KEYBIT, i);
}
ioctl(fd, UI_SET_EVBIT, EV_REL);
ioctl(fd, UI_SET_RELBIT, REL_X);
ioctl(fd, UI_SET_RELBIT, REL_Y);
/* Create input device into input sub-system */
write(fd, &uidev, sizeof(uidev));
if(ioctl(fd, UI_DEV_CREATE) < 0)
{
die("error: create uinput device");
LOGI("error: create uinput device");
}
return fd;
}
如上就是在Android下实现模拟鼠标的简单思路了,至于怎么将手机客户端的相关命令发送到Android下的TV端然后再模拟鼠标这个的方法就老多了,譬如可以通过网络啊通过蓝牙啊。这些东西就不在我讨论的范围之内了。我这里只是提供了一个简单思路。