原子学习笔记2——输入设备应用编程

news2024/11/17 7:16:24

一、输入类设备介绍

1、输入设备

常见的输入设备有鼠标、键盘、触摸屏、遥控器、电脑画图板等,用户通过输入设备与系统进行交互。

2、input子系统

常见的输入设备有鼠标、键盘、触摸屏、遥控器、电脑画图板等,用户通过输入设备与系统进行交互。
基于 input 子系统注册成功的输入设备,都会在/dev/input 目录下生成对应的设备节点(设备文件),设备节点名称通常为 eventX(X 表示一个数字编号 0、1、2、3 等),譬如/dev/input/even 、/dev/input/event1、/dev/input/event2等,通过读取这些设备节点可以获取输入设备上报的数据。

3、读取数据的流程

如果我们要读取触摸屏的数据,假设触摸屏设备对应的设备节点为/dev/input/event0,那么数据读取流程如下:
①、应用程序打开/dev/input/event0 设备文件;
②、应用程序发起读操作(譬如调用 read),如果没有数据可读则会进入休眠(阻塞 I/O 情况下);
③、当有数据可读时,应用程序会被唤醒,读操作获取到数据返回;
④、应用程序对读取到的数据进行解析。

4、解析数据

应用程序打开输入设备对应的设备文件,向其发起读操作,其实每一次 read 操作获取的都是一个 struct input_event 结构体类型数据,该结构体定义在<linux/input.h>头文件中,它的定义如下:

struct input_event {
 struct timeval time;
 __u16 type;
 __u16 code;
 __s32 value;
};
  • type:type 用于描述发生了哪一种类型的事件(对事件的分类)。点击鼠标按键(左键、右键,或鼠标上的其它按键)时会上报按键类事件,移动鼠标时则会上报相对位移类事件。
  • code:code 表示该类事件中的哪一个具体事件,以上列举的每一种事件类型中都包含了一系列具体事件,譬如一个键盘上通常有很多按键,譬如字母 A、B、C、D 或者数字 1、2、3、4 等,而 code变量则告知应用程序是哪一个按键发生了输入事件。
  • value:内核每次上报事件都会向应用层发送一个数据 value,对 value 值的解释随着 code 的变化而变化。譬如对于按键事件(type=1)来说,如果 code=2(键盘上的数字键 1,也就是KEY_1),那么如果 value 等于 1,则表示 KEY_1 键按下;value 等于 0 表示 KEY_1 键松开

二、按键应用编程

编写按键应用程序,读取按键状态并将结果打印出来。
如果是按下,则上报 KEY_A 事件时,value=1;如果是松开,则 value=0;如果是长按,则 value=2。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
int main(int argc, char *argv[])
{
    struct input_event in_ev = {0};
    int fd = -1;
    int value = -1;
    // /* 校验传参 
    if (2 != argc) {
        fprintf(stderr, "usage: %s <input-dev>\n", argv[0]);
        exit(-1);
    }
    /* 打开文件 */
    if (0 > (fd = open(argv[1], O_RDONLY))) {
        perror("open error");
        exit(-1);
    }
    for ( ; ; ) {
        // /* 循环读取数据 
        if (sizeof(struct input_event) !=
            read(fd, &in_ev, sizeof(struct input_event))) {
            perror("read error");
            exit(-1);
        }
        if (EV_KEY == in_ev.type) { //按键事件
            switch (in_ev.value) {
                case 0:
                    printf("code<%d>: 松开\n", in_ev.code);
                    break;
                case 1:
                    printf("code<%d>: 按下\n", in_ev.code);
                    break;
                case 2:
                    printf("code<%d>: 长按\n", in_ev.code);
                    break;
            }
        }
    }
}

在这里插入图片描述
可以看出开发板下的设备节点是event1,结果如下:
在这里插入图片描述

三、触摸屏应用编程

触摸屏分为多点触摸设备和单点触摸设备。单点触摸设备只支持单点触摸,一轮(笔者把一个同步事件称为一轮)完整的数据只包含一个触摸点信息;多点触摸设备,一轮完整的数据可能包含多个触摸点信息。

1、获取触摸屏信息

首先介绍ioctl()函数,ioctl()是一个文件 I/O 操作的杂物箱,可以处理的事情非常杂、不统一,一般用于操作特殊文件或设备文件。

