当前位置: 首页 > news >正文

Linux驱动开发——(十一)INPUT子系统

目录

一、input子系统简介

二、input驱动API

2.1 input字符设备

2.2 input_dev结构体

2.3 上报输入事件

2.4 input_event结构体

三、代码

3.1 驱动代码

3.2 测试代码

四、平台测试


一、input子系统简介

input子系统是管理输入的子系统,和pinctrl、gpio子系统一样,都是Linux内核针对某一类设备而创建的框架。比如按键输入、键盘、鼠标、触摸屏等等这些都属于输入设备,不同的输入设备所代表的含义不同,按键和键盘就是代表按键信息,鼠标和触摸屏代表坐标信息,因此在应用层的处理就不同。

input子系统分为input驱动层input核心层input事件处理层,最终给用户空间提供可访问的设备节点:

最左边是最底层的具体设备,比如按键、USB键盘/鼠标等;中间部分是Linux内核空间,分为驱动层、核心层和事件层;最右边是用户空间,所有的输入设备以文件的形式供用户应用程序使用:

驱动层:输入设备的具体驱动程序,比如按键驱动程序,向内核层报告输入内容。

核心层:为驱动层提供输入设备注册和操作接口,通知事件层对输入事件进行处理。

事件层:主要和用户空间进行交互。


二、input驱动API

2.1 input字符设备

input核心层会向Linux内核注册一个字符设备——drivers/input/input.c即input输入子系统的核心层:

struct class input_class = { .name = "input", .devnode = input_devnode, 
};......static int __init input_init(void) 
{ int err;err = class_register(&input_class); if (err) { pr_err("unable to register input_dev class\n"); return err; } err = input_proc_init(); if (err) goto fail1; err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), INPUT_MAX_CHAR_DEVICES, "input"); if (err) { pr_err("unable to register char major %d", INPUT_MAJOR); goto fail2; } return 0;fail2: input_proc_exit(); fail1: class_unregister(&input_class); return err; 
}

其中,以下代码是注册一个input类:

err = class_register(&input_class);

这样系统启动以后就会在/sys/class目录下有一个input子目录:

其中,以下代码是注册一个字符设备:

err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), INPUT_MAX_CHAR_DEVICES, "input");

主设备号为INPUT_MAJOR INPUT_MAJOR定义在include/uapi/linux/major.h文件中:

#define INPUT_MAJOR 13

因此,input子系统的所有设备主设备号都为13。在使用input子系统处理输入设备时不需要注册字符设备只需要向系统注册一个input_device结构体即可。

2.2 input_dev结构体

input_dev结构体表示input设备,定义在include/linux/input.h文件中:

struct input_dev { const char *name; const char *phys; const char *uniq; struct input_id id; unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; /* 事件类型的位图 */ unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; /* 按键值的位图 */ unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; /* 相对坐标的位图 */ unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; /* 绝对坐标的位图 */ unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; /* 杂项事件的位图 */ unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; /*LED相关的位图 */ unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];/* sound有关的位图 */ unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; /* 压力反馈的位图 */ unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; /*开关状态的位图 */ ...... bool devres_managed; 
};

其中,evbit表示输入事件类型,可选的事件类型定义在include/uapi/linux/input.h文件中:

#define EV_SYN 0x00 /* 同步事件 */ 
#define EV_KEY 0x01 /* 按键事件 */ 
#define EV_REL 0x02 /* 相对坐标事件 */ 
#define EV_ABS 0x03 /* 绝对坐标事件 */ 
#define EV_MSC 0x04 /* 杂项(其他)事件 */ 
#define EV_SW 0x05 /* 开关事件 */ 
#define EV_LED 0x11 /* LED */ 
#define EV_SND 0x12 /* sound(声音) */ 
#define EV_REP 0x14 /* 重复事件 */ 
#define EV_FF 0x15 /* 压力事件 */ 
#define EV_PWR 0x16 /* 电源事件 */ 
#define EV_FF_STATUS 0x17 /* 压力状态事件 */

