DFHack / dfhack

Memory hacking library for Dwarf Fortress and a set of tools that use it
Other
1.86k stars 468 forks source link

Screens created by commands run through command-prompt don't pass keys to the right parent screen #1803

Closed lethosor closed 3 years ago

lethosor commented 3 years ago

Reported by Bumber here: http://www.bay12forums.com/smf/index.php?topic=164123.msg8261345#msg8261345

To reproduce:

lethosor commented 3 years ago

From an initial inspection, the issue is that the command-prompt screen is re-added to the screen stack after the command (gui/liquids in this case) is run:

[DFHack]# devel/list-screens
<viewscreen: 0x232a668>
 <viewscreen_dwarfmodest: 0x7fff9e993b70>
  <viewscreen: 0x7fffb4000e40>   # created by command-prompt
   <viewscreen: 0x7fffd18c3f90>   # created by gui/liquids

My understanding of how command-prompt works after #1319:

  1. The user enters a command and presses Enter
  2. The command-prompt screen is removed from the screen stack entirely
  3. The command is run
  4. The command-prompt screen is re-added in the stack, underneath its previous parent screen - this matches the above
  5. If the command produced no output (true in this case!), the command-prompt screen is dismissed with Screen::dismiss(). However, as with all screens, the screen is not actually removed from the stack until it is the topmost screen. In this case, gui/liquids ends up on top somehow.

My best guess is that gui/liquids is attempting to pass keys to the command-prompt screen. This confuses me a bit because in step 3, the gui/liquids screen should identify the fortress mode screen as its parent when it is created. I may be misunderstanding when the screen is actually added, though. Another possibility is that gui/liquids is passing keys to the fortress mode screen successfully, but that screen is not re-rendering due to the intermediate command-prompt screen.

Possible solutions:

lethosor commented 3 years ago

It turns out that keys are being passed to the command-prompt screen, which does not propagate them to its parent, and also ignores most keys entirely if is_response is set (i.e. after a command has been run). In the case of gui/teleport, cursor keys are passed through propagateMoveKeys(), which checks screen._native.parent every time, usually after it has been changed by Screen::Hide.

I think the best solution here is to move the command-prompt screen to the top of the stack when it is shown again, which will cause it to be dismissed right away. This appears to work for gui/liquids and gui/teleport, at least.