zoukankan      html  css  js  c++  java
  • python监听、操作键盘鼠标库pynput详细教程

    § 0.0.0 前言

    监听、操作鼠标、键盘是实现自动化的捷径,比如我实现自动化签到用到了模拟键盘操作。

    pynput是监听、操控鼠标和键盘的跨平台第三方python库。
    你可以通过pip insnall pynput来安装。安装时会自动下载依赖库。

    pypi链接在此。

    接下来我会按
    “鼠标按键”“监听鼠标”“控制鼠标”,“键盘按键”“监听键盘”“控制键盘”
    的顺序介绍它的用法。



    • 以下为正文。


    §1.0.0 鼠标按键

    鼠标的按键在pynput.mouse.Button中,
    liftrightmiddle还有unknown四种。

    每一个按键都有两个有意义的属性:namevalue
    name是该按键的名称,比如 Button.left.name == 'left';
    value是记录上一次点击位置的元组。



    §1.1.0 监听鼠标

    有两种方法,一种是函数式、非阻塞型,另一种是语句式、阻塞型。

    先说第一种,这种是常见的教程所说的方法。

    §1.1.1 pynput.mouse.Listener

    以下是官网的说明示例:

    import pynput, time
    
    def on_move(x, y):
        print('Pointer moved to {0}'.format((x, y)))
    
    def on_click(x, y, button, pressed):
        print('{0} at {1}'.format(
            'Pressed' if pressed else 'Released',
            (x, y)))
        if not pressed:
            # Stop listener
            return False
    
    def on_scroll(x, y, dx, dy):
        print('Scrolled {0} at {1}'.format(
            'down' if dy < 0 else 'up',
            (x, y)))
    
    # Collect events until released
    with pynput.mouse.Listener(
            on_move=on_move,
            on_click=on_click,
            on_scroll=on_scroll) as listener:
        listener.join()
    

    运行这段代码时,移动鼠标会显示其坐标,
    按下鼠标按键并松开后,程序结束。

    • 当三个函数任意一个返回False((还有就是释放Exception或继承自Exception的异常)时,就会结束进程。
    • 可以用listener.start()listener.stop()代替with语句。

    §1.1.2 pynput.mouse.Events

    个人认为,这个方法比上一个更直观。

    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.0 控制鼠标

    • § 1.2.1
      先执行pynput.mouse.Controller()获取控件。
      以下方法都是该控件的所属方法。

    如下:

    import pynput
    
    ctr = pynput.mouse.Controller()
    

    • § 1.2.2

    动态属性position返回鼠标位置坐标的元组(像这样: (x, y) ),
    通过定义来改变鼠标位置,比如ctr.position = (500, 500)


    • § 1.2.3

    当然,也有move方法,用于移动鼠标
    用法是ctr.move(dx, dy)


    • § 1.2.4

    使用方法click进行模拟点击,需提供点击的按钮,
    按钮在pynput.mouse.Button里,有leftrightmiddle
    还有可选参数count,是点击次数,默认为1。

    示例:

    import pynput
    
    ctr = pynput.mouse.Controller()
    
    ctr.click(pynput.mouse.Button.left)
    #左键单击。
    
    ctr.click(pynput.mouse.Button.left, 2)
    #左键双击。
    
    ctr.click(pynput.mouse.Button.right)
    #右键单击。
    

    • § 1.2.5

    使用press(button)按下button键;
    方法release(button)释放键,如果操作时按键并没有被按下,也不会报错。

    示例:

    import pynput
    
    ctr = pynput.mouse.Controller()
    
    ctr.press(pynput.mouse.Button.left)
    #按下左键。
    
    ctr.move(50, 0)
    #右移50单位。
    
    ctr.move(0, 50)
    #下移50单位。
    
    ctr.release(pynput.mouse.Button.left)
    #释放左键。
    

    • § 1.2.6

    模拟滚轮,使用的方法是scroll,提供参数dxdy

    例:

    import pynput
    
    ctr = pynput.mouse.Controller()
    
    ctr.scroll(0, 50)
    #向上滚动50单位。
    
    ctr.scroll(0, -50)
    #向下滚动50单位。
    


    • 以上是鼠标操作,
    • 以下是键盘操作。


    § 2.0.0 键盘按键

    键盘的按键获取比鼠标的麻烦些,但是没有鼠标用得多。
    因此我先说给常用的使用方法,再说获取


    § 2.0.1 使用方法

    首先,当获取事件后,要判断按键是“特殊按键”还是“普通按键”,
    需判断其是否具有name属性,有则是特殊按键
    这个属性记录属性的名称,比如ctrl对应着'ctrl''ctrl_l'或是'ctrl_r'
    普通按键中,取而代之的是.char

    注:大写字母与小写字母有不同的按键。

    还有其他功能。这里就不多说了。

    § 2.0.2 获取

    首先,特殊按键pynput.keyboard.Key“模块”中可以直接找到。
    比如ctrl对应pynput.keyboard.Key.ctrl还有.ctrl_l以及.ctrl_r

    然后,普通按键可以通过pynput.keyboard.KeyCode.from_char取得(特殊按键不可以,使用时会出现ArgumentError)。
    a可以运行pynput.keyboard.KeyCode.from_char('a')获得。

    二者都可以用pynput.keyboard.KeyCode.from_vk通过按键的映射码取得。



    § 2.1.0 监听键盘

    主要有两种方法,类似于鼠标的,我的讲述顺序同前文。
    还有一种是对Listener的封装,用于快捷键,我放在最后一个说。

    § 2.1.1 pynput.keyboard.Listener

    注:如果你只想关注个别按键而非所有事件,可以使用GlobalHotKeys。我会在后文说。

    官网示例:

    from pynput import keyboard
    
    def on_press(key):
        '按下按键时执行。'
        try:
            print('alphanumeric key {0} pressed'.format(
                key.char))
        except AttributeError:
            print('special key {0} pressed'.format(
                key))
        #通过属性判断按键类型。
    
    def on_release(key):
        '松开按键时执行。'
        print('{0} released'.format(
            key))
        if key == keyboard.Key.esc:
            # Stop listener
            return False
    
    # Collect events until released
    with keyboard.Listener(
            on_press=on_press,
            on_release=on_release) as listener:
        listener.join()
    
    • 当两个函数中任意一个返回False(还有就是释放Exception或继承自Exception的异常)时,就会结束进程。
    • 可以用listener.start()listener.stop()代替with语句。

    § 2.1.2 pynput.keyboard.Events

    
    import pynput
    
    with pynput.keyboard.Events() as event:
    
        for i in event:
        #迭代用法。
            key_event = i
            break
        
        key_event = event.get()
        #get用法。
        #可以提供一个实数作为最长等待时间(单位秒),超过这个时间没有事件,
        #就会报错。错误类型是queue模块的Empty,而非TimeoutError。
    
    #判断事件情况:
    
    if isinstance(key_event, pynput.keyboard.Events.Press):
        print('按下按键', end = '')
    elif isinstance(key_event, pynput.keyboard.Events.Release):
        print('松开按键', end = '')
    
    #判断按键:
    
    #*这个事件的`key`属性*对应才是*Listener方法获得的按键`'key'`*。
    
    try:
        print(key_event.key.name)
    except AttributeError:
        #说明这个是普通按键。
        print(key_event.key.char)
    else:
        #两种判断方式,第一种是我自创的,第二种是官网上的。
        if (key_event.key.name).startswith('ctrl'):
            #通过名称判断。
            print('发生了ctrl键事件。')
        elif key_event.key is pynput.keyboard.Key.esc:
            print('发生了esc键事件。')
    

    § 2.1.3 pynput.keyboard.GlobalHotKeys

    (还有'pynput.keyboard.HotKey'可以实现相似功能,但很麻烦)

    官网示例,esc那个是我写的。

    from pynput import keyboard
    
    def on_activate_h():
        print('<ctrl>+<alt>+h pressed')
    
    def on_activate_i():
        print('<ctrl>+<alt>+i pressed')
    
    def esc():
        print('<esc> pressed')
        return False
    
    def esc_shift():
        print('<esc>+<shift> pressed')
        raise Exception
    
    with keyboard.GlobalHotKeys({
            '<ctrl>+<alt>+h': on_activate_h,
            '<ctrl>+<alt>+i': on_activate_i,
            '<esc>':          esc,
            '<esc>+<shift>':  esc_shift}) as h:
        h.join()
    

    当按下esc键时,函数被触发,但运行未停止。
    观察源码,发现虽然该类继承自Listener,但会对执行的函数有封装,封装后只返回None。
    所以无法通过return False结束进程。

    设置单个普通按键(比如“a”)也是可以的。

    不能分辨按键顺序如“<ctrl>+a”与“a+<ctrl>”。



    § 2.2.0 控制键盘

    • § 2.2.1

    先获取控件 :ctr = pynput.keyboard.Controller()
    以下所说的方法均是指该控件的方法。


    • § 2.2.2

    通过方法press按下按键
    你需要提供一个“长度为1的字符”或是“前文所说的按键对象”。

    温馨提示,此方法测试有风险,如果发现电脑打字、操作异常,
    很可能是因为模拟按下了某个键未松开。
    可以重启控制台或电脑。


    • § 2.2.3

    通过release释放按键
    和press方法一样,需要提供一个“长度为1的字符”或是“前文所说的按键对象”。

    示例:

    '''
    这段程序会按“下ctrl+shilf+s”快捷键,停顿3秒后按下esc键。
    简单模拟了“另存为”操作。
    '''
    
    import pynput, time
    
    ctr = pynput.keyboard.Controller()
    
    ctr.press(pynput.keyboard.KeyCode.from_vk(17))
    #通过按键的映射码 按下ctrl键。
    
    ctr.press(pynput.keyboard.Key.shift)
    #通过按键对象 按下shift键。
    
    ctr.press('s')
    #通过长度为1的字符 按下s键。
    
    
    #扫尾,释放刚才按下的键。后面我会说更简单、优雅的办法。
    ctr.release(pynput.keyboard.Key.ctrl)
    ctr.release(pynput.keyboard.Key.shift)
    ctr.release('s')
    
    time.sleep(0.3)
    
    ctr.press(pynput.keyboard.Key.esc)
    ctr.release(pynput.keyboard.Key.esc)
    

    • § 2.2.4

    pressed方法就是我说的“更简单、优雅”的方法。
    使用时提供要按下的键,再用with语句“封装”上。
    效果是进入语句块时顺序按下提供按键,退出语句块时逆序释放按键。

    如下:

    import pynput, time
    
    ctr = pynput.keyboard.Controller()
    
    with ctr.pressed(
            pynput.keyboard.Key.ctrl,
            pynput.keyboard.Key.shift,
            's'):
        pass
    
    time.sleep(0.3)
    
    with ctr.pressed(pynput.keyboard.Key.esc):
        pass
    

    • § 2.2.5

    type在英语中除了“类型”还有“打字”之意。
    该方法接收字符串,然后打出每个字符。
    据测试,向它提供一个“按键列表”也可以正常使用。

    例:

    import pynput
    
    ctr = pynput.keyboard.Controller()
    
    ctr.type('Hello world!')
    
    ctr.type([pynput.keyboard.Key.esc])
    #按下esc再松开。
    


    • 以上是正文。


    一些建议

    该模块鼠标、键盘的监听操作均由多线程实现。
    所以,可以利用多线程共享内存的特征编程;二要注意不要频繁启动监听,这样对系统开支极大。

    还有就是对鼠标位置监听要求不是很高时(比如实时向用户显示鼠标位置),可以每次循环sleep一下。
    如果向Listener提供的函数会执行很久(比如含有sleep),会导致电脑变卡。

    闲谈

    之前和别人聊天,他说他在不需要时把电脑的麦拔下来、摄像头挡上。
    我说用Fn快捷键禁掉麦克风更方便。
    现在想想,黑客可以通过模拟按键解禁麦克风啊。
    虽然这个模块没有Fn键,但别的呢?

    最后

    这份算是最全的了。原创不易,纯手打。

    转载请注明作者和链接哦。

    感谢阅读!

  • 相关阅读:
    详测 Generics Collections TDictionary(2): ContainsKey、ContainsValue、AddOrSetValue、TryGetValue
    详测 Generics Collections TQueue (3): OnNotify、Extract
    详测 Generics Collections TDictionary(4): OnKeyNotify、OnValueNotify
    详测 Generics Collections TStack(1): Push、Pop、Peek 其他功能同 TQueue
    详测 Generics Collections TDictionary(1): Add、Items、Keys、Values、Remove
    测试字符串写入类: TStringWriter
    在IIS 6 中使用HTTP压缩(Compression)遇到的一个问题
    [好消息]博客园新服务器到货
    [公告]美化家园行动—博客园成立Skin设计小组
    [公告]星期天上午更换新服务器
  • 原文地址:https://www.cnblogs.com/tobe-goodlearner/p/tutorial-pynput.html
Copyright © 2011-2022 走看看