如果要使用按键,就要注册EV_KEY事件;如果要实现连按,还需要注册EV_REP事件。

其中,keybit表示按键事件使用的位图。Linux内核定义的keybit定义在include/uapi/linux/input.h文件中:

#define KEY_RESERVED 0 
#define KEY_ESC 1 
#define KEY_1 2 
#define KEY_2 3 
#define KEY_3 4 
#define KEY_4 5 
#define KEY_5 6 
#define KEY_6 7 
#define KEY_7 8 
#define KEY_8 9 
#define KEY_9 10 
#define KEY_0 11 ...... #define BTN_TRIGGER_HAPPY39 0x2e6 
#define BTN_TRIGGER_HAPPY40 0x2e7

编写input设备驱动则需要先申请一个input_dev结构体变量,使用input_allocate_device函数来申请一个input_dev:

struct input_dev *input_allocate_device(void)

返回值:要申请的input_dev。

如果要释放的input设备则需要使用input_free_device函数来释放掉申请到的input_dev:

void input_free_device(struct input_dev *dev) 

dev:要释放的input_dev。

返回值:无。

申请好input_dev后要初始化input_dev,需要初始化的内容主要为事件类型(evbit)事件值(keybit)。input_dev初始化好后则需要使用input_register_device函数向Linux内核注册input_dev

int input_register_device(struct input_dev *dev)

dev:要注册的input_dev。

返回值:0,input_dev注册成功;负值,input_dev注册失败。

如果要注销input设备则需要使用input_unregister_device函数来注销掉注册到的input_dev:

void input_unregister_device(struct input_dev *dev)

dev:要注销的input_dev 。

返回值:无。

综上,按键功能的input_dev注册流程如下:

struct input_dev *inputdev; /* input结构体变量 */ /* 驱动入口函数 */ 
static int __init xxx_init(void) 
{ ...... /* 初始化input_dev */inputdev = input_allocate_device(); /* 申请input_dev */ inputdev->name = "test_inputdev"; /* 设置input_dev名字 */ /* 第一种设置事件和事件值的方法 *///__set_bit(EV_KEY, inputdev->evbit);//__set_bit(EV_REP, inputdev->evbit);//__set_bit(KEY_0, inputdev->keybit);/* 第二种设置事件和事件值的方法 */ //keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); //keyinputdev.inputdev->keybit[BIT_WORD(KEY_0)] |= BIT_MASK(KEY_0); /* 第三种设置事件和事件值的方法 */ keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); input_set_capability(keyinputdev.inputdev, EV_KEY, KEY_0); /* 注册input_dev */ input_register_device(inputdev);...... return 0; 
}/* 驱动出口函数 */ 
static void __exit xxx_exit(void)
{ input_unregister_device(inputdev); /* 注销input_dev */ input_free_device(inputdev); /* 删除input_dev */ 
}

其中,input_set_capability函数表示设置输入设备可以上报的输入事件——该函数一次只能设置一个具体事件,如果设备可以上报多个事件,则需要重复调用该函数来进行设置:

input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code)

dev:该设备的input_dev结构体变量。

type设备可以上报的事件类型,即evbit的值

code设备可以上报的具体事件,本文即keybit的值。

2.3 上报输入事件

input设备都具有输入功能,但Linux内核并不知道具体的输入值。在向Linux内核注册好input_dev后还需要获取具体的输入值作为输入事件上报给Linux内核。

不同的事件,其上报事件的API函数不同。input_event函数用于上报指定的事件以及对应的值。此函数可以上报所有的事件类型和事件值:

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

dev:需要上报的input_dev。

type: 上报的事件类型,如EV_KEY、EV_SYN等等。

code:事件码,如EV_KEY事件中的KEY_0、KEY_1等等。

value:事件值。如EV_KEY事件中0表示按键松开,1表示按键按下,2表示按键连按。

返回值:无。

如果是上报按键事件,则可以使用input_report_key函数,此函数本质即input_event函数:

