Python And Keyboard Events

TL;DR: Use click.getchar()!

Here's the Problem

Like many other developers, I spend a lot of my time in the terminal. That means for a lot of simple tasks and small tools, I'm happy to stick with writing scripts or commandline clients. And for me, Python is a great language to do that.

It's batteries included approach to many problems makes it super easy to hack together a script for almost any job, and if you look at a library like Click make building command-line clients a piece of cake. If you haven't heard of it, check out my talk at PyCon US 2016.

Why am I rambling on about this? Well, with all of these libraries and included batteries, you'd expect getting key press events from the commandline would also be a 🍰. But far from it! Unless you accept that input has to be terminated by a newline (i.e. hitting [Enter]), things seem to be more complicated than they have to be...

Stack Overflow To The Rescue?

I did some searching for best pratices and recommended solutions. The result was fairly disappointing since all I could find was a few suggestions on Stack Overflow. It's hard to tell if the answers there can be considered best practise in this instance but that's what I found.

The outcome of my search is very similar to the suggestions in this SO answer:

  1. Use something like TkInter, PyGames or some other GUI framework.

  2. Use curses for the commandline.

  3. Or put together a getchar method using sys, tty and termios (or msvcrt on Windows).

It doesn't sound to bad at first glance until you look a the actual implementation that's required for some of these soution. My thoughts are:

  1. Unless you are using TKinter, PyGames or something already, this seems like overkill to simply get key press events. And it doesn't solve the problem for the terminal.

  2. Using curses might be fine, but it takes over the terminal and you'll have to go through curses for all you printing...which is less then ideal, in my opinion.

  3. The DIY option works but requires a lot of boilerplate that increases as you are trying to cover all platforms including Windows. The simpler version as in this SO answer only works for single character events which excludes keys such as the arrow keys. And if you take those into account (similar to this snippet) it starts looking pretty convoluted.

For me, the question remained, isn't there a nice and simple way of doing this?

Click To The Rescue!

Not surprising, there actually is a simple solution. And even better, it's part of my favourite CLI library: Click. In an act of desperation during my search, I reached for the Click documentation. And no surprise, it ships with exactly what I was looking for:

import click

key = click.getchar()

This will give you the Unicode character identifying the key that was pressed and in the case of arrow keys, their representation "the platform's native escape format" (see the docs). And once again, peace is restored in my developer mind 😉.

Copyright © 2017 Roadside Software & Adventures / All rights reserved.