2021-11-06 pynput库中鼠标和键盘事件的学习与使用

当你想要记录按键记录的时候来看看吧

欢迎来到python-pynput的世界,在这里你可以学到如何记录键盘与鼠标的使用记录,这将为你的自动化提供非常大的帮助,来看看pynput吧 。

鼠标和键盘的事件监听都是阻塞的,因此在学完鼠标键盘的操作后记得使用两个线程来配合使用哦
参考文档1
参考文档2

1、学会控制你的鼠标

   1.0 鼠标详解

  1. 鼠标按键:
    鼠标的按键在pynput.mouse.Button中,有lift、right、middle还有unknown四种。每一个按键都有两个有意义的属性:name和value。
            name是该按键的名称,比如 Button.left.name == ‘left’;
           value是记录上一次点击位置的元组。

  2. **鼠标事件的侦听器: pynput.mouse.Listener(on_move=None, on_click=None, on_scroll=None, suppress=False, kwargs)

# 此类继承自threading.Thread并支持它的所有方法。它会daemon到True当被创造的时候。
# 相当于下面的代码
listener.start()
try:
    listener.wait()
    with_statements()
finally:
    listener.stop()

其中:
----on_move为鼠标移动事件发生时调用的回调
将于当前指针的位置(x,y)一起回调,如果此回调引发StopException或返回False,监听就停止了。

----on_click为单击鼠标按钮时要调用的回调
将与参数(x, y, button, pressed)一起调用。(x, y)是新的指针位置,button是Button名字和值和pressed是否按下了按钮。
如果此回调引发StopException或返回False,听众就停止了。

----on_scroll为鼠标滚动事件发生时要调用的回调。
将与参数(x, y, dx, dy)一起调用。(x, y)是新的指针位置,(dx, dy)是滚动矢量。
如果此回调引发StopException或返回False,监听就停止了。

----suppress(布尔)-是否要压制事件,将此设置为True将防止输入事件传递到系统的其他部分。

----kwargs任何非标准平台相关选项。因此,应以平台名称作为前缀:darwin_, xorg_或win32_.
支持的值是:
darwin_intercept
一个可调用的接受论点的人(event_type, event),在哪里event_type是任何与鼠标相关的事件类型常量,以及event是CGEventRef.
此可调用函数可以使用以下函数自由地修改事件Quartz.CGEventSetIntegerValueField。如果此可调用程序不返回该事件,则该事件将在系统范围内被抑制。
win32_event_filter
一个可调用的接受论点的人(msg, data),在哪里msg是当前消息,并且data关联数据作为MSLHOOKSTRUCT.
如果此回调返回False事件将不会传播到侦听器回调。

如果self.suppress_event()调用,则该事件在系统范围内被抑制。

  1. **init(on_move=None, on_click=None, on_scroll=None, suppress=False, kwargs)
    应该始终使用关键字参数调用此构造函数。
    理由如下:
    group应该为None;在实现ThreadGroup类时为以后的扩展保留。
    target要由run()方法调用的可调用对象。默认为None,意味着没有任何调用。

name是线程名。默认情况下,一个唯一的名称是由“Thread-N”形式构造的,其中N是一个小的十进制数

args是目标调用的参数元组。默认为()。

kwargs是目标调用的关键字参数字典。默认为{}。

如果子类重写构造函数,则必须确保在对线程执行任何其他操作之前调用基类构造函数(Thread.init())。

4. running
侦听器当前是否正在运行。

5. start()
启动线程的活动。

每个线程对象最多只能调用一次。它安排在单独的控制线程中调用对象的run()方法。

如果在同一个线程对象上多次调用该方法,则此方法将引发RuntimeError。

6. stop()
停止监听事件。

当此方法返回时,将不再传递事件。调用此方法后,将不再使用侦听器实例,因为侦听器是threading.Thread,一旦停止,就不能重新启动。

若要继续侦听事件,必须创建一个新侦听器。

7. wait()
等待此侦听器准备就绪。

  1. 监听鼠标有两种方法,一种是函数式、非阻塞型,另一种是语句式、阻塞型。

   1.1 监听鼠标事件

方法一:函数式、非阻塞型

from pynput import mouse

# # 监控鼠标
# 鼠标的位置
# 当这个函数返回False时结束监听
def on_move(x, y): 
    print('Pointer moved to {0}'.format(
        (x, y)))
    # return False

# 鼠标键位的点击或者释放,
# 传入其点击或者释放的坐标位置
# 传入鼠标的哪个按键,left左键,middle中键,right右键
# 传入鼠标的点击或者释放,鼠标的每次点击获释放都会触发on_click,当pressed为真时为点击,否则的话为释放
# 当这个函数返回False时结束监听
def on_click(x, y, button, pressed):
    # print(button)   #当前按下的鼠标按键
    print('{0} at {1}'.format(
        'Pressed' if pressed else 'Released',
        (x, y)))
    if not pressed:  # 如果不是按下鼠标则为释放鼠标,释放鼠标后返回False停止监听
        # Stop listener
        return False
        
