通信原理课设(gec6818) 004:触摸屏
1、触摸屏
就像之前说的,在linux中,一切皆文件。触摸屏:在linux也是一个文件:/dev/input/event0。触摸屏是一个二维的,我们的手在触摸屏上面滑动点击就是坐标的变动,而我们的内存又是一个一维的, 因此必须有多个参数才能表示这个坐标,因此输入事件是维护在一个结构体里面的
struct input_event
{
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
参数解释:
time:你的事件发生的时间,这个时间是一个绝对时间。绝对时间就是:1970.1.1 0:0:0到现在所有的秒数,一般为了去实现回溯,我们的点击和长按就可以通过这个时间去搞定。
type:你的事件的类型,这个值说明你现在获取到的是一个什么样子的输入事件(#define EV_ABS 0x03)
code:编码,这个编码在触摸屏事件里面是用于去区分XY轴的
#define REL_X 0x00
#define REL_Y 0x01value:值 这里表示坐标值。
if(code == REL_X) { x = value; } else if(code == REL_Y) { y = value; }
2、练习
在触摸屏上利用手势的变换,如上滑、下滑、左滑、右滑。实现切换图片的效果。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <linux/input.h>
int lcd_fd = -1; // Global LCD file descriptor
unsigned int *plcd = NULL; // Global mapping base address
void LcdInit(void) {
lcd_fd = open("/dev/fb0", O_RDWR);
if (-1 == lcd_fd) {
perror("open fb0 error");
exit(1);
}
plcd = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd_fd, 0);
if (MAP_FAILED == plcd) {
perror("mmap lcd error");
exit(2);
}
}
//绘制一个点
void Display(int x, int y, unsigned int color) {
if (x >= 0 && x < 800 && y >= 0 && y < 480) {
*(plcd + y * 800 + x) = color;
}
}
//打开bmp
void DisplayBmpPic(const char* pic)
{
//1、打开文件
int fd = open(pic , O_RDONLY);
if( fd == -1)
{
perror("open bmp error");
return;
}
//2、判断这个文件是不是真的bmp图片
//暂时省略
//读取bmp文件头相关信息:
int width,height,depth=0;
//读取宽度、高度
lseek(fd,0x12,SEEK_SET);
read(fd,&width,4);
read(fd,&height,4); //高度和宽度连在一起
//读取色深
lseek(fd,0x1c,SEEK_SET);
read(fd,&depth,2);
printf("width= %d height= %d depth= %d\n",width,height,depth);
//为了凑4的倍数,需要在每一行的后面加1/2/3/0个字节
int n =(4 - width * (depth / 8) % 4) % 4;
//计算像素数组 w*h*(depth/8) 由于数组较大,故采用动态内存分配
unsigned char *coclorbuf = malloc((width*(depth/8)+n)*height);
//读取像素数组,偏移过头部
lseek(fd,0x36,SEEK_SET);
read(fd,coclorbuf,(width*(depth/8)+n)*height);
//拿到每一个像素点的rgb
unsigned char c_a,c_r,c_g,c_b;
unsigned int color;
int i=0;//coclorbuf的下标
int x=400-(width/2),y=240+(height/2);//坐标
for(y=240+(height/2)-1 ; y>=240-(height/2) ; y--)//列
{
for(x=400-(width/2) ; x<width+400-(width/2) ; x++)//行
{
c_b = coclorbuf[i++];
c_g = coclorbuf[i++];
c_r = coclorbuf[i++];
if( 32 == depth) // 32/8=4 说明存储的是argb
{
c_a = coclorbuf[i++];
}
color = c_a<<24 | c_r<<16 | c_g<<8 | c_b;
Display(x,y,color);
}
i += n;//每走完一行都要跳过后面补的没用的n个字节
}
//释放动态分配内存 free只能释放动态内存空间
free(coclorbuf);
//3、关闭文件
close(fd);
}
//切换
void Switching()
{
int fd = open("/dev/input/event0",O_RDWR);
if(-1 == fd)
{
perror("open event0 error");
}
//操作这个触摸屏 一般触摸屏的操作是不会死掉的 因此我们需要实现死循环
struct input_event ev;
int flag = 0;//超时的flag
int ev_x0,ev_y0,ev_x,ev_y;
while(1)
{
//我们想获取坐标值 那么就是从这个文件里面读取内容
int r = read(fd,&ev,sizeof(ev));
if(sizeof(ev) != r)//读出问题出来了
{
usleep(10);
flag++;
if(10 <= flag)
{
//超时太多了 不行了
perror("read ev error");
break;
}
continue;
}
flag = 0;
//将数据打印出来看看
//printf("type:%d code:%d value:%d\n",ev.type,ev.code,ev.value);
//获取坐标
if(EV_ABS == ev.type)//接下来的数据就是坐标
{
if(REL_X == ev.code)//x轴
{
ev_x = ev.value;
}
else if(REL_Y == ev.code)//y轴
{
ev_y = ev.value;
}
}
if(0x01 == ev.type && BTN_TOUCH == ev.code && 0x01 == ev.value)//手按下去的时候
{
ev_x0 = ev_x;
ev_y0 = ev_y;
}
else if(0x01 == ev.type && BTN_TOUCH == ev.code && 0x00 == ev.value)//手抬起来
{
//实现点击和方向判断
if(ev_x0 == ev_x && ev_y0 == ev_y)//你的手没有动
{
printf("点击\n");
}
else//滑动 滑动就会有方向
{
if(ev_x > ev_x0 && abs(ev_x - ev_x0) > abs(ev_y - ev_y0))
{
//sprintf(picture,"%d.bmp",i);
//sprintf(picture,"%d.bmp",i);
lseek(fd,0x00,SEEK_SET);
DisplayBmpPic("1.bmp");
printf("右滑\n");
}
else if(ev_x < ev_x0 && abs(ev_x - ev_x0) > abs(ev_y - ev_y0))
{
lseek(fd,0x00,SEEK_SET);
DisplayBmpPic("2.bmp");
printf("左滑\n");
}
else if(ev_y > ev_y0 && abs(ev_y -ev_y0) > abs(ev_x - ev_x0))
{
lseek(fd,0x00,SEEK_SET);
DisplayBmpPic("3.bmp");
printf("上滑\n");
}
else if(ev_y < ev_y0 && abs(ev_y -ev_y0) > abs(ev_x - ev_x0))
{
lseek(fd,0x00,SEEK_SET);
DisplayBmpPic("4.bmp");
printf("下滑\n");
}
}
}
}
//3 关闭这个文件
close(fd);
}
int main()
{
//1 打开这个触摸屏
LcdInit();
//调用图片切换函数 在图片切换函数中嵌套音乐切换
Switching();
return 0;
}
代码解释:
ev_x0,ev_y0代表手挪动前的坐标,ev_x,ev_y;代表手挪动后的坐标。
点击:手挪动前后的坐标相同(ev_x0 == ev_x && ev_y0 == ev_y)左滑:手挪动后的x坐标小于手挪动前的x坐标,且x轴方向的坐标绝对值变化大于y轴方向的坐标值变化(ev_x < ev_x0 && abs(ev_x - ev_x0) > abs(ev_y - ev_y0)
右滑:手挪动后的x坐标大于手挪动前的x坐标,且x轴方向的坐标绝对值变化大于y轴方向的坐标值变化(ev_x > ev_x0 && abs(ev_x - ev_x0) > abs(ev_y - ev_y0)
上滑:手挪动后的y坐标大于手挪动前的y坐标,且x轴方向的坐标绝对值变化小于y轴方向的坐标值变化(ev_y > ev_y0 && abs(ev_y -ev_y0) > abs(ev_x - ev_x0)
下滑:手挪动后的y坐标小于手挪动前的y坐标,且x轴方向的坐标绝对值变化小于y轴方向的坐标值变化(ev_y < ev_y0 && abs(ev_y -ev_y0) > abs(ev_x - ev_x0)