Simulate horizontal scroll in Windows with python - python

as the title says, I'm looking for a way to simulate horizontal scrolling (specifically in OneNote). I know it is possible to do it in AutoHotKey with a script, but I'm trying to keep the program as localized as possible. I also know it is possible with PyAutoGui on mac and linux, but I've come up empty handed with anything related to windows. If you have any leads, I would greatly appreciate it:)

For anyone running into a similar problem in the future, here's my solution:
import win32api, time, pyautogui as pag, keyboard
from win32con import *
running = True
lastX, lastY = pag.position()
while running:
while keyboard.is_pressed("shift"):
x, y = pag.position()
if lastX!=x:
win32api.mouse_event(MOUSEEVENTF_HWHEEL, 0, 0, x-lastX, 0) # Horizontal scrolling
lastX=x
if lastY!=y:
win32api.mouse_event(MOUSEEVENTF_WHEEL, 0, 0, lastY-y, 0) # Vertical scrolling
lastY=y
Hope this can help anyone in the future:)

Windows 10 already has an out-of-the-box shortcut for horizontal scroll:
Hold Shift down and use the mouse wheel for side scroll. (This shortcut seems to also work on Ubuntu und MacOS)
Considering this shortcut exists it is possible to emulate it with PyAutoGui like so
import pyautogui
offset = 100
pyautogui.keyDown('shift')
pyautogui.scroll(offset)
pyautogui.keyUp('shift')

Related

Python; "simulate" mouse and keyboard

I recently started learning Python, trying to make short programs with simple functions but that I can use in one way or another while learning.
I have studied a bit several libraries that they functions are what the title say, with some I have had better experiences than with others, but at the moment I have a problem when trying to make a "Shift+Click" in concrete positions of the screen.
Im actually using win32api and win32con since they are the ones that to my way of seeing have better results for what Im trying to do.
Its nothing very complicated, its just do a Shift + Left Click in specific positions, like same way that you can recreate it in a normally with your mouse and keyboard.
Here is a simplified version of the code:
def mouse_click(x, y):
win32api.SetCursorPos((x, y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x, y, 0, 0)
time.sleep(0.065)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x, y, 0, 0)
def shift_down():
win32api.keybd_event(win32con.VK_LSHIFT, 0, 0, 0)
time.sleep(0.005)
def shift_up():
win32api.keybd_event(win32con.VK_LSHIFT, 0, win32con.KEYEVENTF_KEYUP, 0)
time.sleep(0.005)
def clicks():
for offs in coord:
x, y = offs
x += random.randint(-15, 15)
y += random.randint(-15, 15)
if random.random() > 0.0:
shift_down()
time.sleep(0.005)
mouse_click(x, y)
time.sleep(0.005)
shift_up()
print('click on', offs)
def main():
while True:
if win32api.GetAsyncKeyState(win32con.VK_INSERT):
break
elif win32api.GetAsyncKeyState(win32con.VK_F2):
clicks()
print('clicking end')
if __name__ == '__main__':
main()
Yes, Im aware that some sleep are unnecessary, but here is my current problem. The way you see above is the best way I have had the code respond correctly and in time according to my needs.if I low the time on mouse_click below 0.55 some clicks start to be ignored, from what I have read and seen it should not be necessary make pauses, but at the moment this is the solution I found.So I want to fix the basic formatting of it first.
Am I missing something or is it some kind of "optimization" problem?
Any hints or improvements are welcome even if its about using another library.
I would recommend using the PyAutoGUI module available here: https://pyautogui.readthedocs.io/
It is very beginner friendly and very easy to use!
You would perform a shift-click like this:
import pyautogui
pyautogui.keyDown('shift')
pyautogui.click()
pyautogui.keyUp('shift')
Somehow these randoms sleep are no longer necessary, and the sleep in mouse_click() I could lower it to a maximum of 0.06 without problems.
The press and release Shift seems to work fine in other applications, so I deduce that it is some kind of incompatibility with the application/window itself (Im not trying to force or use it in a particular window or screen). So maybe it can work with some other library than the ones currently in use.
The problem with the pyautogui and pynput library, is that the same thing happens but they also add some kind of delay by default.
In any case, setting the Shift press outside of if in clicks() seems to be the solution as well as using win32con.KEYEVENTF_EXTENDEDKEY inside win32api.keybd_event().
I don't see any point in going on with this and it will probably end up being better if I hold down Shift by myself.

Simulate Win+D (Show Desktop) from Python Script

I want to minimize all open windows and / or show the desktop on a Windows 10 machine from within a python script. I had a look in the win32api, win32con, win32gui but cannot find anything appropriate.
Any idea appreciated. Thanks
Pyautogui is a great module for stimulating keyboard clicks and mouse clicks. To install it, try this command in the terminal. pip install PyAutoGUI
Using pyautogui, you can stimulate a virtual click in 2 ways. Choose which one works best for you:
1:
import pyautogui
pyautogui.hotkey('winleft', 'd')
2:
import pyautogui
pyautogui.keyDown('winleft')
pyautogui.press('d')
pyautogui.keyUp('winleft')
Sometimes the first one doesn't work, so if it doesn't, try the second one.
If you want to use WinApi to implement keyboard emulation, you can use the keybd_event function.
code:
import win32api
win32api.keybd_event(0x5B, 0, ) # LWIN
win32api.keybd_event(0x44, 0, ) # D
win32api.keybd_event(0x5B, 0, 2)
win32api.keybd_event(0x44, 0, 2)
Of course, you should probably use SendInput, but it is a bit complicated to use in python.
You can refer to this thread : How to generate keyboard events in Python?