# 鼠标的滚动
# 鼠标在(x,y)位置滚动(dx,dy)值,每次dy或者dx只会返回1,但会更具你滚动的时间调用多次滚动函数
# 当这个函数返回False时结束监听
def on_scroll(x, y, dx, dy):
    print('Scrolled {0} at {1}'.format(
        'down' if dy < 0 else 'up',
        (x, y)))
    print(str(dy) + '   ' + str(dx))
    # return False

# 监听事件,直到返回False后结束
with mouse.Listener(
        on_move=on_move,
        on_click=on_click,
        on_scroll=on_scroll) as listener:
    listener.join()

# 一个鼠标监听器是一个线程。线程,所有的回调将从线程调用。从任何地方调用pynput.mouse.Listener.stop,或者调用pynput.mouse.Listener.StopException或从回调中返回False来停止监听器。

# with as # 能够帮我们自动分配并且释放资源
# 例如,使用 with as 操作已经打开的文件对象(本身就是上下文管理器),无论期间是否抛出异常,都能保证 with as 语句执行完毕后自动关闭已经打开的文件。


# 以非阻塞的方式开启鼠标监听事件
listener = mouse.Listener(
    on_move=on_move,
    on_click=on_click,
    on_scroll=on_scroll)
listener.start()
# 这个位置一直没弄懂,希望大佬们给个能看懂的解释
# 用listener.start()和listener.stop()代替with语句

方法二:同步事件监听,对所有事件进行迭代,非阻塞的方式
我只是大自然的搬运工,显然这个似乎比方法一更方便

迭代器方法不支持非阻塞操作,因此它将等待至少一个鼠标事件。

import pynput

with pynput.mouse.Events() as event:

    for i in event:
    #迭代用法。
        if isinstance(i, pynput.mouse.Events.Move):
            #鼠标移动事件。
            print(i.x, i.y)
            #不要直接打印`i`,模块这里有问题,会报错。

        elif isinstance(i, pynput.mouse.Events.Click):
            #鼠标点击事件。
            print(i.x, i.y, i.button, i.pressed)
            #这个i.button就是上文所说的“鼠标按键”中的一个,用is语句判断即可。

        elif isinstance(i, pynput.mouse.Events.Scroll):
            #鼠标滚轮。
            print(i.x, i.y, i.dx, i.dy)


        # break  # 终止循环,不写会一直监听
    
    i = event.get(1)

    # 另一种用法。
    # 默认值是None。
    # 这个`1`就是最长等待时间,超过这个时间没有事件,
    # 就会报错。错误类型是queue模块的Empty,而非TimeoutError。

   1.2 监听鼠标事件

# 控制鼠标
import pynput
from pynput.mouse import Button  # 获取鼠标键位

mouse = pynput.mouse.Controller()  # 通过pynput.mouse.Controller()获取控件

# mouse.position = (0,0)  #移动鼠标到该位置
# 你对这个值进行赋值时,你的鼠标就会被移动到该值对于的位置去啦,不要找不到鼠标的位置了哦
# 也可以通过打印该值获取到鼠标当前的位置哦
mouse.position = (1016,848)   #移动鼠标到当前位置
print(mouse.position)  #打印鼠标当前的位置

# 移动一个鼠标 mouse.move(x,y)
# 将鼠标指针从其当前位置移动若干像素,请记住鼠标的移动是从当前的位置移动的,x和y分别为从当前位置移动多少像素的值
# x为水平移动,正值向右移动
# y为垂直移动,正值向下移动
mouse.move(0,100)

# 点击鼠标 mouse.click(pynput.mouse.Button,count)
# pynput.mouse.Button为鼠标的键位:left、right和middle
# count为点击次数,默认为1
mouse.click(pynput.mouse.Button.right)  # 右键单击

# 拆分点击事件:按下和释放
# 方法press(button)按下button键;
# 方法release(button)释放键,如果操作时按键并没有被按下,也不会报错。
mouse.press(Button.left)
mouse.move(-100,-300)
mouse.release(pynput.mouse.Button.left)  
# pynput.mouse.Button.left和Button.left为一个键

# mouse.scroll()鼠标滚动
# x为水平滚动,正值向右滚动,很少用到
# y为垂直滚动,正值向下滚动
mouse.scroll(10,0)

2、学会控制你的键盘

pynput.keyboard包含用于控制和监视键盘的类

键盘事件监听器是一个线程,所有的回调函数都会在独立的线程中运行。

