How to obtain the keycodes in Python
Asked Answered
T

8

14

I have to know what key is pressed, but not need the code of the Character, i want to know when someone press the 'A' key even if the key obtained is 'a' or 'A', and so with all other keys.

I can't use PyGame or any other library (including Tkinter). Only Python Standard Library. And this have to be done in a terminal, not a graphical interface.

NOT NEED THE CHARACTER CODE. I NEED TO KNOW THE KEY CODE.

Ex:

ord('a') != ord('A')                      # 97 != 65
someFunction('a') == someFunction('A')    # a_code == A_code
Tobey answered 22/2, 2009 at 20:1 Comment(5)
Graphical or terminal user interface?Tien
Windows or Linux? Please update the question, rather than add yet another comment.Barbrabarbuda
Please update your question with "Edit" marks to show where you enhanced question.Antarctic
TKinter is part of the standard python library. It has shipped with python for many years.Tumular
I have a similar problem could you help me please: #63464907Redness
A
26

See tty standard module. It allows switching from default line-oriented (cooked) mode into char-oriented (cbreak) mode with tty.setcbreak(sys.stdin). Reading single char from sys.stdin will result into next pressed keyboard key (if it generates code):

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

Note: solution is Unix (including Linux) only.

Edit: On Windows try msvcrt.getche()/getwche(). /me has nowhere to try...


Edit 2: Utilize win32 low-level console API via ctypes.windll (see example at SO) with ReadConsoleInput function. You should filter out keypresses - e.EventType==KEY_EVENT and look for e.Event.KeyEvent.wVirtualKeyCode value. Example of application (not in Python, just to get an idea) can be found at http://www.benryves.com/tutorials/?t=winconsole&c=4.

Antarctic answered 22/2, 2009 at 21:2 Comment(4)
repeat, i dont need the character code, i need the KeyCode, the press of the key A or SHIFT+A has to be the same. Using ord() will return one value whit A and another whith SHIFT+A; and whith keys like the arrows will not workPertussis
I think the question you are asking about is too low level. It was valid in DOS. OS nowadays employ keymapping approach from keys to symbols, making it easy to switch keyboard layouts (languages) thus there is little chance getting to low level keypresses. pygame workaround that.Antarctic
The code works well except some issue I found on my laptop. 1. CTRL+J=10 and CTRL+M=10. They are the same, I don't know why. 2. CTRL+some char is the same as CTRL+ALT+some char.Inhabit
On macOS this does not print results for fn, control, option, command. If you need key codes for those please see my wxPython answer below.Lessielessing
B
9

Depending on what you are trying to accomplish, perhaps using a library such as pygame would do what you want. Pygame contains more advanced keypress handling than is normally available with Python's standard libraries.

Bach answered 22/2, 2009 at 20:3 Comment(4)
thanks, but i dont have to use any other library than the standard python library.Pertussis
Okay. I'm leaving this answer here (and not deleting it) because it may be useful to somebody else who comes here asking a similar question.Bach
And to whoever downvoted this: The original question did not state that pygame was not acceptable.Bach
+1 for tangential helpfulness: one of the major strengths of SO.Philan
D
5

Take a look at pynput module in Python. It also has a nice tutorial using which you can easily create keyboard listeners for your code.

The official example for listeners is:

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

Hope this helps.

Donnydonnybrook answered 11/4, 2018 at 13:11 Comment(3)
Just FYI this library does not work well on MacOD per their docs pynput.readthedocs.io/en/latest/limitations.html#macosLessielessing
Doesn't work in console: "Please make sure that you have an X server running, and that the DISPLAY environment variable is set correctly"Drysalt
While this works, you just reproduced the example from the docs. This doesn't answer the question : "I need to know the key code"Mesnalty
T
4

You probably will have to use Tkinter, which is the 'standard' Python gui, and has been included with python for many years.

A command-line solution is probably not available, because of the way data passes into and out of command-line processes. GUI programs (of some flavor or another) all recieve user-input through a (possibly library wrapped) event stream. Each event will be a record of the event's details. For keystroke events, the record will may contain any of a keycode, modifier key bitfield, or text character in some encoding. Which fields, and how they are named depends on the event library you are calling.

Command-line programs recieve user input through character-streams. There is no way to catch lower-level data. As myroslav explained in his post, tty's can be in cooked or uncooked mode, the only difference being that in cooked mode the terminal will process (some) control characters for you, like delete and enter so that the process receives lines of input, instead of 1 character at a time.

Processing anything lower than that requires (OS dependent) system calls or opening character devices in /dev. Python's standard library provides no standard facility for this.

Tumular answered 22/2, 2009 at 20:12 Comment(0)
L
3

This is a topic that I have been grappling with recently. Another thing to check here is if you are getting correct values in different keyboard layouts. For example it doesn't look like pygame reports number key codes correctly when you switch into a French - PC layout. My suggestion is to use wxPython. It exposes the platform specific key codes in the RawKeyCode property. Here is a code sample which demonstrates that:

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

For example when I hit the fn key on my mac (a mac-only key) I see this logged:

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

Which is consistent with the platform specific key codes here.

Lessielessing answered 13/12, 2020 at 18:29 Comment(0)
C
0

If you need to work in windows only you should try msvcrt.

Carhart answered 22/2, 2009 at 20:50 Comment(0)
B
0

The obvious answer:

someFunction = string.upper

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

or, in other (key)words:

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...

Here is a implementation of the getch function, that would work in both Windows and Linux platforms, 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()
Baca answered 26/2, 2009 at 18:59 Comment(0)
H
0

this function will return the code for the uppercase character:

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

and this is for the lowercase character code:

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

this way is far easier, and you won't need to import external libraries.

You will need to choose one of the two methods to be the 'someFunction' you described in your question. Here's an example:

OUTPUT:

# when using upCode():
>> upCcode('a')
65

>> upCcode('A')
65

# when using lowCode():
>> lowCcode('a')
97

>> lowCcode('A')
97
Harlequin answered 26/10, 2016 at 9:32 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.