转自:http://www.cnblogs.com/leaven/archive/2011/02/12/1952793.html
include/linux/input.h
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGREP _IOR('E', 0x03, int[2]) /* get repeat settings */
#define EVIOCSREP _IOW('E', 0x03, int[2]) /* set repeat settings */
#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */
#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */
#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */
#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */
#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */
#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */
#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */
#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */
#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */
#define
EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect))
/* send a force effect to a force feedback device */
#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */
#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */
#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */
原文:http://www.linuxjournal.com/article/6429
尽管原文写于2003,仍有参考价值。
<!-- @page { margin: 0.79in } P { margin-bottom:
0.08in } H4 { margin-bottom: 0.08in } PRE.cjk { font-family: "DejaVu
Sans", monospace } TD P { margin-bottom: 0in } -->
The Linux USB Input Subsystem
Part 1
Linux USB输入子系统是一种简单的协调的管理所有输入设备的方式。
本文讨论 4部分内容:输入子系统的描述;内核中输入子系统的实现;输入子系统的用户空间 API;在你的程序中如何使用它。
什么是输入子系统 ?
输入子系统是 Linux内核用于管理各种输入设备 (键盘,鼠标,遥控杆,书写板等等 )的部分,用户通过输入子系统进行内核,命令行,图形接口之间的交换。输入子系统在内核里实现,因为设备经常要通过特定的硬件接口被访问 (例如串口, ps/2, usb等等 ),这些硬件接口由内核保护和管理。内核给用户导出一套固定的硬件无关的 input API,供用户空间程序使用。
理解内核内部实现
输入子系统分为三块: input core, drivers和 event handlers。他们之间的关系如图 1所示。正常的路径是从底层硬件到驱动,从驱动到 input core,从 input core到 event handler,从 event handler到 user space。此外,还存在一个返回路径 (return path)。返回路径允许给一个键盘设置 LED,给一个 force feedback joystick提供 motion commands。路径的两个方向(指从内核到用户的方向和从用户到内核的方向)使用相同的 event定义和不同的 type identifier。
这三个核心模块之间的交互主要通过 events数据结构来实现, events的数据结构定义如下:
Listing 1. event-dev-struct.txtstruct input_dev { void *private; char *name; |
type域显示了被报告事件的类型,例如,一个 key press或者 button press, relative motion(比如移动鼠标 )或者 absolute motion(比如移动游戏杆 ); code域告诉你是哪一个 key或者坐标轴在被操作; value域告诉你现在的状态或者运动情况是什么。
例如,如果 type域是一个 key, code域告诉你是哪一个 key, value域告诉你该 key是被按下还是抬起。类似的,如果 type域是一个相对坐标轴, code域告诉你是哪一个坐标轴, value域告诉你移动的距离以及相对坐标轴的方向。
如果你以对角线的方向移动鼠标,同时移动滚轮,你将获得三个相对事件:垂直轴上的运动事件 (x-axis),水平轴上的运动事件 (y-axis),滚轮的运动事件。
Event handlers给用户空间提供接口,将标准事件格式转换为特定 API所需要的格式。 Handlers也通常负责设备节点 (/dev entries)。最常见的 handler是 keyboard handler,它是大多数 C程序员熟悉的” standard input”。
驱动通常提供底层硬件的接口,例如 USB, PCI memory或者 I/O regions,或者 serial port I/O regions。
在发送给 input core之前,驱动将用户接口的底层硬件形式转换为标准的事件格式。 Input core使用标准的内核 plugin design:使用 input_register_device()来添加设备,使用 input_unregister_device()来删除设备。这些调用的参数是 struct input_device, 如 listing-1所描述。尽管这个数据结构看起来很大,但是绝大多数的域被提供,用于保证驱动可以规定一个设备的能力,例如哪种事件类型,设备接受或者发送的 codes。
除了管理驱动和 handlers, input core也导出了一些有用的 /proc文件系统接口,用于查看当前活动的设备和事件 handlers。下面是查看 usb鼠标的例子 (cat /proc/bus/input/devices):
I: Bus=0003 Vendor=046d Product=c002 Version=0120 |
I line:这行包含身份信息,显示了 bus type是 3 (usb), vendor, product, version等来来自 usb descriptoer关于鼠标的厂商信息。
N line:这行包含了名字信息。
P line:这行包含了物理设备信息。上述例子包含了 usb controller的 pci address, usb tree以及 input interface。
H line: 这行包含了与设备关联的 handler drivers。
B line: 这些行包含了显示设备能力的一些位域 (bitfield)。
Listing 2. register.c#include <linux/input.h> |
/proc接口是一种简单使用的方法来测试一些简单的驱动。考虑如下 listing 2的一个驱动例子,在 init()里注册,在 removal()里注销。该驱动示例使用 init_input_dev()来做一些初步的初始化工作:设置名字,物理描述符,身份描述符;然后设置 bit arrays来指定设备提供的事件类型是 EV_KEY,两个可能的 codes是 KEY_A, KEY_B。初始化代码然后将设备注册到 input core。如果你将这个示例代码 modprobe到内核,你会从 /proc/bus/input/devices里看到如下信息:
I: Bus=0019 Vendor=0001 Product=0001 Version=0100 |
如果我想从设备驱动发送事件到 input core,我们需要调用 input_event()或者更便利的封装函数,例如 input_report_key()/input_report_abs(),在 include/linux/input.h里定义。示例 listing 3使用了这些函数。
这个示例与 listing 2示例基本相同,但是增加了一个 timer,调用 ex2_timeout()。这个新函数发送了 4次 KEY_A press和 4次 KEY_B press。注意这总共会产生 16次 press 事件,这是因为每次 event由一次按键或一次释放键产生。这些事件传递给 input core,然后传递给 keyboard handler,产生” aaaabbbb”或者” AAAABBBB”,依赖于 shift键是否被选择。 timer在 4秒后被设置循环运行, 4秒的时间确保你有最够的时间移除模块当你认为打印了足够的测试信息。同样注意需要调用 input_sync()函数。该函数用于通知 event handler (这里是 keyboard handler)设备已经传递完一组完整的数据。在 input_sync()函数被调用之前,
handler可能缓存 events。
Listing 3. aaaabbbb.cstruct input_dev ex2_dev; void ex2_timeout(unsigned long unused/*UNUSED*/) |
让我们来看最后一个驱动例子,显示相对信息如何提供,如 listing 4所示。这个驱动例子模仿了一个鼠标。初始化代码配置设备有两个坐标轴 (REL_X和 REL_Y)和一个 key(BTN_LEFT)。我们使用一个 timer来运行 ex3_timeout。这个 timer调用 input_report_rel来提供相对运动 (5个单步 ---相对运动是函数的的 3个参数 ),包含 30步向右, 30 步向下, 30步向左, 30步向上,因此光标构成了一个正方形。为了提供运动动画,
timeout是 20毫秒。再次强调的是, input_sync()是保证事件 handler处理一个完整的事件数据的,你需要调用 input_sync()来确保你的数据已经完整的传递给 input core。如果你向对角线移动,你需要这样做:
... |
这样确保了鼠标对角线移动,而不是现横向移动,后竖向移动。
Listing 4. squares.cvoid ex3_timeout(unsigned long unused /*UNUSED*/) |
Handlers---到达用户空间
我们看到设备驱动位于硬件设备和 input core之间,将硬件事件(通常是中断)翻译成 input events。为了使用 input events,我们使用 handlers,它提供了用户空间的接口。
input子系统包含了你需要的大多数 handlers:一个提供 console的 keyboard handler;一个供应用程序使用的 mouse handler;一个 joystick handler以及一个 touchscreen handler。同样有一个通用的 event handler,向用户空间提供 basic input events。这意味着你不需要在内核里再写一个 handler,因为你可以在用户空间通过访问 event handler完成你需要的功能。
<!-- @page { size: 8.5in 11in; margin: 0.79in } P { margin-bottom: 0.08in } H4 { margin-bottom: 0.08in } TD P { margin-bottom: 0in } -->
Using the Input Subsystem
part 2
Linux input子系统一个很重要的特性是它提供了 event interface。它通过字符设备节点对用户空间导出了原生 event,允许用户程序操作任何 event,不会遗失任何信息。
查找 event interface版本
使用 EVIOCGVERSION ioctl function。参数是 32位 int类型,代表 major version (two high bytes), minor version (third byte), patch level (low byte)。 Listing 1显示了使用 EVIOCGVERSION的例子:第 1个参数是 event device node的打开文件描述符。你需要传递一个指向 int数据的一个指针作为第 3个参数。
Listing 1. Sample EVIOCGVERSION Function/* ioctl() accesses the underlying driver */ |
查找设备身份信息
event interface支持获取设备的身份信息,使用 EVIOCGID ioctl function。参数是指向 input_id数据结构的指针。 input_id数据结构定义如 listing 2所示。 _u16数据类型是 16为无符号整型。
Figure 2. input_id Structure Definitionsstruct input_id { |
bustype 域包含了你需要的准确的数据信息。你应把它当作是一个非透明的枚举类型,需要与通过 <linux/input.h>里定义的 BUG_x 类型比较获知。 vendor/product/version是与 bus type相关的表示设备身份信息的域。现代设备(如 USB, PCI)都使用了这些域,但是传统的设备( serial mice, ps/2 keyboard, ISA sound card)没有这些域。 EVIOCGID的使用如 listing 3所示。这个例子调用了 ioctl并打印了结果。
Listing 3. Sample EVIOCGID ioctl/* suck out some device information */ |
除了 bus type/vendor/product/version等设备信息,某些设备还会提供一个有意义的名字字符串,使用 EVIOCGNAME获取。如果名字串太长,则在返回的参数里被截取。 Listing 4显示了它的使用的例子。
Listing 4. Example Truncated Stringint fd = -1; |
下面是上述例子运行的结果样例:
The device on /dev/input/event0 says its name is Logitech USB-PS/2 Optical Mouse
尽管设备身份信息和名字信息通常很有用,但是它也许并没有提供足够的信息告诉你当前在使用哪个设备。例如,你当前有两个完全相同的遥控杆,你需要确定每个使用哪个端口。这通常属于拓扑信息( topology information),可以使用 EVIOCGPHYS ioctl获取。它返回一串字符串(或者一个负值错误码)。 Listing 5显示了它的使用的例子。
Listing 5. Using EVIOCGPHYS for Topology Informationif(ioctl(fd, EVIOCGPHYS(sizeof(phys)), phys) < 0) { |
它的运行结果样例如下所示:
The device on /dev/input/event0 says its path is usb-00:01.2-2.1/input0
为了了解输出的含义,你需要将其分成几部分。 Usb部分意味着这使用 usb系统的一个物理拓扑。 00:01.2是 usb host controller所在的 pci bus information (bus 0, slot 1, function 2)。 2.1表示了从 root hub到 device的路径,这里表示上行 hub接在 root hub的第 2个端口上,设备接在上行 hub的第 1个端口上。 Input0表示这是设备的第 1个 event device 节点。大部分设备只有一个 event device节点,但是有些设备例外。比如多媒体键盘,它有一个 event device节点用于 normal keyboard,另一个 event device节点用于 multimedia keyboard。拓扑示例如下图表示。
如果你在同一根连接线上将一个设备还成另外一个同样的设备,你无法区分设备更换,除非每一个设备有一个唯一号,比如 serial number。使用 EVIOCGUNIQ可以获取。 Listing 6是其示例。绝大多数设备没有这样的唯一号,所以你使用该 ioctl将返回一个空字符串。
Listing 6. Finding a Unique Identifierif(ioctl(fd, EVIOCGUNIQ(sizeof(uniq)), uniq) < 0) { |
确定设备能力和特性
对于一些设备,也许知道设备的身份信息就足够了,因为它允许你根据设备的使用情况处理设备的任何 case。但是这总做法的尺度不好。比如,你有一个设备仅有一个滑轮,你想使能处理滑轮的 handler,但是你并不想在 code里列出每个带有滑轮的鼠标的 vendor/product信息。为此, event interface允许你对于某个设备确定有哪些功能和特性。 Event interface支持的 feature types有:
EV_KEY: absolute binary results, such as keys and buttons.
EV_REL: relative results, such as the axes on a mouse.
EV_ABS: absolute integer results, such as the axes on a joystick or for a tablet.
EV_MSC: miscellaneous uses that didn't fit anywhere else.
EV_LED: LEDs and similar indications.
EV_SND: sound output, such as buzzers.
EV_REP: enables autorepeat of keys in the input core.
EV_FF: sends force-feedback effects to a device.
EV_FF_STATUS: device reporting of force-feedback effects back to the host.
EV_PWR: power management events
这些仅仅是 type features。每个 type feature包含了很大范围的不同的个体 feature。例如, EV_REL type区别了 x轴, y轴, z轴,横轮,竖轮。同样, EV_KEY type包含了成千上百个 keys和 buttons。
使用 EVIOCGBIT ioctl可以获取设备的能力和特性。它告知你设备是否有 key或者 button。
EVIOCGBIT ioctl处理 4个参数 ( ioctl(fd, EVIOCGBIT(ev_type, max_bytes), bitfield))。 ev_type是返回的 type feature( 0是个特殊 case,表示返回设备支持的所有的 type features)。 max_bytes表示返回的最大字节数。 bitfield域是指向保存结果的内存指针。 return value表示保存结果的实际字节数,如果调用失败,则返回负值。 Listing 7展现了其使用示例,测试了 /dev/input/event0设备节点支持哪些 type feature。
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <linux/input.h> #define BITS_PER_LONG 32 #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) static int test_bit(int nr, const volatile unsigned long *addr) { return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); } int main(int argc, char ** argv) { int fd; unsigned long *evtype_b = malloc(sizeof(int)); int yalv; if ((fd = open(argv[1], O_RDONLY)) < 0) { perror("evdev open"); exit(1); } memset(evtype_b, 0, sizeof(evtype_b)); if (ioctl(fd, EVIOCGBIT(0, EV_MAX), evtype_b) < 0) { perror("evdev ioctl"); } printf("Supported event types:\n"); for (yalv = 0; yalv < EV_MAX; yalv++) { if (test_bit(yalv, evtype_b)) { /* the bit is set in the event types list */ printf(" Event type 0x%02x ", yalv); switch ( yalv) { case EV_SYN : printf(" (Synch Events)\n"); break; case EV_KEY : printf(" (Keys or Buttons)\n"); break; case EV_REL : printf(" (Relative Axes)\n"); break; case EV_ABS : printf(" (Absolute Axes)\n"); break; case EV_MSC : printf(" (Miscellaneous)\n"); break; case EV_LED : printf(" (LEDs)\n"); break; case EV_SND : printf(" (Sounds)\n"); break; case EV_REP : printf(" (Repeat)\n"); break; case EV_FF : case EV_FF_STATUS: printf(" (Force Feedback)\n"); break; case EV_PWR: printf(" (Power Management)\n"); break; default: printf(" (Unknown: 0x%04hx)\n", yalv); } } } close(fd); } |
这个例子使用了 evtype_bit掩码 EV_MAX(在 <linux/input.h>里定义),觉得 bit array需要多少内存。当 ioctl提交后,由 event layer填充 bit array。我们测试 bit array里的每一个 bit,来确定设备支持哪些 feature type。所有的设备都支持 EV_SYNC,该 bit由 input core来设置。
下面是运行结果的样例:
如果是 keyboard,则
Supported event types: |
如果是 mouse,则
Supported event types: |
获取设备 (from or to)的 input
当确定了设备的能力和特性后,你就知道了设备的事件类型。
获取设备的 event通过 char设备的 read function。当你从 event device (例如 /dev/input/event0)里读取 event时,你将获得一系列 events,每个 event由 input_event结构表示。
Listing 8示例展示了读取一个打开文件描述符 fd的事件。它过滤了不属于 key的事件,并打印 input_event结构里的每个域。
Listing 8. Checking for Busy Spots/* how many bytes were read */ |
下面是运行的结果样例:
Event: time 1033621164.003838, type 1, code 37, value 1 |
对于每个 key,你会获得一个 key press和一个 key depress的 event。
这是 char设备的标准 read接口,所以你不需要在程序里 busy loop。此外,如果你想同时获得许多设备的 input事件时,使用 poll/select函数。
给设备发送信息,使用 char设备的标准 write函数,发送的数据必须是 input_event数据结构。
Listing 9展示了简单的给设备写数据的示例。这个例子先让 Caps Lock LED打开,等 200毫秒,然后让 Caps Lock LED关闭;然后让 Num Lock LED打开,等 200毫秒,然后让 Num Lock LED关闭。不断循环这个过程,你会看到键盘上的指示灯交替闪烁。
Listing 9. Sample Data Write Functionstruct input_event ev; /* the event */ /* we turn off all the LEDs to start */ |
现在我们清楚的知道如何接收或者发送一个事件 ---key按下 /抬起,鼠标移动等等。对于一些程序,可能还需要知道设备的一些全局状态。比如,一个管理 keyboard的程序需要知道当前的哪些指示灯在亮,哪些键被释放。
EVIOCGKEY ioctl用于确定一个设备的全局 key/button状态,它在 bit array里设置了每个 key/button是否被释放。 Listing 10展示了该示例。
Listing 10. Determining a Device's Global Key and ButtonState uint8_t key_b[KEY_MAX/8 + 1]; memset(key_b, 0, sizeof(key_b)); |
EVIOCGLED和 EVIOCGSND ioctl与 EVIOCGKEY类似,分别表示当前 LED亮灯和声音通道打开。 Listing 11展示了 EVIOCGLED的使用。
Listing 11. Using EVIOCGLEDmemset(led_b, 0, sizeof(led_b)); |
使用 EVIOCGREP ioctl来获取键盘的重复速率。 Listing 12展示了该示例。(重复速率指你按下键后,输出的事件的次数。例如,按下 1键且不释放, console里会输出多个 1的速率)
Listing 12. Checking the Repeat Rate Settingsint rep[2]; if(ioctl(fd, EVIOCGREP, rep)) { |
其中, rep[0]表示在按键重复出现之前 delay的时间; rep[1]表示按键重复出现的时间间隔。
使用 EVIOCSREP ioctl来设置键盘的重复速率。 Listing 13展示了该示例。
Listing 13. Setting the Repeat Ratesint rep[2]; rep[0] = 2500; |
rep[0]/rep[1]的含义同 Listing 12。
有些 input driver支持 key mapping。使用 EVIOCGKEYCODE ioctl获取一个 key对应的 scancode。 Listing 14/Listing 15展示了 key mapping的示例。注意有些键盘驱动并不支持这个特性(比如 USB键盘)。如果你想修改 key mapping,使用 EVIOCSKEYCODE ioctl即可。
Listing 14. Looping over Scancodesint codes[2]; for (i=0; i<130; i++) { |
Listing 15. Mapping Keysint codes[2]; codes[0] = 58; /* M keycap */ |
使用 EVIOCGABS ioctl提供绝对坐标轴设备的状态信息。它为每一个绝对坐标轴提供了一个 input_absinfo数据结构(参考 Listing 16)。如果你想查看设备的全局状态,对每一个坐标轴调用 EVIOCGABS ioctl函数。 Listing 17展示了该示例。
Listing 16. input_absinfo for an Absolute Axisstruct input_absinfo { |
Listing 17. Checking Global State by Axisuint8_t abs_b[ABS_MAX/8 + 1]; |
Force Feedback (力回馈)
有三个 ioctl用于控制 force-feedback设备: EVIOCSFF, EVIOCRMFF, EVIOCGEFFECT。这三个 ioctl分别表示发送一个 force-feedback effect,删除一个 force-feedback effect,获取当前多少个 effect在同时使用。
Linux input子系统 io控制字段【转】的更多相关文章
-
Linux Input子系统浅析(二)-- 模拟tp上报键值【转】
转自:https://blog.csdn.net/xiaopangzi313/article/details/52383226 版权声明:本文为博主原创文章,未经博主允许不得转载. https://b ...
-
Linux input子系统分析
输入输出是用户和产品交互的手段,因此输入驱动开发在Linux驱动开发中很常见.同时,input子系统的分层架构思想在Linux驱动设计中极具代表性和先进性,因此对Linux input子系统进行深入分 ...
-
Linux Input子系统
先贴代码: //input.c int input_register_handler(struct input_handler *handler) { //此处省略很多代码 list_for_each ...
-
Linux input子系统编程、分析与模板
输入设备都有共性:中断驱动+字符IO,基于分层的思想,Linux内核将这些设备的公有的部分提取出来,基于cdev提供接口,设计了输入子系统,所有使用输入子系统构建的设备都使用主设备号13,同时输入子系 ...
-
Android驱动之 Linux Input子系统之TP——A/B(Slot)协议
将A/B协议这部分单独拿出来说一方面是因为这部分内容是比较容易忽视的,周围大多数用到input子系统的开发人员也不甚理解:另一方面是由于这部分知识一旦扩展到TP(触摸屏Touch Panel)的多点触 ...
-
Linux input子系统简介
1.前言 本文主要对Linux下的input子系统进行介绍 2. 软件架构 图 input子系统结构图 input子系统主要包括三个部分:设备驱动层.核心层和事件层.我们可以分别理解为:具体的输入设备 ...
-
Android驱动之 Linux Input子系统之TP——A/B(Slot)协议【转】
转自:http://www.thinksaas.cn/topics/0/646/646797.html 将A/B协议这部分单独拿出来说一方面是因为这部分内容是比较容易忽视的,周围大多数用到input子 ...
-
Linux input子系统实例分析(二)
紧接着上一节的实例我们来分析调用的input子系统的接口: 1. input_dev,用来标识输入设备 1: struct input_dev { 2: const char *name; //设备名 ...
-
Linux input子系统实例分析(一)
这是一个简单的输入设备驱动实例.这个输入设备只有一个按键,按键被连接到一条中断线上,当按键被按下时,将产生一个中断,内核将检测到这个中断,并对其进行处理.该实例的代码如下: 1: #inclu ...
随机推荐
-
LinuxMM--MemoryHierarchy
MemoryHierarchy 为了理解内核中的页替换算法,有必要认识linux中的存储体系分层架构.访问模式以及混合工作mixed workloads. 存储器分层架构 有两种类型的存储分层架构 ...
-
APK Downgrade Method working fine on LINE latest version 6.7.1
Line is one of the most popular messaging Apps, especially in Asia. On March 3 I downgraded the app ...
-
zookeeper服务器端管理工具
zookeeper基本是基于API和console进行znode的操作,并没有一个比较方便的操作界面,这里也发现了taobao 伯岩写的一个工具,可以比较方便的查询zookeeper信息. 工具的开发 ...
-
JqGrid实现自定义查询
$("#jqGridId").setGridParam({url:"数据查询地址"}).trigger("reloadGrid");
-
两个bootstrap插件bootstrap-select和bootstrap-paginator
基于bootstrap的选择器 http://silviomoreto.github.io/bootstrap-select/ <label for="androids" c ...
-
【webpack】-- 样式加载
加载css需要用到css-loader和style-loader css-loader将@import 和 url 处理成正规的ES6 import ,如果@import指向的是一个外部资源,css- ...
-
C# 通过IEnumberable接口和IEnumerator接口实现自定义集合类型foreach功能
1.IEnumerator和IEnumerable的作用 其实IEnumerator和IEnumerable的作用很简单,就是让除数组和集合之外的类型也能支持foreach循环,至于foreach循环 ...
-
python上下文管理
一.python上下文介绍: python中的上下文,指的就是代码所执行的环境状态,或者运行的场景 python上下文管理器规定了某个对象的使用范围,当进入或者离开了使用范围,会有相应的操作,多用于资 ...
-
PostgreSQL使用笔记
下载并安装 注意安装图形界面 pgAdmin 需要输入缺省用户 postgres 的密码 在 Windows 下安装之后注意把 bin文件夹加到 Path 环境变量中. 重置密码 使用管理员权限打开 ...
-
python--元组tuple
元组与列表一样,都是序列.但元组不能修改内容(列表允许) 默认的,元组通过圆括号括起来 1. 使用type函数查看类型 numbers = (1,2,3,4,5,6,7,8,9,0) print(ty ...