2.0 键盘事件

参考链接

  1. 类pynput.keyboard.Controller: 一种控制器,用于向系统发送虚拟键盘事件
  2. 部分类似鼠标监听事件,自行参考以上链接
  3. 类pynput.keyboard.Key: 表示可能与字母不相对应的各种按钮的类。这包括修饰符键和函数键

   2.1 键盘监听

      2.1.1 单个键位监听

一次pynput.keyboard.Listener.stop调用后,无法重新启动侦听器,因为侦听器是threading.Thread.

同理鼠标监听事件,有两种方法

方法一:

# 监听键盘
from pynput import keyboard

# 按下按键时执行。
def on_press(key):
   try:
       print(f'字母 {key.char} 被按下了')
   except AttributeError:
       print(f'特殊的键 {key} 被按下了')
# 普通按键可以通过pynput.keyboard.KeyCode.from_char取得(特殊按键不可以,使用时会出现ArgumentError),如上即为argumentError报错后打印特殊键值:a可以运行pynput.keyboard.KeyCode.from_char('a')获得。
# 特殊按键可以在pynput.keyboard.Key“模块”中可以直接找到,比如ctrl对应pynput.keyboard.Key.ctrl还有.ctrl_l以及.ctrl_r。
# 二者都可以用pynput.keyboard.KeyCode.from_vk通过按键的映射码取得。

# 松开按键时执行
def on_release(key):
   print(f'{key} 被释放了')
   if key == keyboard.Key.esc:
       # 停止监听
       return False

# 一直监听键盘事件,直到停止
with keyboard.Listener(
       on_press=on_press,
       on_release=on_release) as listener:
   listener.join()
# 调用pynput.keyboard.Listener.stop,发起StopException异常,或者回调函数中返回False都会停止事件的监听。
# 传递给回调函数的key参数是一个pynput.keyboard.Key类的实例。当特殊按键和普通按键一起按下时,数字字母按键的值会被放置在pynput.keyboard.KeyCode类的实例中,对于不知道的按键会返回None。

# ...or, in a non-blocking fashion:
listener = keyboard.Listener(
    on_press=on_press,
    on_release=on_release)
listener.start()
# 用listener.start()和listener.stop()代替with语句

方法二:

import pynput

with pynput.keyboard.Events() as events:

    for event in events:
    #迭代用法。

        print(event)   # 输出按下的键值
        #判断事件情况:

        if isinstance(event, pynput.keyboard.Events.Press):
            print('按下按键', end = '')
        elif isinstance(event, pynput.keyboard.Events.Release):
            print('松开按键', end = '')

        #判断按键:

        #*这个事件的`key`属性*对应才是*Listener方法获得的按键`'key'`*。

        try:
            print(event.key.name)   # 输出键名nameme
            print(event.key)        # 输出键名key.name
            print(event.key.value)  # 特殊键会有值
        except AttributeError:
            #说明这个是普通按键。s
            print(event.key.char)
            print(event.key)        # 输出一个's'
        else:
            #两种判断方式,第一种是我自创的,第二种是官网上的。
            if (event.key.name).startswith('ctrl'):
                #通过名称判断。
                print('发生了ctrl键事件。')
            elif event.key is pynput.keyboard.Key.esc:
                print('发生了esc键事件。')
        # break   # 使用break退出事件a
    
    event = events.get()
    #get用法。
    #可以提供一个实数作为最长等待时间(单位秒),超过这个时间没有事件,
    #就会报错。错误类型是queue模块的Empty,而非TimeoutError。

   2.1.2 热键监听(多个键位一起按)

键盘监视器的一个常见用例是对全局热键作出反应。由于侦听器不维护任何状态,涉及多个键的热键必须将此状态存储在某个位置。

pynput提供类pynput.keyboard.HotKey为了这个目的。它包含两种更新状态的方法,设计这些方法可以轻松地与键盘侦听器进行互操作:pynput.keyboard.HotKey.press和pynput.keyboard.HotKey.release它可以作为侦听器回调直接传递。

监听单个全局热键

from pynput import keyboard

def on_activate():
    print('Global hotkey activated!')

def for_canonical(f):
    return lambda k: f(l.canonical(k))

hotkey = keyboard.HotKey(
    keyboard.HotKey.parse('<ctrl>+<alt>+h'),
    on_activate)
# 创建一个热键,当指定所有键按下时,执行on_activate()
# 方法pynput.keyboard.HotKey.parse是将快捷字符串转换为键集合的方便函数。

with keyboard.Listener(
       on_press=for_canonical(hotkey.press),
        on_release=for_canonical(hotkey.release)) as l:
    l.join()

监听多个全局热键

from pynput import keyboard

