pynput keyboard listener does not detect keys on Mac OS X - python-3.x

I am using pynput to record keystrokes via Listener on OS X Mojave. I am using Pycharm as my IDE for running the code.
I was not able to get it to work using the same example from the pynput site.
from pynput.keyboard import Listener as key_listener
class recorder:
def on_press(self, key):
print(key)
def on_release(self, key):
print(key)
if __name__ == "__main__":
testme = recorder()
with key_listener(on_press=testme.on_press, on_release=testme.on_release) as listener:
listener.join()
I did step through it and I get no errors (unless I put the with statement in a function, instead of in the main, but that's a known issue with threading in Mojave, from what I can tell after searching for that error), but everything stops at the .join() statement, and I get nothing printed when I press and release a key on my keyboard.

This is probably a bit late, but the answer is to go into:
Settings -> Security & Privacy
Click on the Privacy tab
Click the + Hold down CMD + SHIFT + . (so that you can see hidden
files/folders)
Navigate to /usr/local/bin or wherever you have Python installed
Click okay.
That should do it.
Note
If you try to run your app via the terminal, you will need to add the terminal.app to the list of allowed apps, as done above for Python.

Found the problem.
For some strange reasons; OSX is uber-picky about returning events, so unless you go in the security settings and enable Pycharm to be in the list of apps that are allowed to use accessibility, it won't work.
I didn't try on Windows yet, but I assume it will be the same issue. The only gripe I have is that I have no idea how to add Python itself to the list of supported accessibility apps; since the control panel does not allow me to go in /usr/local/bin, which is where I have Python3 installed (via Brew).

This is probably a bit late too, but the simple answer is to go into:
Preference
Security & Privacy
Input Monitoring
-> confirm PyCharm

Some people have stated that adding IDLE to supported accessibility apps is what allows python itself to run the listener.
while your in a finder window, if you press cmd+shft+'.' (period key) it will show hidden files, which will allow you to navigate to usr/local/bin and look for your python implementation.
On windows this is slightly different, I always run python/pycharm as admin and it never gives me any issues.

Try superuser ($sudo su) and run your python code in terminal, I think
it should work
Im was working with OSX 10.12 and pynput was only getting cmd ctrl fn and option keys when pressed but now in superuser it gets the keys.

Related

root.deiconify(), trying to pick up a minimalized app. tkinter in python3

Part of the script responsible for minimalizing works just fine, point is, when I want to restore the window it doesnt work. I guess it's because the keyboard input is not sent into my app anymore. Can I fix that somehow? I use Ubuntu. How do I make the app wait for my shortcut no matter where in the system I am at the moment? I would like to make it work, even when I'm on my browser for example.
def minimize(event):
root.wm_state("iconic") # minimize the window
def restore_window(event):
root.deiconify()
root.bind("<Control-z>", minimize)
root.bind("<F11>", restore_window)
I dont know, maybe I should use a different package than tkinter for that kind of software.

Move Window to second Screen

I want to move the currently active window to a different monitor (left or right) with Python.
The shortcut on Windows for this is usually WIN + shift + arrow key [left|right]. I tried it with a bunch of libraries, but none of them do the trick somehow.
I tried pyautogui:
pyautogui.hotkeys('shift', 'win', 'left')
The longer solution doesn't work either
pyautogui.keyDown('shift')
pyautogui.keyDown('win')
pyautogui.press('left')
pyautogui.keyUp('shift')
pyautogui.keyUp('win')
Neither does any combination of different buttons like as "winleft" or "shiftright" and such.
Changing the order of the shift and win key does also nothing more for me.
All it does is move the window to the edge of the screen (similar to WIN + left).
Then I started testing other libraries, such as pynput:
hotkey = keyboard.HotKey(
keyboard.HotKey.parse('<shift>+<cmd>+<left>'),
None
)
This one seems to be for monitoring purposes, tho.
After that, I discovered win32gui (and win32api). This one has next to no documentation that is actually helpful for anything (imho).
Does anyone know why pyautogui does not properly execute this specific shortcut and how to make it do it? Or does anyone know how to execute that shortcut in a different way?
It seems like pyautogui doesn't support this functionality for some reason. I managed to move the window with pynput, though, like this:
from pynput.keyboard import Key, Controller
keyboard = Controller()
keyboard.press(Key.cmd)
keyboard.press(Key.shift)
keyboard.press(Key.left)
keyboard.release(Key.cmd)
keyboard.release(Key.shift)
keyboard.release(Key.left)

pyautogui on Container can't Control Mouse

I'm trying to automate mouse and keyboard using pyautogui on linux container on my chromebook (official linux support) however, the mouse and keyboard are not responding to any function (moving, clicking, pressing keys ....) yet something like pyautogui.alert('This is the message to display.') works and pop up a window.
Is there anyway to make it work on the container?
It has been more than a year since this question was asked, and there still doesn't seem to be any answer... I can confirm that this pyautogui problem still exists. One clue, perhaps, is the error message produced if an attempt is made to run under sudo like this:
sudo idle [python program that controls mouse]
This generates the error message:
_tkinter.TclError: couldn't connect to display ":0"
Some folks seemed to suggest that an appropriate EXPORT statement might help this problem, but I couldn't determine the exact details...
I really hope there is some solution/workaround for this problem since manipulating the mouse & keyboard is critical in many applications!

Inconsistent Imagesnap behavior taking pictures on MacOS X, depending on calling environment

EDITED POST
When I first wrote this, I was mystified by the varied behaviors of the "imagesnap" USB cam image capture program on MacOS. Sometimes it took pictures and sometimes it didn't, and this seemed to vary with the environment where it was called: such as directly in a Terminal window, in a shell program, in a Python program running in the Terminal, in a Python program running in the Pycharm IDE, called with os.popen(), subprocess.run(), subprocess.call(), subprocess.popen(), etc.
Sometimes imagesnap would work just fine and take images, and sometimes it would fail silently. I was really having a hard time figuring out why the behaviors were varied, and how to get picture taking using imagesnap on my mac to work reliably when called from a Python program.
I searched on keywords like MacOS, Catalina, imagesnap, USB camera, webcam, Python, PyCharm IDE, shell command, os.popen(), subprocess.run(), subprocess.call(), subprocess.Popen(), and more. I did not find the solution anywhere, and I didn't get an answer here.
I've finally understood the problem better, and that's why I've rewritten this question.
What's behind the inconsistent behavior of imagesnap when called from different environments, and how can I call it from a Linux program and get it to reliably take pictures?
I now understand that MacOS X's privacy settings in System Preferences control which environments are allowed or silently denied to access USB cameras.
For more detail, and a workaround, see my own answer below. I hope that others who understand the issues even more will add improved answers.
ORIGINAL POST:
Below is a simple Python test program. It uses os.popen() and
captures an image from a selected USB webcam using imagesnap -d and
saves an image in image.jpg.
But the imagesnap -d command behaves differently when running in the
PyCharm environment, returning a blank response (' ') and failing to save the requested image.
Submitting this same code WITHIN PyCharm's terminal window fails in
exactly the same way.
But when the same python commands are submitted to the terminal
outside Pycharm, the program takes the image successfully and reports back as shown in the output below.
I'm running Mac OS X Catalina, and using PyCharm 2019.2.3
Community Edition for development. Python version is 3.7.4
Sample code:
import os
return_string = os.popen("imagesnap -d 'DEVICE_NAME' 'image.jpg'").read()
print("'",return_string,"'")
Within the PyCharm development environment this program returns the following and does not create the jpg file:
/Users/mcgregor94086/PycharmProjects/SonaScannerGUI/venv/bin/python
/Users/mcgregor94086/Library/Preferences/PyCharmCE2019.2/scratches/scratch_5.py
' '
Process finished with exit code 0
Outside PyCharm this same code returns:
$ python3
Python 3.7.4 (v3.7.4:e09359112e, Jul 8 2019, 14:54:52)
[Clang 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> return_string = os.popen("imagesnap -d 'DEVICE_NAME' 'image.jpg'").read()
>>> print("'",return_string,"'")
' Capturing image from device "<AVCaptureDALDevice: 0x7fa9bc203330 [DEVICE_NAME][0x141717501bcf0b09]>"... '
>>>
After digging into this problem a great deal, and without any responses, I started to search the web more broadly for answers. And although I found almost no information on the web to guide me what was happening, I now believe that I know what is preventing me from taking pictures programmatically within a python program. I also believe that I now have a reasonable hypothesis as to why I am seeing the results I was seeing.
I have a work around that is currently working, but which I fear may not in the future.
The believe the problem has to do with MacOS and I believe it may vary with the specific release of MacOS. I am currently using MacOS X 10.15.1 Catalina. earlier MacOS X releases might not be as strict.
In the Catalina release at a minimum, ANY connected USB Camera is considered a special device governed by special security, and management of access to the camera device is controlled in the Systems Preferences -> Security & Privacy panel.
When you click the Camera row in the menu on the left of the panel you will see a checkbox list of apps which are allowed to programmatically access you camera. If you unlock the page (lower left), you can change which apps are allowed to access the camera by checking or unchecking them in the list.
On the machines I have available, there is a list of 4 apps in this panel: Terminal, UberConference, Google Chrome, Skype.
The list of available apps varies for other resources, such as Contacts, Calendars, Accessibility, Full Disk Access, etc.
Some of these resources (such as Accessibility and Full Disk Access) selection lists have a pair of "+|-" buttons below the app list that allow you to add, or permanently remove, apps from accessing that resource.
But Camera. Microphone and some other resource do not have such a pair of buttons, and for these devices, the list appear unchangeable by the user.
The panel suggests that the apps get on the list by "requesting access" to the camera, but I have not found an explanation anywhere on line about how to add an app to this access list.
One of the predefined apps in the list is "Terminal". That was checked, so when I ran imagesnap from within a terminal window the program had the necessary privacy privileges and the camera took pictures just fine.
In contrast, when I tried to run a python program within the PyCharm IDE, the PyCharm IDE did not identify itself as a terminal and the request silently failed.
Python has a number of different ways to launch an independent program such as imagesnap. These methods include os.popen(), subprocess.run() and subprocess.Popen(). Some of these methods are deprecated, so we can't rely on them working in the future. Other methods() have additional options which control whether a new "shell" is created or not, and these may complicate determining what environment the app will see.
I found it confusing to try to predict which of these python methods
would succeed in opening the camera and which would not, as well as
their behavior when run inside the IDE vs. in a terminal window.
Perhaps someone else can compile such a table.
Work around: For the present, I was able to work around this problem by using os.popen, by having it open a new terminal with an initial string. This seems to ensure that Apple security sees the parent as the "Terminal" app which we specifically authorized in the control panel.
I then found
os.popen("open -a Terminal.app imagesnap.sh")
worked.
While this work around is working for me at present, I was not happy about using os.popen() instead of one of the subprocess methods, as I worry it may be deprecated. Second, this worked with a shell script ("imagesnap.sh") but I have not figured out how to pass parameters or run executables.
Perhaps a knowledgable reader can help with better suggestions.

Clear PyCharm Run Window

Is there a way to clear the "Run" console in PyCharm?
I want a code that delete/hide all the print() made previously.
Like the "clear_all" button, but without having to press it manually.
I have read that there is a way to do it in a terminal with os.system("cls"), but in PyCharm, it only adds a small square without clearing anything.
Also, I don't want to use print("\n" *100) since I don't want to be able to scroll back and see the previous prints.
In Pycharm:
CMD + , (or Pycharm preferences);
Search: "clear all";
Double click -> Add keyboard shortcut (set it to CTRL + L or anything)
Enjoy this new hot key in your Pycharm console!
Pycharm Community Edition 2020.1.3
You can right click anywhere above the current line on the console, and choose the "Clear All" option. It'll clear the console
How to
Download this package https://github.com/asweigart/pyautogui. It allows python to send key strokes.
You may have to install some other packages first
If you are installing PyAutoGUI from PyPI using pip:
Windows has no dependencies. The Win32 extensions do not need to be
installed.
OS X needs the pyobjc-core and pyobjc module installed (in that
order).
Linux needs the python3-xlib (or python-xlib for Python 2) module
installed.
Pillow needs to be installed, and on Linux you may need to install additional libraries to make sure Pillow's PNG/JPEG works correctly. See:
Set a keyboard shortcut for clearing the run window in pycharm as explained by Taylan Aydinli
CMD + , (or Pycharm preferences);
Search: "clear all"; Double click ->
Add keyboard shortcut (set it to CTRL + L or anything)
Enjoy this new hot key in your Pycharm console!
Then if you set the keyboard shortcut for 'clear all' to Command + L use this in your python script
import pyautogui
pyautogui.hotkey('command', 'l')
Example program
This will clear the screen after the user types an input.
If you aren't focused on the tool window then your clear hot-key won't work, you can see this for yourself if you try pressing your hot-key while focused on, say, the editor, you won't clear the embedded terminals contents.
PyAutoGUI has no way of focusing on windows directly, to solve this you can try to find the coordinate where the run terminal is located and then send a left click to focus, if you don't already know the coordinates where you can click your mouse you can find it out with the following code:
import pyautogui
from time import sleep
sleep(2)
print(pyautogui.position())
An example of output:
(2799, 575)
and now the actual code:
import pyautogui
while True:
input_1 = input("?")
print(input_1)
pyautogui.click(x=2799, y=575)
pyautogui.hotkey('command', 'l')
Easy Method:
Shortcut: Control K,
Right click on terminal and clear Buffer
There's also another way of doing it using the system class from os. All you need to do is have this code:
from os import system, name
# define our clear function
def clear():
# for windows the name is 'nt'
if name == 'nt':
_ = system('cls')
# and for mac and linux, the os.name is 'posix'
else:
_ = system('clear')
# Then, whenever you want to clear the screen, just use this clear function as:
clear()
However, in order for this functionality to work in pycharm, you need to enable "Emulate terminal in output console". You can find this under edit configuration of the file where you want to use the clear function, then it's under Execution option. Here's a screenshot: pycharm screensho
You could just do a ("\n" * 100000000), so it'll be impossible to scroll back.
In PyCharm terminal you can type 'cls' just like in linux terminal.
For Python Console (where you see the output) assign a shortkey for "clear all" in File -> Settings -> Keymap -> Other -> "Clear all"
You can also click somewhere on the PythonConsole -> Right button -> clear.
Hope it helps
I just relised that instead of going to the trouble of setting up a shortcut, you could just set up a command using PyAutoGUI to click on the trash bin on the side of the window e.g
note, to install pyautogui click on the end of the import pyautogui line, then press alt+enter and click install pyautogui.
import pyautogui
# to find the coordinates of the bin...
from time import sleep
sleep(2) # hover your mouse over bin in this time
mousepos = pyautogui.position() gets current pos of mouse
x,y = mousepos # storing mouse position
print(mousepos) # prints current pos of mouse
# then to clear it;
pyautogui.click(x, y) # and just put this line of code wherever you want to clear it
(this isn't perfect thanks to the time it takes to run the code and using the mouse, but it is reasonable solution depending on what you are using it for.)
I hope this answer is helpful even though this is an old question.
Just click the trash can icon to the left of the command window and it clears the command history!
In PyCharm 2019.3.3 you can right click and select "Clear All" button.This is deleting all written data inside of the console and unfortunately this is manual.
Sorry to say this, here the main question is how to do it programmatically means while my code is running I want my code to clear previous data and at some stage and then continue running the code. It should work like reset button.
After spending some time on research I solved my problem using Mahak Khurmi's solution https://stackoverflow.com/a/67543234/16878188.
If you edit the run configuration you can enable "emulate terminal in output console" and you can use the os.system("cls") line and it will work normally.
Iconman had the easiest answer.
But simply printing "\n" * 20 (or whatever your terminal height is) will clear the screen, and the only difference is that the cursor is at the bottom.
I came here because I wanted to visually see how long each step of a complex process was taking (I'm implementing a progress bar), and the terminal is already full of scrolling logging information.
I ended up printing ("A" * 40) * 20, and then "B" and "C" etc., and then filming it. Reviewing the video made it easy to see how many seconds each step took. Yes I know I could use time-stamps, but this was fun!

Resources