0

I tried to use pyxhook with wxPython. What the program suppose to do is when the window is hid or minimized, when the user press "R_Control", even when another application is still in focus, wxPython window should be shown, and set in focus. But instead, what it did just RequestUserAttention by blinking in the taskbar. I've tried using Raise(), Restore(), but it still doesn't work. Here's the simplified version of the code

import wx, pyxhook

class Frame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, name='', parent=parent, title='test')
        self.panel = wx.Panel(self, wx.ID_ANY)
        self.text_input = wx.TextCtrl(self.panel)
        self.moduleSizer = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(self.moduleSizer)
        self.moduleSizer.Add(self.text_input, flag=wx.ALIGN_CENTER)
        self.text_input.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
        self.moduleSizer.Fit(self)
        self.text_input.SetFocus()

    def onKeyDown(self, event):
        if event.GetKeyCode() == wx.WXK_ESCAPE: self.Hide()
        event.Skip()

class HookMan(pyxhook.HookManager):
    def __init__(self,frame,master=None):
        pyxhook.HookManager.__init__(self,master)
        self.frame = frame
        self.KeyDown = self.key_down
        self.HookKeyboard()

    def key_down(self,event):
        if event.Key == 'Control_R':
            self.frame.Show()

if __name__ == '__main__':
    app = wx.App()
    frame = Frame(None)
    hookman = HookMan(frame)
    hookman.start()
    frame.Show()
    app.MainLoop()

I've tried this with TkInter, and it just works. root.deconify() just set the window on focus. How do i recreate this behaviour in wxPython?

import pyxhook
import tkinter as tk

class Root(tk.Tk):
    def __init__(self,master=None):
        tk.Tk.__init__(self,master)
        self.title('test')
        self.text_input = tk.Entry(self)
        self.text_input.pack()
        self.bind("<Escape>", self.minimize)

    def minimize(self,event):
        self.withdraw()

class HookMan(pyxhook.HookManager):
    def __init__(self,frame,master=None):
        pyxhook.HookManager.__init__(self,master)
        self.frame = frame
        self.KeyDown = self.key_down
        self.HookKeyboard()

    def key_down(self,event):
        if event.Key == 'Control_R':
            self.frame.deiconify()

if __name__ == '__main__':
    root = Root()
    hookman = HookMan(root)
    hookman.start()
    root.text_input.focus_set()
    root.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Are you sure? Run it with nothing on the desktop, it may well be dislaying underneath other windows. If not add your platform to the question, it may matter. – Rolf of Saxony Oct 31 '20 at 13:01
  • My Bad.. after messing with some settings, i realized that it's about my Desktop Environment. I'm using KDE Plasma 5.18, and there's focus stealing prevention option. The program work fine when i turn off the focus stealing prevention. – Running Ray Oct 31 '20 at 16:33

1 Answers1

0

For the record, the code you submitted (at least on Linux with wx 4.1.0) did in fact, work. The window was resurrected underneath existing windows.
By using SetWindowStyle and rejigging the calls to pyxhook, we can get this code to function appropriately.

import wx
import pyxhook

class Frame(wx.Frame):
    def __init__(self, parent):
        wx.Frame.__init__(self, name='', parent=parent, title='test')
        self.SetWindowStyle(wx.STAY_ON_TOP)
        self.panel = wx.Panel(self, wx.ID_ANY)
        self.text_input = wx.TextCtrl(self.panel)
        self.moduleSizer = wx.BoxSizer(wx.VERTICAL)
        self.panel.SetSizer(self.moduleSizer)
        self.moduleSizer.Add(self.text_input, flag=wx.ALIGN_CENTER)
        self.text_input.Bind(wx.EVT_KEY_DOWN, self.onKeyDown)
        self.Bind(wx.EVT_CLOSE, self.onExit)
        self.moduleSizer.Fit(self)
        self.text_input.SetFocus()
        self.hookman = HookMan(self)
        self.hookman.start()

    def onKeyDown(self, event):
        if event.GetKeyCode() == wx.WXK_ESCAPE:
            self.Hide()
        event.Skip()

    def onExit(self, event):
        self.hookman.cancel()
        self.hookman.join()
        self.Destroy()

class HookMan(pyxhook.HookManager):
    def __init__(self,parent,master=None):
        pyxhook.HookManager.__init__(self,master)
        self.frame = parent
        self.KeyDown = self.key_down

    def key_down(self,event):
        if event.Key == 'Control_R':
            self.frame.Show()
    
    def close(self):
        self.close()

if __name__ == '__main__':
    app = wx.App()
    frame = Frame(None)
    frame.Show()
    app.MainLoop()
Rolf of Saxony
  • 21,661
  • 5
  • 39
  • 60
  • My Bad.. after messing with some settings, i realized that it's about my Desktop Environment. I'm using KDE Plasma 5.18, and there's focus stealing prevention option. The program work fine when i turn off the focus stealing prevention. Thanks... – Running Ray Oct 31 '20 at 16:33
  • @RunningRay No problem, note my change to the pyxhook code, which closes the thread down properly and allows your code to terminate, rather than hang. – Rolf of Saxony Oct 31 '20 at 18:27