9

我必须知道按下的是什么键,但不需要字符的代码,我想知道有人何时按下“A”键,即使获得的键是“a”或“A”,以及所有其他键.

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

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

前任:

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

8 回答 8

25

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

于 2009-02-22T21:02:36.963 回答
9

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

于 2009-02-22T20:03:45.950 回答
4

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

监听器的官方示例是:

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()

希望这可以帮助。

于 2018-04-11T13:11:13.990 回答
3

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

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

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

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

于 2009-02-22T20:12:31.373 回答
1

这是我最近一直在努力解决的一个话题。这里要检查的另一件事是您是否在不同的键盘布局中获得正确的值。例如,当您切换到法语 - 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 
---------------------

这与此处的平台特定键码一致。

于 2020-12-13T18:29:26.117 回答
0

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

于 2009-02-22T20:50:47.520 回答
0

显而易见的答案:

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()

ETC...

这是 getch 函数的一个实现,它可以在 Windows 和 Linux 平台上运行,基于这个秘籍

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()
于 2009-02-26T18:59:04.840 回答
0

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

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
于 2016-10-26T09:32:31.477 回答