#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);

第一个参数 fd 对应文件描述符;第二个参数 request 与具体要操作的对象有关,没有统一值,表示向文件描述符请求相应的操作,也就是请求指令;此函数是一个可变参函数,第三个参数需要根据 request 参数来决定,配合 request 来使用。
下面代码用于获取触摸屏支持的最大触摸点数:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
int main(int argc, char *argv[])
{
    struct input_absinfo info;
    int fd = -1;
    int max_slots;
    //  /* 校验传参 
    if (2 != argc) {
        fprintf(stderr, "usage: %s <input-dev>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    //  /* 打开文件 
    if (0 > (fd = open(argv[1], O_RDONLY))) {
        perror("open error");
        exit(EXIT_FAILURE);
    }
    //  /* 获取 slot 信息 
    if (0 > ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &info)) {
        perror("ioctl error");
        close(fd);
        exit(EXIT_FAILURE);
    }
    max_slots = info.maximum + 1 - info.minimum;
    printf("max_slots: %d\n", max_slots);
    //  /* 关闭、退出 
    close(fd);
    exit(EXIT_SUCCESS);
}

可以看到ioctl函数第二个参数

#define EVIOCGABS(abs)		_IOR('E', 0x40 + (abs), struct input_absinfo)

通过这个宏可以获取到触摸屏 slot(slot<0>表示触摸点 0、slot<1>表示触摸点 1、slot<2>表示触摸点 2,以此类推!)的取值范围,可以看到使用该宏需要传入一个 abs 参数,该参数表示为一个 ABS_XXX 绝对位移事件,譬如 EVIOCGABS(ABS_MT_SLOT)表示获取触摸屏的 slot 信息,此时 ioctl()函数的第三个参数是一个 struct input_absinfo *的指针,指向一个 struct input_absinfo 对象,调用 ioctl()会将获取到的信息写入到struct input_absinfo 对象中。struct input_absinfo 结构体如下所示:

struct input_absinfo {
 __s32 value; //最新的报告值
 __s32 minimum; //最小值
 __s32 maximum; //最大值
 __s32 fuzz;
 __s32 flat;
 __s32 resolution;
};

拷贝到开发板执行程序可以看到这个屏是这个屏是一个 5 点触摸屏
在这里插入图片描述

2、单点触摸屏应用编程

编写一个单点触摸应用程序,获取一个触摸点的坐标信息,并将其打印出来。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
int main(int argc, char *argv[])
{
    struct input_event in_ev;
    int x, y; //触摸点 x 和 y 坐标
    int down; //用于记录 BTN_TOUCH 事件的 value,1 表示按下,0 表示松开,-1 表示移动
    int valid; //用于记录数据是否有效(我们关注的信息发生更新表示有效,1 表示有效,0 表示无效)
    int fd = -1;
    // /* 校验传参 
    if (2 != argc) {
        fprintf(stderr, "usage: %s <input-dev>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    // /* 打开文件 
    if (0 > (fd = open(argv[1], O_RDONLY))) {
        perror("open error");
        exit(EXIT_FAILURE);
    }
    x = y = 0; //初始化 x 和 y 坐标值
    down = -1; //初始化<移动>
    valid = 0;//初始化<无效>
    for ( ; ; ) {
        // /* 循环读取数据 
        if (sizeof(struct input_event) !=
            read(fd, &in_ev, sizeof(struct input_event))) {
            perror("read error");
            exit(EXIT_FAILURE);
        }
        switch (in_ev.type) {
            case EV_KEY: //按键事件
                if (BTN_TOUCH == in_ev.code) {
                    down = in_ev.value;
                    valid = 1;
                }
                break;
            case EV_ABS: //绝对位移事件
                switch (in_ev.code) {
                    case ABS_X: //X 坐标
                        x = in_ev.value;
                        valid = 1;
                        break;
                    case ABS_Y: //Y 坐标
                        y = in_ev.value;
                        valid = 1;
                        break;
                }
                break;
            case EV_SYN: //同步事件
                if (SYN_REPORT == in_ev.code) {
                    if (valid) {//判断是否有效
                        switch (down) {//判断状态
                            case 1:
                                printf("按下(%d, %d)\n", x, y);
                                break;
                            case 0:
                                printf("松开\n");
                                break;
                            case -1:
                                printf("移动(%d, %d)\n", x, y);
                                break;
                        }
                        valid = 0; //重置 valid
                        down = -1; //重置 down
                    }
                }
            break;
        }
    }
}

观察几个宏定义,通过input_event结构体的type成员判断事件类型

#define EV_SYN 0x00 //同步类事件,用于同步事件
#define EV_KEY 0x01 //按键类事件
#define EV_ABS 0x03 //绝对位移类事件(譬如触摸屏)

再通过code成员判断是时间类型中的哪种具体事件

#define BTN_TOUCH		0x14a
#define ABS_X			0x00  //X坐标
#define ABS_Y			0x01  //Y坐标

最后是数据同步
同步事件用于实现同步操作、告知接收者本轮上报的数据已经完整。应用程序读取输入设备上报的数据时,一次 read 操作只能读取一个 struct input_event 类型数据,对于触摸屏来说,一个触摸点的信息包含了 X 坐标、Y 坐标以及其它信息,对于这样情况,应用程序需要执行多次 read 操作才能把一个触摸点的信息全部读取出来,这样才能得到触摸点的完整信息。所以使用for循环一直读结构体的值。
内核将本轮需要上报、发送给接收者的数据全部上报完毕后,接着会上报一个同步事件,以告知应用程序本轮数据已经完整、可以进行同步了。

#define SYN_REPORT		0     //同步事件

输入设备都需要上报同步事件,上报的同步事件通常是 SYN_REPORT,而 value 值通常为 0。
打印信息如下:
在这里插入图片描述

3、多点触摸屏应用编程

编写一个打印各个触摸点信息的程序:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
#include <linux/input.h>
/* 用于描述 MT 多点触摸每一个触摸点的信息 */
struct ts_mt {
    int x; //X 坐标
    int y; //Y 坐标
    int id; //对应 ABS_MT_TRACKING_ID
    int valid; //数据有效标志位(=1 表示触摸点信息发生更新)
};
/* 一个触摸点的 x 坐标和 y 坐标 */
struct tp_xy {
    int x;
    int y;
};
static int ts_read(const int fd, const int max_slots,struct ts_mt *mt)
{
    struct input_event in_ev;
    static int slot = 0;//用于保存上一个 slot
    static struct tp_xy xy[12] = {0};//用于保存上一次的 x 和 y 坐标值,假设触摸屏支持的最大触摸点数不会超过 12
    int i;
    /* 对缓冲区初始化操作 */
    memset(mt, 0x0, max_slots * sizeof(struct ts_mt)); //清零
    for (i = 0; i < max_slots; i++)
        mt[i].id = -2;//将 id 初始化为-2, id=-1 表示触摸点删除, id>=0 表示创建
    for ( ; ; ) {
        if (sizeof(struct input_event) !=
            read(fd, &in_ev, sizeof(struct input_event))) {
            perror("read error");
            return -1;
        }
        switch (in_ev.type) {
            case EV_ABS:
                switch (in_ev.code) {
                    case ABS_MT_SLOT:
                        slot = in_ev.value;
                        break;
                    case ABS_MT_POSITION_X:
                        xy[slot].x = in_ev.value;
                        mt[slot].valid = 1;
                        break;
                    case ABS_MT_POSITION_Y:
                        xy[slot].y = in_ev.value;
                        mt[slot].valid = 1;
                        break;
                    case ABS_MT_TRACKING_ID:
                        mt[slot].id = in_ev.value;
                        mt[slot].valid = 1;
                        break;
                }
                break;
            //case EV_KEY://按键事件对单点触摸应用比较有用
            // break;
            case EV_SYN:
                if (SYN_REPORT == in_ev.code) {
                    for (i = 0; i < max_slots; i++) {
                        mt[i].x = xy[i].x;
                        mt[i].y = xy[i].y;
                    }
                }
                return 0;
        }
    }
}
int main(int argc, char *argv[])
{
    struct input_absinfo slot;
    struct ts_mt *mt = NULL;
    int max_slots;
    int fd;
    int i;
    /* 参数校验 */
    if (2 != argc) {
        fprintf(stderr,"usage: %s <input_dev>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    /* 打开文件 */
    fd = open(argv[1], O_RDONLY);
    if (0 > fd) {
        perror("open error");
        exit(EXIT_FAILURE);
    }
    /* 获取触摸屏支持的最大触摸点数 */
    if (0 > ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &slot)) {
        perror("ioctl error");
        close(fd);
        exit(EXIT_FAILURE);
    }
    max_slots = slot.maximum + 1 - slot.minimum;
    printf("max_slots: %d\n", max_slots);
    /* 申请内存空间并清零 */
    mt = calloc(max_slots, sizeof(struct ts_mt));
    /* 读数据 */
    for ( ; ; ) {
        if (0 > ts_read(fd, max_slots, mt))
            break;
        for (i = 0; i < max_slots; i++) {
            if (mt[i].valid) {//判断每一个触摸点信息是否发生更新(关注的信息发生更新)
                if (0 <= mt[i].id)
                    printf("slot<%d>, 按下(%d, %d)\n", i, mt[i].x, mt[i].y);
                else if (-1 == mt[i].id)
                    printf("slot<%d>, 松开\n", i);
                else
                    printf("slot<%d>, 移动(%d, %d)\n", i, mt[i].x, mt[i].y);
            }
        }
    }
    /* 关闭设备、退出 */
    close(fd);
    free(mt);
    exit(EXIT_FAILURE);
}

可以看出程序先通过ioct()函数获取触摸屏支持的最大触摸点数,重点关注ts_read()函数,然后在for循环中打印出各个触摸点信息。
在 Linux 内核中,多点触摸设备使用多点触摸(MT)协议上报各个触摸点的数据,MT 协议分为两种类型:Type A 和 Type B,我们使用的是 Type B协议。
首先硬件能够为每一个识别到的触摸点与一个 slot 进行关联,这个 slot 就是一个编号,触摸点 0、触摸点 1、触摸点 2 等。底层驱动向应用层上报 ABS_MT_SLOT 事件,此事件会告诉接收者当前正在更新的是哪个触摸点的数据,ABS_MT_SLOT 事件中对应的 value 数据存放的便是一个 slot、以告知应用层当前正在更新 slot关联的触摸点对应的信息。
其次除了ABS_MT_SLOT 事 件 之 外 , Type B 协 议 还 会 使 用 到 ABS_MT_TRACTKING_ID 事 件 ,ABS_MT_TRACTKING_ID 事件则用于触摸点的创建、替换和销毁工作,ABS_MT_TRACTKING_ID 事件携带的数据 value 表示一个 ID,一个非负数的 ID(ID>=0)表示一个有效的触摸点,如果 ID 等于-1 表示该触摸点已经不存在、被移除了;一个以前不存在的 ID 表示这是一个新的触摸点。
然后得到X,Y的坐标值
最后进行数据同步
上报流程如下:

ABS_MT_SLOT 0
ABS_MT_TRACKING_ID 10
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 11
ABS_MT_POSITION_X
ABS_MT_POSITION_Y
SYN_REPORT

可以看出5个触摸点信息如下:
在这里插入图片描述

4、鼠标应用编程

与触摸屏类似

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

int main(int argc, char *argv[])
{
    struct input_event in_ev = {0};
    int x, y; //触摸点 x 和 y 坐标
    int down; //用于记录事件的 value,1 表示按下,0 表示松开,-1 表示移动
    int valid; //用于记录数据是否有效(我们关注的信息发生更新表示有效,1 表示有效,0 表示无效)
    int fd = -1;
    int value = -1;

    if(2 != argc){
        fprintf(stderr, "usage: %s <input-dev>\n", argv[0]);
        exit(-1);
    }

    if(0 > (fd = open(argv[1], O_RDONLY))){
        perror("open error");
        exit(-1);
    }
    x = y = 0; //初始化 x 和 y 坐标值
    down = -1; //初始化<移动>
    valid = 0;//初始化<无效>
    for( ; ;){
        if(sizeof(struct input_event) != 
            read(fd, &in_ev, sizeof(struct input_event))){
                perror("read error");
                exit(-1);
        }
        switch(in_ev.type){
            case EV_KEY:
                down = in_ev.value;
                valid = 1;
                break;
            case EV_REL://相对位移事件(鼠标)
                switch(in_ev.code){
                    case REL_X:
                        x = in_ev.value;
                        valid = 1;
                        break;
                    case REL_Y:
                        y = in_ev.value;
                        valid = 1;
                        break;
                }
                break;
            case EV_SYN:
                if(SYN_REPORT == in_ev.code){
                    if(valid){
                        switch(down){
                            case 1:
                                printf("按下\n");
                                break;
                            case 0:
                                printf("松开\n");
                                break;
                            case -1:
                                printf("移动(%d, %d)\n", x, y);
                                break;
                        }
                        valid = 0;
                        down = -1;
                    }
                }
                break;
        }
    }
}

结果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1323057.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker 在线安装redis

1、远程仓库拉取redis镜像&#xff0c; docker pull redis&#xff0c;默认拉取最新版本 2、在本地宿主机文件夹下创建相关目录文件&#xff0c;供容器卷使用&#xff0c;创建 /usr/local/data/redisdocker/data 文件夹&#xff0c;准备一个纯净版 redis.conf 配置文件 &#x…

【Linux】ip命令使用

ip命令 用于管理与配置网络接口和路由表。 ip命令的安装 ip 命令来自 iproute2 软件包&#xff0c;在 CentOS 7 中默认已安装。 yum install -y iproute 语法 ip [ OPTIONS ] OBJECT { COMMAND | help }ip [ -force ] -batch filename选项及作用 执行令 &#xff1a; ip …

el-form与el-upload结合上传带附件的表单数据(后端篇)

1.写在之前 本文采用Spring Boot MinIO MySQLMybatis Plus技术栈&#xff0c;参考ruoyi-vue-pro项目。 前端实现请看本篇文章el-form与el-upload结合上传带附件的表单数据&#xff08;前端篇&#xff09;-CSDN博客。 2.需求描述 在OA办公系统中&#xff0c;流程表单申请人…

【SQL】根据年月,查询月份中每一天的数据量

传入YYYY-MM-01&#xff0c;查询这个月中每一天的数据量&#xff0c;没有数据的天数用0表示 WITH RECURSIVE DateRange AS (SELECT :startDate AS DateUNION ALLSELECT DATE_ADD(Date, INTERVAL 1 DAY) FROM DateRangeWHERE Date < LAST_DAY(:startDate) ) SELECTdr.Date,CO…

从 MySQL 到 DolphinDB,Debezium + Kafka 数据同步实战

Debezium 是一个开源的分布式平台&#xff0c;用于实时捕获和发布数据库更改事件。它可以将关系型数据库&#xff08;如 MySQL、PostgreSQL、Oracle 等&#xff09;的变更事件转化为可观察的流数据&#xff0c;以供其他应用程序实时消费和处理。本文中我们将采用 Debezium 与 K…

单总线cpu设计(包含定长指令周期和变长指令周期和现代时序设计)

来都来了点个赞收藏一下再走呗~~~&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339; 一、定长指令周期cpu设计 第1关&#xff1a;MIPS指令译码器设计 此实验就是只需要知道mips知道操作码op对应的值是什么就可以了&#xff0c;下面给出实验中用到的mips指令…

大型语言模型:RoBERTa — 一种稳健优化的 BERT 方法

slavahead 一、介绍 BERT模型的出现BERT模型带来了NLP的重大进展。 BERT 的架构源自 Transformer&#xff0c;它在各种下游任务上取得了最先进的结果&#xff1a;语言建模、下一句预测、问答、NER标记等。 尽管 BERT 性能出色&#xff0c;研究人员仍在继续尝试其配置&#xff0…

JNDI注入Log4jFastJson白盒审计不回显处理

目录 0x00 前言 0x01 Maven 仓库及配置 0x02 JNDI 注入简介 0x03 Java-第三方组件-Log4J&JNDI 0x04 Java-第三方组件-FastJson&反射 0x05 白盒审计 - FastJson 0x06 白盒审计 - Log4j 0x07 不回显的处理方法 0x00 前言 希望和各位大佬一起学习&#xff0c;如果…

RK3399平台开发系列讲解(内核入门篇)网络协议的分层

🚀返回专栏总目录 文章目录 一、应用层二、传输层三、网络层四、数据链路层(Data Link Layer)五、物理层沉淀、分享、成长,让自己和他人都能有所收获!😄 📢对于多数的应用和用户而言,使用互联网的一个基本要求就是数据可以无损地到达。用户通过应用进行网络通信࿰

Android的组件、布局学习

介绍 公司组织架构调整&#xff0c;项目组需要承接其他项目组的android项目&#xff0c;负责维护和开发新需求&#xff0c;故学习下基础语法和项目开发。 组件学习 Toolbarheader布局部分 就是app最顶部的部分 他的显示与否&#xff0c;是与F:\androidProject\android_lear…

LVGL 显示图片

LVGL 显示图片 LVGL显示图片1. 显示图片文件2. 显示C数组格式3. 显示RAM中的图像文件4. 图像符号显示5. 显示GIF动画LVGL显示图片代码分析 LVGL显示图片 lvgl 8.3版本默认支持PNG,BMP,JPG,SJPG和GIF动图等格式的图片显示&#xff1b; 需要在lv_conf.h配置文件里使能对应图片的…

【网络安全】—Shell编程入门(1)

文章目录 基础变量概念介绍特殊变量进阶数值计算实践条件测试比较条件判断语句流程控制语句循环语句应用 Shell 是 Unix/Linux 操作系统下的一种命令行解释器&#xff0c;它接收用户输入的命令然后调用相应的程序。我们可以通过 Shell 脚本来自动执行一系列的命令。接下来&…

基于python的leetcode算法介绍之递归

文章目录 零 算法介绍一 简单示例 辗转相除法Leetcode例题与思路[509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/)解题思路&#xff1a;题解&#xff1a; [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/)解题思路&#xff1a;题解&…

最新AI创作系统ChatGPT系统源码+DALL-E3文生图+AI绘画+GPT语音对话功能

一、前言 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作Ch…

计算机网络 网络层下 | IPv6 路由选择协议,P多播,虚拟专用网络VPN,MPLS多协议标签

文章目录 5 IPv65.1 组成5.2 IPv6地址5.3 从IPv4向IPv6过渡5.3.1 双协议栈5.3.2 隧道技术 6 因特网的路由选择协议6.1 内部网关协议RIP6.2 内部网关协议 OSPF基本特点 6.3 外部网关协议 BGP6.3.1 路由选择 6.4 路由器组成6.4.1 基本了解6.4.2 结构 7 IP多播7.1 硬件多播7.2 IP多…

vp与vs联合开发-通过FrameGrabber连接相机

添加控件 1.CogRecordDisplay 控件 用于显示图像 初始化相机对象方法 //启动窗体时 调用初始化相机方法 //封装相机关闭方法 //窗体关闭时 调用相机关闭方法 拍照 设置采图事件 // 保存图像 设置曝光按钮事件 1.可变参数

C# pictureBox显示一张图片,我想先释放这个图片以免占用无法修改,(旋转)改完再显示这张图片

效果 public static bool RotateFlip(MyDel Log, string fileName){try{string tempPath Path.GetTempFileName();using (Bitmap bmp new Bitmap(fileName)){float resolution 600; //x,y必须为这个数 误差小于-1bmp.RotateFlip(RotateFlipType.Rotate90FlipNone);bmp.Save(…

智能优化算法应用:基于冠状病毒群体免疫算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于冠状病毒群体免疫算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于冠状病毒群体免疫算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.冠状病毒群体免疫算法4.…

飞天使-k8s-知识点1-kubernetes架构简述

文章目录 名词功能要点 k8s核心要素CNCF 云原生框架简介k8s组建介绍 名词 CI 持续集成, 自动化构建和测试&#xff1a;通过使用自动化构建工具和自动化测试套件&#xff0c;持续集成可以帮助开发人员自动构建和测试他们的代码。这样可以快速检测到潜在的问题&#xff0c;并及早…

C/C++编程中的算法实现技巧与案例分析

C/C编程语言因其高效、灵活和底层的特性&#xff0c;被广大开发者用于实现各种复杂算法。本文将通过10个具体的算法案例&#xff0c;详细探讨C/C在算法实现中的技巧和应用。 一、冒泡排序&#xff08;Bubble Sort&#xff09; 冒泡排序&#xff08;Bubble Sort&#xff09;是一…