1
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 "kivy\properties.pyx", line 498, in kivy.properties.Property.__set__
   File "kivy\properties.pyx", line 1527, in kivy.properties.AliasProperty.set
   File "kivy\properties.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.

tripleee
  • 175,061
  • 34
  • 275
  • 318
Paman90
  • 118
  • 6
  • What is interesting about the Excel example is that it is clearly receiving mouse events, but it *doesn't* get the focus. The border doesn't change and any typing still goes to the focussed window. – Oddthinking Jun 19 '23 at 13:50

1 Answers1

2

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 )

Paul Lam
  • 176
  • 2
  • 12
  • Thanks for the reply Paul. I gave your approach a try and it works as described. However, if the mouse enters the window over a software button the button is clicked. This makes me think the "click" action is being fired twice. With your code, the soft button is clicked and with out it your code it requires to two mouse clicks to activate a soft button when window Focus is false. – Paman90 Aug 22 '21 at 12:55
  • I am really surprised there is not a way to change the read only status of Focus. Obviously it can be changed behind the scene, so I imagine I should be able to gain access to it as well. – Paman90 Aug 22 '21 at 12:59
  • The reason it ends up clicking the soft button is because the click down focuses window and my soft buttons are on_release. So the button_down of pyautogui.click() focuses window and then the button_up of pyautogui.click() activates my soft button. – Paman90 Aug 22 '21 at 13:49
  • @Paman90 for the first comment : yes I definitely can see that. I'll try to fix it. for the last comment , so you know the reason behind and the problem is solved ? – Paul Lam Aug 22 '21 at 14:26
  • I know the reason for problem "B" (Activating soft buttons). I still don't have a solution for original problem "A" of focusing the window (that doesn't have problem "B"). I am looking into pyautogui and seeing if I can replicate its ability to focus the window. Maybe I can separate the mouse click from focusing. I just need to follow the trail of how pyautogui accomplishes it and then most likely move through ctypes and further. If pyautogui can do it programatically....so can I. Thank you so much for pointing me in the correct direction. – Paman90 Aug 22 '21 at 14:29
  • I see. but I am a bit confused about it. when the window is not focused , one single click should only focus the window without pressing / affecting anything inside the window .... ‍♂️ maybe I think for another way to do this .... btw do you have any ideas on solving the "Probem 'b'" ? – Paul Lam Aug 22 '21 at 15:31
  • I could work to solve problem "B" by changing my soft buttons to kivy on_press instead of on-release. I think this has larger dowstream issues. Not. For now I am going to work on other things...maybe my brain will think outside the box better that way – Paman90 Aug 22 '21 at 15:44
  • oh ok .... at the same time I give up to solve the "Problem B" idk y it appears like that , before it works without the "Problem B" .... : ( – Paul Lam Aug 22 '21 at 15:51