How to make a keyboard heatmap using python?

156 Views Asked by At

Basically, I am trying to make a keyboard heatmap which shows various colors for frequency of keys and now after exploring libraries like matplotlib and seaborn I am not getting how to make the heatmap on .Png image of a 104 key layout. I have already created a keylogger and am able to record all the keys in a .txt file where normal keys are stored in char form, but special keys are stored in form like Keys.Space, Keys.LCtrl etc. and now I want to plot the frequency of keys on a keyboard heatmap. I dont want to use libraries like tapmap and kbhmap as they just take .txt file as input and return png of keyboard heatmap but this way I would not be able to show usage of ctrl, shift and backspaces. What should I do?

This is my code for keylogger.

from pynput.keyboard import Key
from pynput.keyboard import Listener
the_keys = [] 
def functionPerKey(key):  
    the_keys.append(key)  
    storeKeysToFile(the_keys)

def storeKeysToFile(keys):
    with open('keylog.txt', 'w') as log:
        for the_key in keys:
            the_key = str(the_key).replace("'", "")
            log.write(the_key+'\n')
def onEachKeyRelease(the_key):
    if the_key == Key.esc:
        return False
with Listener(
    on_press = functionPerKey,
    on_release = onEachKeyRelease
) as the_listener:
    the_listener.join()```
1

There are 1 best solutions below

0
On

You can use keyboardlayout to display a keyboard and matplotlib.cm.ScalarMappable to map colors to keystroke counts (assuming you already have a counter of keystrokes):

import tkinter as tk
import tkinter.font as tkf

import keyboardlayout as kl
import keyboardlayout.tkinter as klt

import matplotlib
from matplotlib import cm

from random import randrange

# generating key Counter
counter = {k.name: randrange(20, 120000) for k in kl.Key if not k.name.endswith('_UPPER')}
# mapping colors:
norm = matplotlib.colors.Normalize(vmin=min(counter.values()), vmax=max(counter.values()))
mapper = cm.ScalarMappable(norm=norm, cmap=cm.YlGnBu)

key_size = 60

window = tk.Tk()
window.resizable(False, False)

# common options for keys
key_info_dict = {
    "margin": 5,
    "txt_color": "black",
    "txt_font": tkf.Font(family='Arial'),
    "txt_padding": (key_size//6, key_size//10)
}

keyboard_layout = klt.KeyboardLayout(
    kl.LayoutName.QWERTY,
    kl.KeyboardInfo(position=(0,0), padding=2),
    (key_size, key_size),  # width, height,
    kl.KeyInfo(**key_info_dict, color="grey"),
    master=window
)

# converting rgba to hex string, e.g.: (0, 0, 255, 1) to #0000FF
def rgba_int_to_hex(rgba):
    hex_vals = map(lambda x: hex(int(255*x))[2:].zfill(2), rgba[:-1])
    return "#" + ''.join(hex_vals)

# coloring each key individually
for k, v in counter.items():
    keyboard_layout.update_key(key=getattr(kl.Key, k), 
                            key_info=kl.KeyInfo(**key_info_dict, 
                                            color=rgba_int_to_hex(mapper.to_rgba(v))))

window.mainloop()

Output (keystrokes are fully randomized in my case so this map isn't realistic at all):

enter image description here