Clicking on pixel for certain process with python

Hello I am programming a program to automate mouse presses on a program for certain pixels but I don't want a second program to come in the way with that click, my program is going to look for a green pixel and click it on a certain part of the screen, but if there is another program/image in the way that is green I don't want it to click on that
I just want it to click on the process/program I want it to click on, and not click on the screen
If anyone could give me some tips on this, that would be helpful
To get the focused window (do not click if this is focused) use:
from win32gui import GetWindowText, GetForegroundWindow
print(GetWindowText(GetForegroundWindow()))
Do this on your windows and then do if statements to stop clicking on pixels.
But to click on the pixels you can use win32con and win32api:
import win32api, win32con
def click(x,y):
win32api.SetCursorPos((x,y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0)
sleep(0.01)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0)
To get the pixels and click on them use PyAutoGui
import pyautogui
from pyautogui import *
width = 1920
hight = 1080
while WindowIsFocused:
pic = pyautogui.screenshot()
for x in range(0, width, 1):
for y in range(0, hight, 1):
r, g, b = pic.getpixel((x, y))
if r == 252:
if g == 200:
if b == 118:
click(x,y)
print("Clicked")
Set width and hight to your screen resolution and WindowIsFocused to True if the window you want is focused. Use an extra function for that (the function should run constantly).
I hope that I could help. For any questions ask me. :)
Im sorry im not familiar with keys interacting with programs, but i made a little research and found a library called PyWin32 that should statisfy your need. You can search for its documentation or try your luck by finding videos on this particullar library on youtube.
Anyways, hopefully this helped you getting set in the right direction, and feel free to ask any question

Does anyone know how to fix random green lines appearing on PsychoPy stimuli?

I've just started using PsychoPy and I've tried to flip text and a grating, both of which appear broken up with green lines.
Anyone know how to fix this?
I'm using PyCharm with Python 3.8 and I get these error messages, not sure if related:
C:\Users\USERID\AppData\Local\Programs\Python\Python38\lib\site-packages\pyglet\media\codecs\wmf.py:838: UserWarning: [WinError -2147417850] Cannot change thread mode after it is set
warnings.warn(str(err))
C:\Users\USERID\AppData\Local\Programs\Python\Python38\lib\site-packages\pyglet\image\codecs\wic.py:292: UserWarning: [WinError -2147417850] Cannot change thread mode after it is set
warnings.warn(str(err))
Here is the code and image for the grating:
import psychopy.visual
import psychopy.event
win = psychopy.visual.Window(
size=[400,400],
fullscr=False,
units="pix")
grating = psychopy.visual.GratingStim(
win = win,
units="pix",
size=[150,150])
grating.draw()
win.flip()
psychopy.event.waitKeys()
win.close()
EDIT: I rolled back pyglet to version 1.4.10 and the error messages disappear but the green lines remain.
Here the solution:
Try to add the argument multiSample and numSamples when you create your window, as in the example below:
w = visual.Window([wstim, hstim], color = [0, 0, 0], units = "pix", fullscr=False, multiSample=True, numSamples = 16)
In my script this worked fine.
I'm experiencing the same issue but found that this is only the case on my computer. When I use the exact same code on a different computer, everything appears normal.
I had the same issue, which in my case seemed relate to the window size. It occured with vis.Window(size=[1400,800]) but changing this to vis.Window(size=[1920,1080]) solved it.

How to get the coordinates after a mouse click?

I was using the following code to get the coordinates of a point after a mouse click (keep in mind I was clicking on a random point on the screen, not on a figure):
import win32api
posvals = [[],[]]
x = 0
state_left = win32api.GetKeyState(0x01)
while x<2:
a = win32api.GetKeyState(0x01)
if a != state_left:
state_left = a
print(a)
if a >= 0:
print('button down')
z,y = win32api.GetCursorPos()
posvals[x] = [z,y]
print(z,y)
x += 1
time.sleep(.001)
print(posvals)
Here I saved the coordinates in posvals, and the while loop is there because I only wanted to record 2 clicks. I got and tweaked this code from another question on stackoverflow, but I'm not sure which one.
My current problem is that I'm using a Linux computer and the win32api module (its official name is pywin32) won't work since it is only for windows.
How can I adjust (or completely restart) my code?
So there is no easy way to port the code to linux, unless you run in wrapped with WineLib or equivalent wrapper software. One such explanation of this practice is here.
You could try other mouse position packages like PyMouse. This might be a better option. This question also has some good examples of other more agnostic package options for python mouse coordinates.

Categories