# 如果需要监听多个全局热键,可以参照以下方式
def on_activate_h():
    print('<ctrl>+<alt>+h pressed')
# 多个不同的函数,代表执行不同的命令

def on_activate_i():
    print('<ctrl>+<alt>+i pressed')

with keyboard.GlobalHotKeys({
        '<ctrl>+<alt>+h': on_activate_h,
        '<ctrl>+<alt>+i': on_activate_i}) as h:
# 多个键值调用不同函数
# 不能分辨按键顺序如“<ctrl>+a”与“a+<ctrl>”。
# 单个按键也可以使用
    h.join()

2.2 控制键盘来咯

获取控件 :ctr = pynput.keyboard.Controller()

通过方法press来按下按键
通过release释放按键

2.1.0 类pynput.keyboard.Key: 键与值
Key = pynput.keyboard.Key

Key.alt : 普通的Alt键
Key.alt_gr:AltGr键。
Key.alt_l:左边的Alt键
Key.alt_r :右边的Alt键
Key.backspace :回退键。
Key.caps_lock :CapsLock钥匙。
Key.cmd :通用命令按钮。在……上面Pc平台,这对应于超级键或Windows键,并且在麦克它对应于命令键。
Key.cmd_l :左边的命令按钮。在……上面Pc平台,这对应于超级键或Windows键,并且在麦克它对应于命令键。
Key.cmd_r :正确的命令按钮。在……上面Pc平台,这对应于超级键或Windows键,并且在麦克它对应于命令键。
Key.ctrl :普通的Ctrl钥匙。
Key.ctrl_l :左边的Ctrl钥匙。
Key.ctrl_r :正确的Ctrl键。
Key.delete :删除钥匙。
Key.down :向下箭头键。
Key.end :end键。
Key.enter :回车键。
Key.esc :ESC键。
Key.f1 :功能键。定义了F1到F20。
Key.home :主页键。
Key.insert :插入键。对于某些平台来说,这可能是没有定义的。
Key.left :左箭头键。
Key.media_next :下一个轨道按钮。
Key.media_play_pause :这出戏/暂停切换。
Key.media_previous :前一个轨道按钮。
Key.media_volume_down :音量下降按钮。
Key.media_volume_mute :音量静音按钮。
Key.media_volume_up :音量上升按钮
Key.menu :菜单键。对于某些平台来说,这可能是没有定义的
Key.num_lock :NumLock钥匙。对于某些平台来说,这可能是没有定义的。
Key.page_down 下页键。
Key.page_up :上页键。
Key.pause :暂停/中断键。对于某些平台来说,这可能是没有定义的。
Key.print_screen :PrintScreen键。对于某些平台来说,这可能是没有定义的。
Key.right :右箭头键。
Key.scroll_lock :锁键。对于某些平台来说,这可能是没有定义的。
Key.shift :一个通用的移位键
Key.shift_l :左移键
Key.shift_r :右移键
Key.space :空格键。
Key.tab :Tab键。
Key.up :向上箭头键。

**2.1.1类pynput.keyboard.KeyCode(vk=None, char=None, is_dead=False, kwargs)
A KeyCode表示操作系统使用的密钥代码的说明。

import pynput, time
# from pynput.keyboard import Key  # 获取键名
time.sleep(3)
keyboard = pynput.keyboard.Controller()
Key = pynput.keyboard.Key  # 获取键名的另一种方式

with keyboard.pressed(Key.shift):
    with keyboard.pressed('a'):
        pass    
# 利用with按下并释放某个按键

with keyboard.pressed(Key.page_up):
    pass

keyboard.type('Hello World')
# 直接输出函数中的值
keyboard.type([pynput.keyboard.Key.esc])
#按下esc再松开。

# 按“下ctrl+shilf+s”快捷键
keyboard.press(pynput.keyboard.KeyCode.from_vk(17))
#通过按键的映射码 按下ctrl键。
keyboard.press(pynput.keyboard.Key.shift)
#通过按键对象 按下shift键。
keyboard.press('s')
#通过长度为1的字符 按下s键。

#扫尾,释放刚才按下的键。逆序退出
keyboard.release(pynput.keyboard.KeyCode.from_vk(17))
keyboard.release(pynput.keyboard.Key.shift)
keyboard.release('s')

# 上述按键组合亦可以通过with实现
with keyboard.pressed(
        pynput.keyboard.Key.ctrl,
        pynput.keyboard.Key.shift,
        's'):
    pass

time.sleep(0.3)

# 按下esc键
keyboard.press(pynput.keyboard.Key.esc)
keyboard.release(pynput.keyboard.Key.esc)

最后,本文参考了来自
风吹云动的文章
官方的文章
可以自行看看原文

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤独的履行者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值