【问题标题】:How to obtain the keycodes in Python如何在 Python 中获取密钥代码
【发布时间】:2010-10-09 04:57:03
【问题描述】:

我必须知道按下了什么键,但不需要角色的代码,我想知道有人何时按下“A”键,即使获得的键是“a”或“A”,等等所有其他键。

我不能使用 PyGame 或任何其他库(包括 Tkinter)。只有 Python 标准库。这必须在终端中完成,而不是图形界面。

不需要字符代码。我需要知道关键代码。

例如:

ord('a') != ord('A')                      # 97 != 65
someFunction('a') == someFunction('A')    # a_code == A_code

【问题讨论】:

  • 图形或终端用户界面?
  • Windows 还是 Linux?请更新问题,而不是添加其他评论。
  • 请用“编辑”标记更新您的问题,以显示您增强问题的位置。
  • TKinter 是标准 python 库的一部分。它与 python 一起发布了很多年。
  • 我也有类似的问题,你能帮帮我吗:stackoverflow.com/questions/63464407/…

标签: python input keycode


【解决方案1】:

参见tty 标准模块。它允许使用tty.setcbreak(sys.stdin) 从默认的面向行(熟)模式切换到面向字符(cbreak)模式。从 sys.stdin 读取单个字符将导致下一个按下的键盘键(如果它生成代码):

import sys
import tty
tty.setcbreak(sys.stdin)
while True:
    print ord(sys.stdin.read(1))

注意:解决方案仅适用于 Unix(包括 Linux)。

编辑:在 Windows 上尝试 msvcrt.getche()/getwche()。 /我无处可试...


编辑 2:通过ctypes.windll(参见example at SO)和ReadConsoleInput 函数使用win32 低级控制台API。您应该过滤掉按键 - e.EventType==KEY_EVENT 并寻找 e.Event.KeyEvent.wVirtualKeyCode 值。可以在http://www.benryves.com/tutorials/?t=winconsole&c=4 找到应用程序示例(不是在 Python 中,只是为了了解一下)。

【讨论】:

  • 重复,我不需要字符代码,我需要 KeyCode,按键 A 或 SHIFT+A 的按下必须相同。使用 ord() 将返回一个值 A,另一个值 SHIFT+A;像箭头这样的键不起作用
  • 我觉得你问的问题太低级了。它在 DOS 中有效。如今的操作系统采用从键到符号的键映射方法,使得切换键盘布局(语言)变得容易,因此几乎没有机会获得低级按键。 pygame 解决方法。
  • 代码运行良好,除了我在笔记本电脑上发现的一些问题。 1. CTRL+J=10 和 CTRL+M=10。它们是一样的,我不知道为什么。 2. CTRL+some char 与 CTRL+ALT+some char 相同。
  • 在 macOS 上,这不会打印 fn、控制、选项、命令的结果。如果您需要这些关键代码,请参阅下面我的 wxPython 答案。
【解决方案2】:

根据您要完成的工作,也许使用 pygame 之类的库可以满足您的需求。 Pygame 包含比 Python 标准库通常可用的更高级的按键处理。

【讨论】:

  • 谢谢,但我不必使用标准 python 库以外的任何其他库。
  • 好的。我将这个答案留在这里(而不是删除它),因为它可能对来到这里提出类似问题的其他人有用。
  • 对谁投反对票:最初的问题并没有说明 pygame 是不可接受的。
  • +1 切向帮助:SO 的主要优势之一。
【解决方案3】:

看看 Python 中的 pynput 模块。它还有一个不错的tutorial,您可以使用它轻松地为您的代码创建键盘侦听器。

监听器的官方示例是:

from pynput.keyboard import Key, Listener

def on_press(key):
    print('{0} pressed'.format(
        key))

def on_release(key):
    print('{0} release'.format(
        key))
    if key == Key.esc:
        # Stop listener
        return False

# Collect events until released
with Listener(on_press=on_press,
              on_release=on_release) as listener:
    listener.join()

希望这会有所帮助。

【讨论】:

【解决方案4】:

您可能必须使用Tkinter,它是“标准”Python gui,并且已包含在python 中多年。

由于数据传入和传出命令行进程的方式,命令行解决方案可能不可用。 GUI 程序(某种风格)都通过(可能是库包装的)事件流接收用户输入。每个事件都将记录该事件的详细信息。对于击键事件,记录可能包含任何键码、修饰键位域或某种编码的文本字符。哪些字段以及它们的命名方式取决于您调用的事件库。

