Constant Beeping Sound on Keyboard Input

Here’s the simplest code that reproduces the issue on my machine:

import wx

app = wx.App(False)

frame = wx.Frame(None, title="BEEP")
text = wx.Panel(frame)

frame.SetFocus()

frame.Show()


app.MainLoop()

After clicking on the window, anywhere, any key on my keyboard causes the macOS “bell” sound to ring; the same one which plays when something is out of focus. The desired output is for there to be no sound.

In an application with several panels where some need to take in user input and others do not, I am left with an application that constantly beeps when users press keys. Keys are meant be pressed and picked up by the top-level frame by wx.EVT_CHAR_HOOK, and furthermore custom audio is meant to be played along with these key presses, but the macOS bell sound is ruining the entire situation. The keys are registered, but they consistently cause beeps.

Can this issue be resolved programmatically? How is this issue not present in almost every WX application(Pretty much every demo I’ve copied-pasted has had this same issue)? Surely I must be missing something obvious…

There are a few things going on here…

  1. Frames are not intended to have the focus, and the behavior when you set it there is usually that it will try to give it to a child that accepts the focus, if there is one.

  2. EVT_CHAR_HOOK is kind of a hack and is not always consistent or working the way most people expect it to. If there is any other way to do what you need then I recommend that you avoid EVT_CHAR_HOOK.

  3. The beep typically means that you are not correctly handling one of the key events in the widget which has the focus, where “correctly” means either both EVT_KEY_DOWN and EVT_KEY_UP, or EVT_CHAR.

  4. If you want to get the raw key events in EVT_KEY_DOWN and also the cooked character event (after it has been processed by the active IME) in EVT_CHAR then call event.Skip() in the key-down handler.

  5. You can enable a panel (or other widget types) to be able to receive the focus by overriding AcceptsFocus and returning True. For Panels the default implementation will return True if there are no child widgets, False otherwise.

Here is a quick update of your example to show some of these things in action:

import wx

USE_KEY_EVENTS = False

class FocusablePanel(wx.Panel):
    def __init__(self, *args, **kw):
        super().__init__(*args, **kw)

        if USE_KEY_EVENTS:
            self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
            self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
        else:
            self.Bind(wx.EVT_CHAR, self.OnChar)

    def AcceptsFocus(self):
        return True

    def OnKeyDown(self, event):
        print(f'OnKeyDown: {event.GetKeyCode()}')

    def OnKeyUp(self, event):
        print(f'OnKeyUp: {event.GetKeyCode()}')

    def OnChar(self, event):
        print(f'OnChar: {event.GetKeyCode()}')

app = wx.App(False)
frame = wx.Frame(None, title="BEEP")
text = FocusablePanel(frame)
frame.Show()
app.MainLoop()
1 Like

There is also the KeyEvents sample in the demo where you can experiment a bit more with how the keyboard events work.