static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) 
{ input_event(dev, EV_KEY, code, !!value); 
}

还有一些其他的事件上报函数,如:

void input_report_rel(struct input_dev *dev, unsigned int code, int value)
void input_report_abs(struct input_dev *dev, unsigned int code, int value)
void input_report_ff_status(struct input_dev *dev, unsigned int code, int value) 
void input_report_switch(struct input_dev *dev, unsigned int code, int value) 
void input_mt_sync(struct input_dev *dev)

上报事件后还要使用input_sync函数告知Linux内核input子系统上报结束,该函数本质即上报一个同步事件

void input_sync(struct input_dev *dev) 

dev:需要上报同步事件的input_dev。

返回值:无。

综上,按键的上报事件代码流程如下:

unsigned char value; value = gpio_get_value(keydesc->gpio); /* 读取IO值 */ 
if(value == 0){ /* 按下按键 */ /* 上报按键值 */ input_report_key(inputdev, KEY_0, 1); /* 最后一个参数1,按下 */ input_sync(inputdev); /* 同步事件 */ 
} else { /* 按键松开 */ input_report_key(inputdev, KEY_0, 0); /* 最后一个参数0,松开 */ input_sync(inputdev); /* 同步事件 */ 
} 

2.4 input_event结构体

Linux内核使用input_event结构体(区别于上文的input_event函数!)表示所有的输入事件,定义在include/uapi/linux/input.h文件中:

struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; 
};

time:此事件发生时的时间,为timeval结构体类型:

typedef long __kernel_long_t; 
typedef __kernel_long_t __kernel_time_t; 
typedef __kernel_long_t __kernel_suseconds_t; struct timeval { __kernel_time_t tv_sec; /* 秒 */ __kernel_suseconds_t tv_usec; /* 微秒 */ 
};

type: 上报的事件类型,如EV_KEY、EV_SYN等等。

code:事件码。如EV_KEY事件中的KEY_0、KEY_1等等。

value:事件值。如EV_KEY事件中0表示按键松开,1表示按键按下,2表示按键连按。

所有的输入设备最终都按照input_event结构体呈现给用户,用户应用程序可以通过input_event结构体来获取到具体的输入事件或相关的值,比如按键值等。


三、代码

配合Linux驱动开发——(六)按键中断实验讲解。

3.1 驱动代码

在设备结构体里添加input结构体:

struct keyinput_dev{......struct input_dev *inputdev; /* input结构体 */
}

在定时器服务函数里更改按键按下和释放代码为:

if(value == 0){ /* 按下按键 */ /* 上报按键值 */ input_report_key(inputdev, KEY_0, 1); /* 最后一个参数1,按下 */ input_sync(inputdev); /* 同步事件 */ 
} else { /* 按键松开 */ input_report_key(inputdev, KEY_0, 0); /* 最后一个参数0,松开 */ input_sync(inputdev); /* 同步事件 */ 
} 

在按键初始化函数里添加:


/* 初始化input_dev */
inputdev = input_allocate_device(); /* 申请input_dev */ 
inputdev->name = "test_inputdev"; /* 设置input_dev名字 */ /* 设置事件和事件值 */ 
keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); 
input_set_capability(keyinputdev.inputdev, EV_KEY, KEY_0); /* 注册输入设备 */
ret = input_register_device(keyinputdev.inputdev); 
if (ret) { printk("register input device failed!\r\n"); return ret; 
}return 0; 

在驱动出口函数里添加:

/* 释放input_dev */ 
input_unregister_device(keyinputdev.inputdev); 
input_free_device(keyinputdev.inputdev);

3.2 测试代码

定义一个input_event变量,存放输入事件信息:

static struct input_event inputevent;

更改主函数中while函数的代码为:

