Improved keyboard support [RFC]#1510
Conversation
(Hardcoded shortcuts)
So they can be localized
Let panels enumerate activable buttons they contain
Now the modifiers specified in Hotkeys are ANDed together
HotkeySequences have IsDown/IsDownWith and IsPressed/IsPressedWith methods to check whether the main key is down or pressed. If you need to check several HotkeySequences at once, compute a KeyModifiers beforehand: KeyModifiers keyModifiers = HotkeySequence.GetKeyboardKeyModifiers(); ... if (hotkey1.IsDownWith(keyModifiers)) ... if (hotkey2.IsDownWith(keyModifiers)) ... If you only need to check one HotkeySequence, or don't mind the small overhead of recomputing KeyModifiers, you can use simplified methods: if (hotkey.IsDown()) ... Refactorized DaggerfallShortcut to use HotkeySequence.
Also extend it to support both virtual modifiers (Control-, Shift-, Alt-) but also physical modifiers (LeftControl-, etc.)
….Buttons Could have mapped from one to the other by typecasting, but that would have been a hack
|
nice! |
Yes, I haven't externalized automap HotkeySequences; It's certainly doable, but I'm not sure what this fallback mechanism is all about so I left it as-is for the moment |
Added automap shortcuts to setup The most difficult part was replacing the fallback key feature: when the key used to open the automap is used in an automap shortcut, it creates a conflict because the automap implements toggle open (ie can be closed with the same key used to open it). I reimplemented it like this: - the key used to open the automap also closes the automap (toggle open); - shortcuts that used the same key are replaced with shortcuts using the Home key, but with the same modifiers; - if the key used to open the automap changes, just recreate all shortcuts and tooltips. Added Escape key to exit the automap for consistency and hardcoded fallback Added HotkeySequence.IsUp(With) methods used for toggle key Added HotkeySequence.ToString() method Removed hardcoded modifiers in tooltips texts Renamed *Control- modifiers as *Ctrl- to shorter descriptions in automap tooltips
|
I migrated the automap shortcuts: The most difficult part was replacing the fallback key feature: when the key used to open the automap is used in an automap shortcut, it creates a conflict because the automap implements toggle open (ie can be closed with the same key used to open it). I reimplemented it like this:
Added Escape key to exit the automap for consistency and hardcoded fallback Added HotkeySequence.IsUp(With) methods used for toggle key Added HotkeySequence.ToString() method Removed hardcoded modifiers in tooltips texts Renamed *Control- modifiers as *Ctrl- to shorter descriptions in automap tooltips |
I need to settle for some terminology in the code... Buttons, Shortcuts, Hotkeys, Bindings, I feel this is really more confusing that it needs to be
Not consistent between dialogs, but consistent with what's on screen
| } | ||
| } | ||
|
|
||
| public override void Update() |
There was a problem hiding this comment.
What's this update needed for?
There was a problem hiding this comment.
Right now there's no mechanic in either Button or Panel to check and activate them (or their children) thru hotkeys, so I explicitly call my KeyboardActivation() methods from the different UI windows Update() methods.
I'm not satisfied with this solution, I'm sure it could be better integrated, but I don't know if that was already planned or how...
|
This is nice work, I'm sorry for not looking at this one sooner. I don't have any other plans to integrate hotkeys for message boxes. This fits the bill and shouldn't cause any conflicts with the new keybind setup for game controls. |
|
Thanks! |
One possibility would be to handle the KeyboardActivation() pump in DaggerfallUI.OnGUI(). This is where the other key events for UI are collected. You could query uiManager.TopWindow to get the window at top of stack (if one is open) and call a new window method to trigger a recursive pass down through panel hierarchy to activate hotkeys as necessary. This only needs to be done once per gui update for the top window and shouldn't require many cycles. Just throwing out ideas to help brainstorm a better solution. I like this feature and believe it can get where you want it to be. :) |
|
I don't know how that part of the code works but what you describe sounds good, that's the kind of mechanism I had in mind. |
|
Mmmh interesting conflict with #1625 |
|
Yeah, I thought it was best to leave this one for now until we look at other means of driving key activation. I'd be happy to collab with you on this one if that's something you'd find helpful? :) |
DaggerfallTravelPop fix is not the cleanest; I think that having some other transparent panels taking care of only toggling options behaviors would be better. Assets/Scripts/Game/UserInterfaceWindows/DaggerfallGuildServicePopupWindow.cs Assets/Scripts/Game/UserInterfaceWindows/DaggerfallInventoryWindow.cs Assets/Scripts/Game/UserInterfaceWindows/DaggerfallTravelPopUp.cs
|
Made a quick fix; But as I said in the commit message, I feel that having extra transparent panels to handle options toggling would be more clean... |
Provide a method in DaggerfallUI that simply visits panels starting from TopWindow
By the way vagrancy warnings do not use the usual Y/N prompt code:
DaggerfallMessageBox mb = new DaggerfallMessageBox(uiManager,
DaggerfallMessageBox.CommonMessageBoxButtons.YesNo,
TextManager.Instance.GetText("DaggerfallUI", "illegalRestWarning"),
this);
mb.OnButtonClick += ConfirmIllegalRestForAWhile_OnButtonClick;
mb.Show();
With two subsystems handling keys (DaggerfallUI.ProcessHotkeySequences() and windows' Update()), there's some risk of hotkey sequences to be handled twice; Most common example is "toggle close" keys: ProcessHotkeySequences() detects that you want to open a window, it opens, then the Update() method of that window recognizes the same hotkey and closes immediately. They're several fixes possible: - make sure all hotkeys handling is done by ProcessHotkeySequences. This currently requires all hotkeys to be assigned to some buttons, but that could be made more flexible; - expose whether ProcessHotKeySequences() already handled current hotkey. Flexible but not very pretty, that's what this commit does; - move hotkeys handling from Update() method to a new windows' method, say CustomKeysProcessing(KeyModifiers keyModifiers), that can be called from ProcessHotkeySequences() to override other hotkey processing. Looks more satisfying, but turned out to be hard to get working right.
|
With two subsystems handling keys (DaggerfallUI.ProcessHotkeySequences() and windows' Update()), there's some risk of hotkey sequences to be handled twice; They're several fixes possible:
|
Your method here is sound by returning true if CustomKeysProcessing() is handled by the window. I also like that future UI windows can still do custom key processing if required without needing to modify your hotkey system or be forced to extend DialogShortcuts.txt. This is a plus for bespoke UI from mods that maybe couldn't or shouldn't be making changes to core. I think I like this option most of all.
I'd like to say this is the best option long-term. Prior to your work on this PR, this kind of hotkey handling didn't exist. Toggle open/closed was added in isolation just to accomplish that specific task without any extra framework for additional hotkeys. But I understand this presents new challenges as the toggle keys can themselves be rebound elsewhere. The hotkey system would need to support that in addition to (and perhaps conflicting with) the bindings in DialogShortcuts.txt. I don't know about you, but it seems like one dragon too many.
Perfectly sensible compromise, thank you for that. Would you be comfortable for this PR to make its way into live for user testing? I'm more than happy to include in next round of builds. Just let me know if you want more time in the oven and I'll let it sit for now. |
|
Yes, I think this PR is ready as-is |
|
Really lovely work here. Merging now. |
This adds keyboard support for standard dialog boxen (Y/N prompts, etc.), but also some special dialog boxen (Options menu, Resting, Traveling) and screens (Inventory, Trading). It also replaces hardcoded key bindings of daedra quests Y/N prompts and travel map.
I borrowed the HotkeySequence class from the automap then extended it to support virtual key modifiers (say, Shift that matches either LeftShift or RightShift), then after that changed the logic to AND modifiers together.
All bindings are configured in an external DialogShortcuts.txt file, so they can be localized.
Before going on I submit this patch in its current state for review.
For example its integration into UI code (Panel, Button) is superficial and must be called explicitly, that can probably be improved but I'm not sure how it was planned. It could also be that I'm going in a totally wrong direction, just let me know.
Forums: https://forums.dfworkshop.net/viewtopic.php?f=4&t=1448