Created
October 18, 2020 21:25
-
-
Save wilfreddv/ae344b111cd61089855c101af6c38ed5 to your computer and use it in GitHub Desktop.
Record and visualize keyboard and mouse
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FPS = 20 | |
#ISIZE = 1280, 720 | |
ISIZE = 1920, 1080 | |
TRAIL_FADE = 0.93 # 1.0 - no fade, 0.0 - immediate fade | |
GAMMA = 0.1 | |
RADIUS_F = 30 | |
DEVIATION = 45 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pynput import keyboard, mouse | |
from config import * | |
from collections import OrderedDict | |
import time | |
import sys, os | |
if len(sys.argv) != 2: | |
print(f"Usage: {sys.argv[0]} OUTFILE") | |
sys.exit() | |
outputFile = sys.argv[1] | |
if outputFile[-4:] != ".csv": | |
outputFile += ".csv" | |
if os.path.isfile(outputFile): | |
answer = input(f"File {outputFile} already exists. Continue anyway? [Y/n]") | |
if answer.lower() == 'n': | |
sys.exit() | |
frame = OrderedDict([ | |
("w", 0), | |
("a", 0), | |
("s", 0), | |
("d", 0), | |
("shift", 0), | |
("space", 0), | |
("lmb", 0), | |
("rmb", 0), | |
("mouseX", 0), | |
("mouseY", 0), | |
]) | |
def on_press(key): | |
try: | |
if key.char == 'w': | |
frame['w'] = 1 | |
elif key.char == 'a': | |
frame['a'] = 1 | |
elif key.char == 's': | |
frame['s'] = 1 | |
elif key.char == 'd': | |
frame['d'] = 1 | |
except AttributeError: | |
if key == keyboard.Key.shift: | |
frame['shift'] = 1 | |
elif key == keyboard.Key.space: | |
frame['space'] = 1 | |
def on_release(key): | |
try: | |
if key.char == 'w': | |
frame['w'] = 0 | |
elif key.char == 'a': | |
frame['a'] = 0 | |
elif key.char == 's': | |
frame['s'] = 0 | |
elif key.char == 'd': | |
frame['d'] = 0 | |
except AttributeError: | |
if key == keyboard.Key.shift: | |
frame['shift'] = 0 | |
elif key == keyboard.Key.space: | |
frame['space'] = 0 | |
def on_click(x, y, button, pressed): | |
if button == mouse.Button.left: | |
frame['lmb'] = int(pressed) | |
elif button == mouse.Button.right: | |
frame['rmb'] = int(pressed) | |
keyboardListener = keyboard.Listener(on_press=on_press, on_release=on_release) | |
keyboardListener.start() | |
mouseListener = mouse.Listener(on_click=on_click) | |
mouseListener.start() | |
print("Recording...") | |
mouseController = mouse.Controller() | |
with open(outputFile, "w") as f: | |
f.write(",".join(frame.keys()) + "\n") | |
try: | |
while True: | |
frame['mouseX'], frame['mouseY'] = mouseController.position | |
f.write(",".join(str(v) for v in frame.values()) + "\n") | |
time.sleep(1/FPS) | |
except KeyboardInterrupt: | |
exit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cv2 | |
import numpy as np | |
import sys | |
import csv | |
from config import * | |
if len(sys.argv) < 2: | |
print(f"Usage: {sys.argv[0]} FILENAME") | |
sys.exit() | |
try: | |
with open(sys.argv[1], "r") as f: | |
reader = csv.reader(f, delimiter=",") | |
dataFrames = [] | |
# Skip column names | |
# w a s d shift lmb rmb mousex mousey | |
headerRow = next(reader) | |
for row in reader: | |
dataFrames.append(list(map(int, row))) | |
except FileNotFoundError: | |
print(f"File {sys.argv[1]} not found.") | |
sys.exit() | |
rowIndices = {} | |
for idx, key in enumerate(headerRow): | |
rowIndices[key] = idx | |
getValue = lambda row, key: row[rowIndices[key]] | |
xTranslate = ISIZE[0] / 1920 | |
yTranslate = ISIZE[1] / 1080 | |
filename = sys.argv[1][:-4]+".mp4" | |
fourcc = cv2.VideoWriter_fourcc(*'mp4v') | |
videoWriter = cv2.VideoWriter(filename, fourcc, FPS, ISIZE) | |
image = np.zeros((ISIZE[1], ISIZE[0], 3), np.uint8) | |
mask = np.zeros((ISIZE[1], ISIZE[0], 3), np.uint8) | |
for idx, row in enumerate(dataFrames): | |
sys.stdout.write(f"\rProcessing frame: {idx+1}/{len(dataFrames)}") | |
sys.stdout.flush() | |
image = cv2.addWeighted(image, TRAIL_FADE, mask, 1.0, GAMMA) | |
x = int(getValue(row, 'mouseX')*xTranslate) - RADIUS_F | |
y = int(getValue(row, 'mouseY')*yTranslate) - RADIUS_F | |
w,a,s,d = getValue(row, 'w'), getValue(row, 'a'), getValue(row, 's'), getValue(row, 'd'), | |
pts = np.array([[x, y+RADIUS_F+(w*DEVIATION)], # w | |
[x-RADIUS_F-(a*DEVIATION), y], # a | |
[x, y-RADIUS_F-(s*DEVIATION)], # s | |
[x+RADIUS_F+(d*DEVIATION), y]], | |
np.int32) # d | |
pts = pts.reshape((-1, 1, 2)) | |
color = (20,20,200) if getValue(row, 'lmb') else (255,20,0) | |
color = color if not getValue(row, 'shift') else (color[0], color[1]+130, color[2]) | |
color = color if not getValue(row, 'space') else (color[0], color[1]+100, color[2]) | |
image = cv2.fillPoly(image, [pts], color) | |
# cv2.circle(image, (x, y), radius, color, -1) | |
videoWriter.write(image) | |
videoWriter.release() | |
print("\nDone.") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
what the f