while (1) { err = read(fd, &inputevent, sizeof(inputevent)); if (err > 0) { /* 读取数据成功 */ switch (inputevent.type) { case EV_KEY: if (inputevent.code < BTN_MISC) { /* 键盘键值 */ printf("key %d %s\r\n", inputevent.code,inputevent.value ? "press" : "release"); } else { printf("button %d %s\r\n", inputevent.code, inputevent.value ? "press" : "release"); } break; /* 其他类型的事件,自行处理 */ case EV_REL: break; case EV_ABS: break; case EV_MSC: break; case EV_SW: break; } } else { printf("读取数据失败\r\n"); } 
} 

向Linux内核成功注册input_dev设备后,会在/dev/input目录下生成一个名为“ eventX(X=0….n)”的文件(对应的input设备文件)。使用read函数读取该输入设备文件,读取到的数据(如按键值等等)按照input_event结构体组织起来。获取到输入事件以后(input_event结构体类型)再使用 switch case语句来判断事件类型。


四、平台测试

在加载该驱动模块之前,/dev/input目录下只有以下两个文件: 

 加载该驱动模块后,/dev/input目录下有以下三个文件:

因此/dev/input/event1即注册的驱动所对应的设备文件。使用测试代码读取/dev/input/event1该文件,然后按下按键,查看获取的输入事件信息:

也可以使用hexdump命令来直接查看/dev/input/event1(input_event结构体类型)原始事件数据值:

原始事件数据值的含义如下:

编号tv_sectv_usectypecodevalue
000000052f7 0000be6b 00010001000b0001 0000
000001052f7 0000be6b 0001000000000000 0000
000002052f7 0000451d 00030001000b0000 0000
000003052f7 0000451d 0003000000000000 0000

相关文章:

Linux驱动开发——(十一)INPUT子系统

目录 一、input子系统简介 二、input驱动API 2.1 input字符设备 2.2 input_dev结构体 2.3 上报输入事件 2.4 input_event结构体 三、代码 3.1 驱动代码 3.2 测试代码 四、平台测试 一、input子系统简介 input子系统是管理输入的子系统&#xff0c;和pinctrl、gpio子…...

大数据毕业设计Python+Django旅游景点评论数据采集分析可视化系统 NLP情感分析 LDA主题分析 bayes分类 旅游爬虫 旅游景点评论爬虫 机器学习 深度学习 人工智能 计算机毕业设计

毕业论文&#xff08;设计&#xff09;开题报告 学生姓名 学 号 所在学院 信息工程学院 专 业 指导教师姓名 指导教师职称 工程师 助教 指导教师单位 论文&#xff08;设计&#xff09;题目 基于朴素贝叶斯算法旅游景点线上评价情感分析 开 题 报 告…...

FSNotes for Mac v6.7.1中文激活版:强大的笔记管理工具

FSNotes for Mac是一款功能强大的文本处理与笔记管理工具&#xff0c;为Mac用户提供了一个直观、高效的笔记记录和整理平台。 FSNotes for Mac v6.7.1中文激活版下载 FSNotes支持Markdown语法&#xff0c;使用户能够轻松设置笔记格式并添加链接、图像等元素&#xff0c;实现笔记…...

课程34:Windows Docker部署.Net Core项目

这里写目录标题 🚀前言一、安装Docker Desktop1.1 官网下载Docker1.2 安装Docker1.2.1 选择配置,默认都勾选1.2.2 安装中1.2.3 安装成功1.2.4 启动1.2.5 启动成功二、.Net Core 项目发布与部署2.1 修改Dockerfile文件2.2 Web项目发布2.3 修改配置2.3.1 修改dockerfile<...

分布式与一致性协议之ZAB协议(四)

ZAB协议 ZooKeeper是如何选举领导者的。 首先我们来看看ZooKeeper是如何实现成员身份的&#xff1f; 在ZooKeeper中&#xff0c;成员状态是在QuorumPeer.java中实现的&#xff0c;为枚举型变量 public enum ServerState { LOOKING, FOLLOWING, LEADING, OBSERVING }其实&…...

在M1芯片安装鸿蒙闪退解决方法

