PopupMenu's accelerator keys don't seem to work

Godot Version

4.4.1

Question

I am very confused as to how accelerator keys are supposed to work and what I could be doing wrong.

The documentation says:

Signals

[…]
● id_pressed(id: int)
Emitted when an item of some id is pressed or its accelerator is activated.
[…]
When reading this I thought I could just press any item’s accelerator key when the popup is visible and detect it through the id_pressed signal. Things look normal when running the project, I even see the accelerator keys’ labels next to each item’s text but when pressing the accelerator, nothing happens.

My node tree looks like this:

Main
:left_arrow_curving_right:PopupMenu

Here is the script I’ve attached to Main:

extends Node

@onready var pm = $PopupMenu

func _ready() -> void:
	pm.allow_search = false
	pm.add_item("Action", 0, KEY_A)
	pm.add_item("Select", 1, KEY_S)
	pm.add_item("Reflect", 2, KEY_R)

func _input(event):
	if event.is_action_pressed("right_click"):
		pm.popup()


func _on_popup_menu_id_pressed(id: int) -> void:
	print("Clicked: ", pm.get_item_text(id))

What is it I am doing wrong? Do accelerator keys require additional setup to work?

Yes, you need to call PopupMenu.activate_item_by_event() manually.

Example:

extends Node


@onready var popup_menu: PopupMenu = $PopupMenu


func _ready() -> void:
	popup_menu.id_pressed.connect(func(id:int):
		print("Pressed %s" % id)
	)
	popup_menu.add_item("Hello", 0, KEY_MASK_CTRL | KEY_A)
	popup_menu.add_item("World", 1, KEY_MASK_CTRL | KEY_S)


func _unhandled_input(event: InputEvent) -> void:
	if event.is_pressed():
		popup_menu.activate_item_by_event(event)
1 Like

Thank you for the solution!

I was confused because what Godot means by “Accelerator Keys” wasn’t what I thought and there are multiple things “Accelerator Keys” is used to refer to online. I come from Blender where I’ve heard accelerator keys refer to keys that only work in the context of their popup menu like shown in this video. But from my understanding in Godot, accelerator keys refer to something similar to global shortcuts that (and this is what got me confused) always work except when the popup menu is focused.

Maybe I am using the term accelerator keys wrong, either way, my goal is to implement a feature similar to blender’s “Accelerator Keys” which I assume I should use Control nodes rather than Popup Menus for.

You don’t need to re-invent the wheel. You can just call the activate_item_by_event() function inside a callback for the signal Window.window_input like:

extends Node


@onready var popup_menu: PopupMenu = $PopupMenu


func _ready() -> void:
	popup_menu.window_input.connect(func(event:InputEvent):
		if event.is_pressed():
			popup_menu.activate_item_by_event(event)
	)

	popup_menu.id_pressed.connect(func(id:int):
		print("Pressed %s" % id)
	)
	popup_menu.add_item("Hello", 0, KEY_MASK_CTRL | KEY_A)
	popup_menu.add_item("World", 1, KEY_MASK_CTRL | KEY_S)


func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
			popup_menu.popup(Rect2(event.global_position, Vector2.ZERO))
1 Like