I'm writing a stenography like script, such that, when you press specific combination of keys on your keyboard such as "ASDF" it would translate to a word and type out the word instead of your key presses. However I cannot find a way to override key presses such that programs such as Notepad will ignore me typing "ASDF".
My only current solution to this has been to have my script backspace the characters that were typed, then paste the word that was intended to be typed.
Here is my script thus far:
import ctypes
def main():
GetAsyncKeyState = ctypes.windll.user32.GetAsyncKeyState
key_states = [0] * 26
pressed_keys = [0] * 26
chord = ''
while True:
for k in range(65,91):
key_states[k-65] = GetAsyncKeyState(k)
if GetAsyncKeyState(k): pressed_keys[k-65] = 1
if sum(key_states) == 0:
for k in range(26):
if pressed_keys[k] == 1:
chord += chr(k+65)
if chord != '': write(chord)
chord = ''
pressed_keys = [0] * 26
dictionary = open('dictionary.txt','r').read()
entries = dictionary.split('\n')
chords = [[0,0]]*len(entries)
for e in range(len(entries)):
s = entries[e].split('-')
chords[e] = [s[0],s[1]]
def write(chord):
found = 0
for c in chords:
if chord==c[0]:
found = 1
_type(c[1])
if not found:
_type(chord)
def _type(word):
'''
This is where the code would go...
'''
main()
The expected results would be that none of the characters I'm typing would show up until the script pastes the final word. But instead, my characters that I'm pressing to form the word show up first.
My plan would be to override the keys to do nothing.
I.E. when I pressed "e" nothing would occur.
Related
I am messing around with the blessed library, and I found this basic text editor program. When I run it in my terminal, all of the keys register except for backspace and delete. Inside the program is a function that checks the key inputs:
def readline(term, width=20):
"""A rudimentary readline implementation."""
text = u''
while True:
inp = term.inkey()
if inp.code == term.KEY_ENTER:
break
elif inp.code == term.KEY_ESCAPE or inp == chr(3):
text = None
break
elif not inp.is_sequence and len(text) < width:
text += inp
echo(inp)
elif inp.code in (term.KEY_BACKSPACE, term.KEY_DELETE):
text = text[:-1]
# https://utcc.utoronto.ca/~cks/space/blog/unix/HowUnixBackspaces
#
# "When you hit backspace, the kernel tty line discipline rubs out
# your previous character by printing (in the simple case)
# Ctrl-H, a space, and then another Ctrl-H."
echo(u'\b \b')
return text
Which includes KEY_BACKSPACE and KEY_DELETE. I checked the documentation and ran a program to check the keys myself, and those are the correct names on my device. I am just unsure why all the other keys work except for those? I am on Windows 10 using the default CMD and Python 3.10 if that changes anything.
Thanks!
The code you've pasted in your question is for saving to a file. If you try using backspace when entering the file name, you'll see that it works.
You can find this in the main loop under the logic for Ctrl + S. Notice also that there is no logic here for BACKSPACE or DELETE.
def main():
...
while True:
...
inp = term.inkey()
if inp == chr(3):
# ^c exits
break
elif inp == chr(19):
# ^s saves
...
save(screen, readline(term))
...
continue
...
else:
...
...
Basically the headline.
In Python, I want to take max 280 characters of input from the user, and show a live updating counter on the CLI as the user types the input.(Similar to a Progress bar)
Getting some text to update on the screen is simple, but I don't know how to count the characters as the user is inputting them.
P.S. First-time StackOverflow user, please go easy on me. :)
EDIT:
Codebase: https://github.com/Prathamesh-Ghatole/100DaysOfCode-Writer/blob/master/main.py
I don't have a specific code snippet where I want to implement it yet.
But I basically want to take character input from the user in a loop where each iteration does the following:
Take single character input.
update a variable that counts the total number of input characters.
subtract the number of input characters from the character number limit.
Trigger a flag when the character limit is exceeded.
Using pynput package this seems to work.
from pynput.keyboard import Key, Listener
import os
length = 0
char_count = dict()
text = str()
def on_press(key):
try:
global text
global char_count
global length
if length >= 280:
print("[+] Character Limit Excided!")
return False
elif key == Key.enter:
return False
else:
os.system("cls")
if key == Key.space:
text += ' '
else:
text += f"{key.char}"
char_count[text[-1]] = char_count.get(text[-1], 0) + 1
length += 1
print(f"Enter Text: {text}")
print(f"Characters Left: {280 - length}")
print(f"Char Count {char_count}")
except:
exit()
def main():
os.system("cls")
with Listener(on_press=on_press) as listner:
print("Enter Text: ")
listner.join()
if __name__ == '__main__':
main()
I am working on making a function which does auto completion based on keystrokes.
Like, in google.com when I hit 'a' in search bar, it shows the related search words such as amazon, amazon prime, airbnb...
I am trying make this function using Python and my CSV file based on detecting keystrokes.
There are some words in the CSV file such as Behavior, Building, Chemistry, History, Manufacturing, Mathematics.
The structure of my code consists of
while # infinitely looping in order to keep detecting keystrokes
for word in data
for char in range(numOfKeyStrokes)
The problem is, when I hit 'c', it is supposed to print out chemistry and it works great.
But when I hit 'h' after I already hit 'c', there is no response.
I want to make this printing out "chemistry" again.
I think when I hit 'h', the compiler doesn't go into "for word in data" statement but I don't know why.
There are some junk print outs in order to detect where the problem is.
Here is my code. Can someone help my problem?
import keyboard
import csv
import time
global numOfKeyStrokes #In order to compare each elemtn's letter one by one with keystroke
numOfKeyStrokes = 0
def keyStroke():
temp = keyboard.read_key()
time.sleep(0.1)
global numOfKeyStrokes
numOfKeyStrokes += 1
return temp
def init():
f = open('./DataBase.csv')
data = csv.reader(f)
getKeyStroke = []
matchingFlag = False
while True: # looping in order to keep getting keystrokes
global numOfKeyStrokes
getKeyStroke.append(keyStroke())
print(getKeyStroke)
print("numOfKeyStrokes ", numOfKeyStrokes)
for word in data: # each row is an each cell in a csv file
matchingFlag = False
for char in range(numOfKeyStrokes): # each x is an each letter in an each cell
print("word[9][char]==getKeyStroke[numOfKeyStrokes-1]", word[9] [char].lower(),",",getKeyStroke[numOfKeyStrokes-1])
if word[9][char].lower() == getKeyStroke[numOfKeyStrokes-1]:
print("char matched")
matchingFlag = True
break
else:
matchingFlag = False
break
if matchingFlag == True : print(word[9])
f.close()
init()
The reason your code only works one time is because you open the csv file once at the beginning of your init function.
When you pass it to the csv.reader and iterate over the entire file, you consume the resource. When you go for the next iteration the file/reader is empty and so your for word in data loop will not run.
I've refactored your program rather significantly, so I don't necessarily know if this still achieves your desired behaviour, especially without knowing exactly how your csv is setup, but I think you were looking for something like:
import csv
import time
import keyboard
def key_stroke_gen():
num_of_key_strokes = 0
while True:
num_of_key_strokes += 1
yield num_of_key_strokes, keyboard.read_key()
time.sleep(0.1)
def init():
get_key_stroke = []
words = []
with open('./DataBase.csv') as f:
data = csv.reader(f)
for row in data:
for word in row:
words.append(word.strip().lower())
for num_of_key_strokes, key_stroke in key_stroke_gen():
get_key_stroke.append(key_stroke)
for word in words:
if word[:num_of_key_strokes] == ''.join(get_key_stroke):
print(word)
if __name__ == '__main__':
init()
Generating the search_str directly in the generator might be a better approach overall, since it's easier to manage the building of the search string in one place and have the processing code separate.
import csv
import time
import keyboard
def search_strs():
search_str = ""
while True:
time.sleep(0.1)
key_press = keyboard.read_key()
if key_press == "backspace" and search_str:
search_str = search_str[:-1]
elif len(key_press) == 1 and ('a' <= key_press <= 'z'):
search_str += keyboard.read_key()
else:
continue
yield search_str
def init():
words = []
with open('./DataBase.csv') as f:
data = csv.reader(f)
for row in data:
for word in row:
words.append(word.strip().lower())
for search_str in search_strs():
for word in words:
if word[:len(search_str)] == search_str:
print(word)
if __name__ == '__main__':
init()
I am trying to control 2 servos from my pca9685 which is connected to my raspberry pi. I have written code that works with key inputs like I want, but I am only able to use one key input, and then I don’t get a response after the first key input. Any idea on how to fix the issue?
import time
import adafruit_servokit import ServoKit
kit = ServoKit(channels=8)
key = input()
angle = 0
while angle <= 100:
if key == "a":
kit.servo[0].angle = 100
time.sleep(1)
elif key = "aa":
kit.servo[0].angle = 0
time.sleep(1)
I guess the problem is with the key assignment 'a' and 'aa', if you can change the 'aa' with some other key input i guess it will work, because when using the input() stream it processes the stream character by character so "aa" will be an equivalent of 'a' + 'a', hence you are facing this issue
The issue was that my key = input() was outside of the while loop. By having it outside of the loop, it was only being called once.
import time
import adafruit_servokit import ServoKit
kit = ServoKit(channels=8)
angle = 0
while angle <= 100:
key = input()
if key == "a":
kit.servo[0].angle = 100
time.sleep(1)
elif key = "aa":
kit.servo[0].angle = 0
time.sleep(1)
I am running Python 3.8 (Also tested on 2.7). Attached below is code to a keylogger that I created with reference to a video tutorial as I'm fairly new to Python and trying to learn. I am trying to make it where when the space key is pressed, it writes a new line to the file so it tabs down and looks nicer. I've tried a few different things online that I've found however nothing has fixed it. If someone could help me and explain why this doesn't work it would be much appreciated. Thanks and have a great week
# Define imports
import pynput
from pynput.keyboard import Key, Listener
# Define variables for keylogger
count = 0
keys = []
# Function to detect key presses
def on_press(key):
global count, keys
keys.append(key)
count += 1
print(str(key))
if count >= 1:
write_file(str(keys))
keys = []
count = 0
# Function to write the letters to a file
def write_file(keys):
with open("log_test.txt", "a") as f:
for key in keys:
k = str(key).replace("'", "").replace("u", "").replace("]", "").replace(",", "").replace("[", "")
if k.find("space") >= 0: # This is the code to check for space bar press
f.write('\n')
else:
k.find("Key") == -1
f.write(k)
# Detect when a key is released
def on_release(key):
if key == Key.esc:
return False
with Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
That's because your "k" is not "space", but "s", "p", "a", "c", "e".
Not the most elegant method, but try this:
def on_press(key):
global count, keys
keys.append(key)
count += 1
if count >= 1:
write_file(keys) # don't convert to string here
keys = []
count = 0
def write_file(key):
with open("log_test.txt", "a") as f:
if str(key).find("space") >= 0: # transform to string to find what you want
f.write('\n')
elif str(key).find("Key") == -1: # transform to string to find what you want
# key will come as a list, like this: ['char']
# take the first (and only) element, and it will be like this: 'char'
# then remove the "'" and you'll have your character
key = str(key[0]).replace("'", '') # take only the character, then save it
f.write(key)
When you are checking for space, do this:
if k.find(" ") >= 0: # use plain space " " and not "space"
f.write('\n')