在M1芯片安装鸿蒙闪退解决方法 前言下载鸿蒙系统安装完成后&#xff0c;在M1 Macos14上打开闪退解决办法接下来就是按照提示一步一步安装。 前言 重新安装macos系统后&#xff0c;再次下载鸿蒙开发软件&#xff0c;竟然发现打不开。 下载鸿蒙系统 下载地址&#xff1a;http…...

Linux基础-socket详解、TCP/UDP

文章目录 一、Socket 介绍二、Socket 通信模型三、Socket 常用函数1 创建套接字2 绑定套接字3、监听连接4、接受连接5、接收和发送数据接收数据发送数据 6、关闭套接字 四、Socket编程试验1、源码server.cclient.c 2、编译&#xff1a;3、执行结果 五、补充TCP和UDP协议的Socke…...

【菜单下拉效果】基于jquery实现二级菜单下拉效果(附完整源码下载)

Js菜单下拉特效目录 &#x1f354;涉及知识&#x1f964;写在前面实现效果&#x1f367;一、涉及知识&#x1f333;二、具体实现2.1 搭建一级菜单2.2 搭建二级菜单项2.3 引入js文件2.4 构建CSS文件 &#x1f40b;三、源码获取&#x1f305; 作者寄语 &#x1f354;涉及知识 ht…...

如何使用resource-counter统计跨Amazon区域的不同类型资源数量

关于resource-counter resource-counter是一款功能强大的命令行工具&#xff0c;该工具基于纯Python 3开发&#xff0c;可以帮助广大研究人员跨Amazon区域统计不同类型资源的数量。 该工具在统计完不同区域的各类资源数量后&#xff0c;可以在命令行中输出并显示统计结果。res…...

nextTick的作用与原理

在 Vue 中&#xff0c;nextTick允许我们延迟执行一段代码&#xff0c;直到 Vue完成其当前的 DOM 更新周期。这使得我们可以在 DOM 更新后安全地访问和修改 DOM 元素。 一、Vue 的异步更新策略 Vue 采用了一种称为异步更新策略的机制。这意味着当数据发生变化时&#xff0c;Vue…...

mybatis工程需要的pom.xml,以及@Data 、@BeforeEach、@AfterEach 的使用,简化mybatis

对 “mybatis - XxxMapper.java接口中方法的参数 和 返回值类型&#xff0c;怎样在 XxxMapper.xml 中配置的问题” 这篇文章做一下优化 这个pom.xml文件&#xff0c;就是上面说的这篇文章的父工程的pom.xml&#xff0c;即&#xff1a;下面这个pom.xml 是可以拿来就用的 <?…...

微信小程序demo-----制作文章专栏

前言&#xff1a;不管我们要做什么种类的小程序都涉及到宣传或者扩展其他业务&#xff0c;我们就可以制作一个文章专栏的页面&#xff0c;实现点击一个专栏跳转到相应的页面&#xff0c;页面可以有科普类的知识或者其他&#xff0c;然后页面下方可以自由发挥&#xff0c;添加联…...

Linux migrate_type初步探索

1、基础知识 我们都知道Linux内存组织管理结构架构&#xff0c;顶层是struct pglist_data&#xff0c;然后再到struct zone&#xff0c;最后是struct page。大概的管理结构是这样的&#xff1a; 根据物理内存的地址范围可划分不同的zone&#xff0c;每个zone里的内存由buddy…...

i.MX 6ULL 裸机 IAR 环境安装

一. IAR 的安装请自行搜索 二. 使用最新版本的 IAR&#xff0c;需要修改 SDK 1. 在 SDK 的 core_ca7.h 加上 #include "intrinsics.h" /* IAR Intrinsics */ 2. debug 时需要修改每个工程下的 ddr_init.jlinkscript&#xff0c;参考链接 Solved: How to conn…...

cmake进阶:文件操作

一. 简介 前面几篇文章学习了 cmake的文件操作&#xff0c;写文件&#xff0c;读文件。文章如下&#xff1a; cmake进阶&#xff1a;文件操作之写文件-CSDN博客 cmake进阶&#xff1a;文件操作之读文件-CSDN博客 本文继续学习文件操作。主要学习 文件重命名&#xff0c;删…...

