Hello again everyone!
I’ve been working on a plugin for the last couple of weeks to integrate RenderDoc with UE4 to make debugging shaders easier.
It’s basically ready for alpha, but I’m having trouble with a silly detail. I’m adding a capture frame button to each viewport, and if you click that button it will force a render and capture it for processing.
My problem has nothing to do with that though, and rather a problem with getting hotkeys to work. Getting the button itself hooked up to a UI command list was easy as pie. Unfortunately, the InputGesture I associated with it did not work out of the box.
What I would like to accomplish is simply either a global hotkey, or a hotkey scoped to the viewport that triggers a capture. It does not seem trivial however, please let me explain.
I have looked all over the solution for plugins that attempt to do this. While there are plenty of plugins that use slate buttons, not many define their own hotkeys, and those who do are nicely scoped to their own windows.
Debugging this I have also discovered that input is sent through an event path much like other modern GUI frameworks like WPF. The event bubbles upward from the widget you clicked on until it finds something to handle the event. When this happens, if the handled event marks it as such the event stops there. In most cases, the handler will be a window that then calls ProcessCommandBindings(FKeyEvent) on its command list with the keyboard event data. The command lists themselves seem to be organized in a hierarchical manner as you can specify a parent context when you create a new command list. Looking at the callbacks in InputBindingManager::FindCommandInContext supports this as you can clearly see the notifications starting in the context that you clicked on, and then propagate up through each context in turn through its “parent path”.
Looking at how global hotkeys work right now, this seems to be the key. The FGeneralCommands UI command list is simply the root of this parent tree. When you have a given window open and you press a button, if that window is attached to this hierarchy, then the upper contexts will almost certainly have a chance to react to the commands.
It then becomes clear that the best way to get a global or scoped hotkey to work would then be to either:
- Get the command list for the system I would like to add my hotkey to, and bind my command to that command list (i.e. the general commands UI command list, or the viewport command list).
- Get generic key down messages and invoke my own command list’s ProcessCommandBindings function on call.
I’d prefer the first one as it seems the least invasive and the most flexible, however, while there are methods like GetCommandList() sprinked over different classes in the editor slate class hierarchy, all of them seem to return const instances. I assume this has to do with initialization more than anything else. Adding extra commands to the command lists probably has to be done before some global initialization step.
Right now I’m working on trying to figure out if this solution might be feasible, and if it is, and there is no better solution, I intend to do a pull request on this.
My question to you guys subsequently is:
Is there a way to already do this (Associate a global hotkey to a function in your own plugin).