!!! Seamless solution - 5.3.2 tested !!!
I have found a decent workaround using .lldbinit script. It makes LLDB execute a function in the LinuxPlatform when a breakpoint is hit.
Simple (1 minute, global config)
This solution applies the hook globally (to all lldb runs). It might not be always desirable. The advanced one doesn’t. If you don’t use lldb anywhere except for unreal, this should suffice.
-
You need to create a
.lldbinitfile in your home directory (~/.lldbinit) and paste the following:File:
.lldbinit:target stop-hook add --one-liner "p ::UngrabAllInputImpl()" -
That’s it. The mouse should be released when a breakpoint is hit.
Explanation
The .lldbinit file is executed every time lldb is started (duh). It will hook to the stopping event (like a breakpoint) and call an unreal internal function - lldb command print (p) will execute the specified C++ code (with some caveats).
::UngrabAllInputImpl() is defined in one of the Unreal source files related to unix platform and should gracefully release the input without much side-effects.
Under the hood this calls some SDL functions, which in turn talk to X11 and do the actual job.
Advanced (5 minutes, Unreal-specific)
To address the globality issue I’ve prepared a slightly more complex solution to filter for Unreal presence, one that requires a custom python lldb extension.
-
Create a python file
ue_dbg_hook.pyin a reasonable location. I’ve used my Rider installation directory; feel free to choose a different folder.File:
ue_dbg_hook.py:import lldb class UnrealBreakpointHook: def __init__(self, target, extra_args, internal_dict): pass running_unreal = None @staticmethod def check_module_loaded(debugger, module_name): # Get the current target target = debugger.GetSelectedTarget() # Iterate over all modules in the target for module in target.module_iter(): # Check if the module name matches if module.GetFileSpec().GetFilename() == module_name: return True return False def handle_stop(self, exe_ctx, stream): tgt = exe_ctx.GetTarget() dbg = tgt.GetDebugger() if UnrealBreakpointHook.running_unreal is None: UnrealBreakpointHook.running_unreal = self.check_module_loaded(dbg, "UnrealEditor") if UnrealBreakpointHook.running_unreal: dbg.HandleCommand("p ::UngrabAllInputImpl()") return True def __lldb_init_module(debugger, internal_dict): print("ue_dbg_hook loaded") -
Change the
.lldbinitslightly to use the python hook instead. Don’t forget to use the path where you actually placed the python script.NOTE: Notice that in the second line
ue_dbg_hookmodule name is used - if for some reason you decided to name your python script differently, remember to apply this change here as well.File:
.lldbinit:command script import "~/JetBrains Rider-2023.3.2/ue_dbg_hook.py" target stop-hook add -P ue_dbg_hook.UnrealBreakpointHook -
That’s it. The mouse should be released when a breakpoint is hit, but only in Unreal.
Disclaimers, notes
-
I haven’t tested this thoroughly yet, nor I have used this for an extended period of time - the solution appears to be “clean” in a sense that it doesn’t interfere with much of the engine/system, but I cannot give any guarantees for no side effects or derived issues.
-
I haven’t tested that with packaged builds either. I’m pretty sure the simple solution will work right away and for the advanced one a different module name to look for should be selected (
UnrealEditoris the current choice). -
The python hook in the advanced solution caches the unreal presence to reduce performance impact - it might not be desired when debugging low-level engine, but I honestly cannot think of any situation where one would need to break earlier. Just keep in mind that such feature exists in case some troubleshooting is in order.
-
It should work with different Unreal versions, provided the
::UngrabAllInputImplexists. If for some reason this convenient function goes the dodo way, there is plenty of room to find a different route.
Cheers.