在UI界面中播放视频_unity基础开发教程

在UI界面中播放视频_unity基础开发教程 前言操作步骤结语 前言 之前我写过一篇在场景中播放视频的文章&#xff0c;但是在开发中有时候也会在UI的界面中播放视频&#xff0c;这期我们做一下在UI的界面中播放视频。 操作步骤 首先在场景中创建一个Raw Image&#xff0c;UI->…...

TypeScipt 联合类型 | 号的使用

联合类型有两种使用方法&#xff1a; 一种类型中多个可能的值。具有多种不同的类型中的一种。 一种类型中多个可能的值。 type isAye true | false;const aye:isAye true; const aye1:isAye false; const aye2:isAye 3; // Type number is not assignable to type isAye…...

MATLAB 变换

MATLAB 变换&#xff08;Transforms&#xff09; MATLAB提供了用于处理诸如Laplace和Fourier变换之类的变换的命令。转换在科学和工程中用作简化分析和从另一个角度查看数据的工具。 例如&#xff0c;傅立叶变换允许我们将表示为时间函数的信号转换为频率函数。拉普拉斯变换使…...

【005_音频开发_基础篇_ALSA_Codec_驱动-MA120x0P功放】

005_音频开发_基础篇_ALSA_Codec_驱动-MA120x0P功放 文章目录 005_音频开发_基础篇_ALSA_Codec_驱动-MA120x0P功放创作背景MA120X0P输出模式BTLSEPBTLSEBTL 硬件配置方式/硬件Limiter限幅器限幅器作用过程 主要寄存器操作指令 ma120x0p.cma120x0p.h 创作背景 学历代表过去、能…...

2、​​​​​​​FreeCAD模块与核心架构总结

FreeCAD作为一个开源的3D建模软件&#xff0c;其内部架构由多个模块组成&#xff0c;这些模块共同协作以支持软件的各种功能。本总结将基于提供的参考文档&#xff0c;对FreeCAD的核心模块、架构特性以及启动过程进行翻译和详细阐述。 核心模块概览 FreeCAD的核心模块主要包括…...

MySQL为什么默认引擎是InnoDB?

因为InnoDB特别强大,其支持很多东西 1.支持事务: 意味着对于一个复杂的SQL语句要么全部执行成功,要么全部失败,因为其底层是原子性的 2.支持并发(行级并发) 意味着面对高并发,多个用户可以同时访问一个表的不同行,不同行之间上锁,而不是给一个表上锁,这样就提高了高并发的性能和…...

K8s: Helm搭建mongodb集群(1)

mongodb 集群搭建 mongdb 部署前 需要创建 pvc, pv 和 sc&#xff0c;如果在云上会自动创建helm 应用中心: https://artifacthub.io 1 &#xff09;Helm 安装 mongodb A. 无本地存储配置&#xff0c;重启数据消失 在 https://artifacthub.io/packages/helm/bitnami/mongodb…...

应用分层和企业规范

目录 一、应用分层 1、介绍 &#xff08;1&#xff09;为什么需要应用分层&#xff1f; &#xff08;2&#xff09;如何分层&#xff1f;&#xff08;三层架构&#xff09; MVC 和 三层架构的区别和联系 高内聚&#xff1a; 低耦合&#xff1a; 2、代码重构 controlle…...

Flutter笔记:Widgets Easier组件库(1)使用各式边框

Flutter笔记 Widgets Easier组件库&#xff08;1&#xff09;&#xff1a;使用边框 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress o…...

OpenHarmony实战开发-上传文件

Web组件支持前端页面选择文件上传功能&#xff0c;应用开发者可以使用onShowFileSelector()接口来处理前端页面文件上传的请求。 下面的示例中&#xff0c;当用户在前端页面点击文件上传按钮&#xff0c;应用侧在onShowFileSelector()接口中收到文件上传请求&#xff0c;在此接…...

外贸企业邮箱是什么?做外贸企业邮箱哪个好?