命令行程序通过字符流接收用户输入。没有办法捕获较低级别的数据。正如 myroslav 在他的帖子中解释的那样,tty 可以处于熟或未熟模式,唯一的区别是在熟模式下,终端将为您处理(一些)控制字符,例如删除和输入,以便进程接收输入行,而不是一次 1 个字符。

处理低于此要求的任何内容都需要(取决于操作系统)系统调用或在 /dev 中打开字符设备。 Python 的标准库没有为此提供标准工具。

【讨论】:

    【解决方案5】:

    这是我最近一直在努力解决的话题。 这里要检查的另一件事是,您是否在不同的键盘布局中获得了正确的值。例如,当您切换到法语 - PC 布局时,pygame 似乎无法正确报告数字键代码。我的建议是使用 wxPython。它在 RawKeyCode 属性中公开平台特定的键代码。 这是一个演示代码示例:

    import logging as log
    import wx
    
    class MainWindow(wx.Frame):
        def __init__(self, parent, title):
            wx.Frame.__init__(self, parent, title=title, size=(200,100))
    
            self.panel = wx.Panel(self, wx.ID_ANY)
            self.panel.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
            self.panel.Bind(wx.EVT_KEY_UP, self.OnKeyDown)
            self.panel.Bind(wx.EVT_CHAR, self.OnKeyDown)
            self.panel.SetFocus()
            self.Show(True)
    
        def OnKeyDown(self, event=None):
            line_txt = '---------------------'
            print(line_txt)
            for var in ['RawKeyCode', 'KeyCode', 'UnicodeKey']:
                print(var, getattr(event, var))
                if var == 'UnicodeKey':
                    print('char', chr(getattr(event, var)))
            print(line_txt)
    
    
    if __name__ == "__main__":
        app = wx.App(False)
        gui = MainWindow(None, "test")
        app.MainLoop()
    

    例如,当我在我的 mac 上按下 fn 键(一个 mac 专用键)时,我看到记录如下:

    ---------------------
    RawKeyCode 63
    KeyCode 0
    UnicodeKey 0
    char 
    ---------------------
    

    platform specific key codes here一致。

    【讨论】:

      【解决方案6】:

      如果您只需要在 Windows 中工作,您应该尝试msvcrt

      【讨论】:

        【解决方案7】:

        显而易见的答案:

        someFunction = string.upper
        
        ord('a') != ord('A')                      # 97 != 65
        someFunction('a') == someFunction('A')    # a_code == A_code
        

        或者,换句话说:

        char_from_user = getch().upper() # read a char converting to uppercase
        if char == 'Q':
            # quit
            exit = True # or something
        elif char in ['A', 'K']:
            do_something()
        

        等等……

        这是一个 getch 函数的实现,它可以在 Windows 和 Linux 平台上运行,based on this recipe

        class _Getch(object):
            """Gets a single character from standard input.  
               Does not echo to the screen."""
            def __init__(self):
                try:
                    self.impl = _GetchWindows()
                except ImportError:
                    self.impl = _GetchUnix()
        
            def __call__(self): 
                return self.impl()
        
        class _GetchUnix(object):
            def __init__(self):
                import tty, sys
        
            def __call__(self):
                import sys, tty, termios
                fd = sys.stdin.fileno()
                old_settings = termios.tcgetattr(fd)
                try:
                    tty.setraw(sys.stdin.fileno())
                    ch = sys.stdin.read(1)
                finally:
                    termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
                return ch
        
        
        class _GetchWindows(object):
            def __init__(self):
                import msvcrt
        
            def __call__(self):
                import msvcrt
                return msvcrt.getch()
        
        
        getch = _Getch()
        

        【讨论】:

          【解决方案8】:

          此函数将返回大写字符的代码:

          def upCcode( ch ):
              if(len(ch) == 1):
                  return ord(ch.upper())
          

          这是小写字符代码:

          def lowCcode( ch ):
                  if(len(ch) == 1):
                      return ord(ch.lower())
          

          这种方式要简单得多,而且不需要导入外部库。

          您需要选择两种方法之一作为您在问题中描述的“someFunction”。这是一个例子:

          输出:

          # when using upCode():
          >> upCcode('a')
          65
          
          >> upCcode('A')
          65
          
          # when using lowCode():
          >> lowCcode('a')
          97
          
          >> lowCcode('A')
          97
          

          【讨论】:

            猜你喜欢
            • 2020-08-29
            • 1970-01-01
            • 2020-03-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-11-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多