How do I make my python-kivy window become the focus when the mouse cursor is over the window?
Question:
python 3.7.8
kivy 2.0.0
Modern programs are able to make changes in a window even when the focus is not True for the app.
Example: Two windows are set side by side (Chrome and Excel). I click inside the Chrome window and it becomes focus True. When I then take my cursor into the Excel window I can click into a cell directly or scroll up and down. This action in Excel does not require me to first click in the Excel window to make it focus True.
I have not been able to replicate this with python-kivy.
Window.on_cursor_enter(do_action())
does not fire when the cursor enters the window.
def on_start(self):
Window.bind(mouse_pos=self.my_callback)
def my_callback(self, instance, value):
Window.focus = True
Throws:
File "kivyproperties.pyx", line 498, in kivy.properties.Property.__set__
File "kivyproperties.pyx", line 1527, in kivy.properties.AliasProperty.set
File "kivyproperties.pyx", line 1485, in kivy.properties.AliasProperty.__read_only
AttributeError: "WindowSDL.focus" property is readonly
UPDATE:
Window.on_cursor_enter(do_action())
is saddled with a pass
in the kivy source. That clears up why it doesn’t work.
I think the true correction is going to come from a call to ctypes.windll.user32
…setFocus…something like that
but I am a Python hobbyist, and my understanding of this is limited.
Answers:
I think I found a work-around but you maybe will not be satisfied with it.
Anyway , here is my solution :
import kivy
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.clock import Clock
from kivy.core.window import Window
import pyautogui # for mouse click
kivy.lang.Builder.load_string("""
#:kivy 2.0.0
<Main>:
ScrollView:
do_scroll_x: True
do_scroll_y: True
size: root.size
BoxLayout:
size_hint: 1, None
width: 50
orientation: "vertical"
Label:
text: "Hello World !"
font_size: 25
Button:
id: my_button
text: "click me !"
font_size: 25
on_release:
root.button_callback()
""")
class Main(Widget):
def button_callback(self): # fired when button is clicked
print("clicked on button !")
def window_callback(self, instance): # fired when cursor entered window
Window.restore() # seems like doesn't work
Window.show() # this also
# so I do this when the mouse is hover on the window
# import pyautogui first
if Window.focus == False:
pyautogui.click() # a mouse click for focusing the window
print(True) # just to clarify the above line got executed
print(f"window is focus ? {Window.focus}") # although it may says the windows is not focused , it should be
def update(self, dt):
Window.bind(on_cursor_enter = self.window_callback) # bind when on_cursor_enter
class MyKivyApp(App):
def build(self):
Clock.schedule_interval(Main().update, 1/60)
return Main()
if __name__ == "__main__":
MyKivyApp().run()
How it works : when mouse is hovered on the app window , it will have one mouse click by pyautogui
to force focus to the app window programmatically.
The only line of code inside the update
func and the window_callback
func will fired when the mouse is hover on the window ( i.e. like when the mouse leaves and moves back to the app window , the window_callback
will be fired ) then I use pyautogui
to do a mouse click by itself so that the window can be focused by itself. This way , the kivy app window can be focused when the mouse moves back to the window.
Moreover , according to this stackoverflow answer , the SLD2 on desktop app can hide the window but to restore / show it. It can scroll even when the app window is not focused ( I tested )
Just add the following at the top of your code:
import os
os.environ["SDL_MOUSE_FOCUS_CLICKTHROUGH"] = '1'
See discussion at: https://groups.google.com/g/kivy-users/c/b1wXKpjzjkg/m/5HF6WxSyAwAJ
python 3.7.8
kivy 2.0.0
Modern programs are able to make changes in a window even when the focus is not True for the app.
Example: Two windows are set side by side (Chrome and Excel). I click inside the Chrome window and it becomes focus True. When I then take my cursor into the Excel window I can click into a cell directly or scroll up and down. This action in Excel does not require me to first click in the Excel window to make it focus True.
I have not been able to replicate this with python-kivy.
Window.on_cursor_enter(do_action())
does not fire when the cursor enters the window.
def on_start(self):
Window.bind(mouse_pos=self.my_callback)
def my_callback(self, instance, value):
Window.focus = True
Throws:
File "kivyproperties.pyx", line 498, in kivy.properties.Property.__set__
File "kivyproperties.pyx", line 1527, in kivy.properties.AliasProperty.set
File "kivyproperties.pyx", line 1485, in kivy.properties.AliasProperty.__read_only
AttributeError: "WindowSDL.focus" property is readonly
UPDATE:
Window.on_cursor_enter(do_action())
is saddled with a pass
in the kivy source. That clears up why it doesn’t work.
I think the true correction is going to come from a call to ctypes.windll.user32
…setFocus…something like that
but I am a Python hobbyist, and my understanding of this is limited.
I think I found a work-around but you maybe will not be satisfied with it.
Anyway , here is my solution :
import kivy
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.clock import Clock
from kivy.core.window import Window
import pyautogui # for mouse click
kivy.lang.Builder.load_string("""
#:kivy 2.0.0
<Main>:
ScrollView:
do_scroll_x: True
do_scroll_y: True
size: root.size
BoxLayout:
size_hint: 1, None
width: 50
orientation: "vertical"
Label:
text: "Hello World !"
font_size: 25
Button:
id: my_button
text: "click me !"
font_size: 25
on_release:
root.button_callback()
""")
class Main(Widget):
def button_callback(self): # fired when button is clicked
print("clicked on button !")
def window_callback(self, instance): # fired when cursor entered window
Window.restore() # seems like doesn't work
Window.show() # this also
# so I do this when the mouse is hover on the window
# import pyautogui first
if Window.focus == False:
pyautogui.click() # a mouse click for focusing the window
print(True) # just to clarify the above line got executed
print(f"window is focus ? {Window.focus}") # although it may says the windows is not focused , it should be
def update(self, dt):
Window.bind(on_cursor_enter = self.window_callback) # bind when on_cursor_enter
class MyKivyApp(App):
def build(self):
Clock.schedule_interval(Main().update, 1/60)
return Main()
if __name__ == "__main__":
MyKivyApp().run()
How it works : when mouse is hovered on the app window , it will have one mouse click by pyautogui
to force focus to the app window programmatically.
The only line of code inside the update
func and the window_callback
func will fired when the mouse is hover on the window ( i.e. like when the mouse leaves and moves back to the app window , the window_callback
will be fired ) then I use pyautogui
to do a mouse click by itself so that the window can be focused by itself. This way , the kivy app window can be focused when the mouse moves back to the window.
Moreover , according to this stackoverflow answer , the SLD2 on desktop app can hide the window but to restore / show it. It can scroll even when the app window is not focused ( I tested )
Just add the following at the top of your code:
import os
os.environ["SDL_MOUSE_FOCUS_CLICKTHROUGH"] = '1'
See discussion at: https://groups.google.com/g/kivy-users/c/b1wXKpjzjkg/m/5HF6WxSyAwAJ