外贸企业邮箱是什么&#xff1f;外贸企业在进行跨国沟通时必不可少的工具就是外贸企业邮箱&#xff0c;外贸企业邮箱需要具备的条件就是海外邮件抵达率高、安全稳定、多语言沟通。而我们又怎么选择一个适合的外贸企业邮箱呢&#xff1f;小编今天带您一起了解。 一、外贸企业邮…...

写一个简单的程序

思路分析&#xff1a; 1. 导入必要的库 首先&#xff0c;确保你的项目中包含了AWT或Swing库&#xff0c;因为我们将使用它们来创建图形界面。 import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import j…...

CentOS安装Docker指南

Docker安装与配置教程 Docker作为一种轻量级的虚拟化技术&#xff0c;在现代软件开发和运维中扮演着重要的角色。下面&#xff0c;我将以技术博主的身份&#xff0c;向大家详细介绍如何在Linux系统上安装和配置Docker&#xff0c;特别是如何设置Docker的监听地址和端口&#x…...

python绘图(pandas)

matplotlib绘图 import pandas as pd abs_path rF:\Python\learn\python附件\pythonCsv\data.csv df pd.read_csv(abs_path, encodinggbk) # apply根据多列生成新的一个列的操作&#xff0c;用apply df[new_score] df.apply(lambda x : x.数学 x.语文, axis1)# 最后几行 …...

Android(Java)项目支持Kotlin语言开发

Android&#xff08;Java&#xff09;项目通过相关Kotlin设置后&#xff0c;允许同时使用Java语言和Kotlin语言进行开发代码的。 示例环境&#xff1a; Android Studio Giraffe | 2022.3.1 Patch 3 Java 8 Kotlin 1.9.20 设置Kotlin选项&#xff1a; 第一步&#xff1a;在项…...

网站里的横幅怎么做/百度竞价外包

Img格式文件可以使用ArcGis或者envi软件打开&#xff0c;这里介绍envi软件的安装过程。 1. 安装环境 操作系统&#xff1a;win10 软件版本&#xff1a;5.1 软件下载地址&#xff1a; 2. 安装步骤 进入软件安装包路径&#xff1b;2. 双击IDL83ENVI51win64.exe开始安装&…...

怀化二手车网站/黑马培训价目表

2019独角兽企业重金招聘Python工程师标准>>> New XAMPP security concept: Access to the requested directory is only available from the local network. This setting can be configured in the file “httpd-xampp.conf”. 解决办法&#xff1a; 打开httpd-xam…...

北京企业网站排名优化/企业网络营销方案

一般插件够用没有bug的话&#xff0c;我们就不需要他提示更新&#xff0c;不然天天wp后台冒红点&#xff0c;看着难受&#xff0c;就随便找了一下禁用更新的过滤器&#xff0c;整理一下&#xff0c;避免用的时候又找不到了&#xff01; // 彻底关闭自动更新add_filter(automat…...

网站建设企业关键词/推广吧

hexdump 语法SYNOPSIS hexdump [options] file [...]-n length (Interpret only length bytes of input.) -s offset Skip offset bytes from the beginning of the input. -x 两字节的十六进制显示 # 查看整个文件 hexdump mapper2# 查看前100个字节 hexdump mapper2 -n 100…...

专门做衣服的网站/免费建站网站一站式

/*** 存储文件 * param collectionName 集合名 * param file 文件 * param fileid 文件id * param companyid 文件的公司id * param filename 文件名称*/public void SaveFile(String collectionName, File file, String fileid, String companyid, String filename) {try {DB …...

聊城做wap网站公司/百度导航2023年最新版

2020-11-14牛客小白月赛29-D [by_041] 本人原文 看题&#xff0c;分析&#xff0c;大剪刀就是用来搬运大数的&#xff0c;多大呢&#xff1f;在(0m1)/2层内最大的那么答案就很明显了&#xff0c;(m1)/2内的深度返回大值&#xff0c;其余返回小值附上代码 #include<iostr…...