From 118c5adede29ffaf8a6f61d4f4ae7d13ed506b1b Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 9 Mar 2024 13:02:29 -0500 Subject: [PATCH 1/7] Clean up horrible key definitions. --- Scripts/Python/xOptionsMenu.py | 159 +++++++++++++++++++-------------- 1 file changed, 90 insertions(+), 69 deletions(-) diff --git a/Scripts/Python/xOptionsMenu.py b/Scripts/Python/xOptionsMenu.py index eee1a991f2..c383edbbb3 100644 --- a/Scripts/Python/xOptionsMenu.py +++ b/Scripts/Python/xOptionsMenu.py @@ -40,22 +40,15 @@ Mead, WA 99021 *==LICENSE==* """ -"""Module: xOptionsMenu -Age: global -Author: Mark DeForest -Date: July 22, 2003 -This is the python handler for the Options Menu ----- Phased for Prologue I thru Episode I - - -""" +from __future__ import annotations MaxVersionNumber = 8 MinorVersionNumber = 4 import functools import os +from typing import * from Plasma import * from PlasmaConstants import * @@ -259,68 +252,96 @@ # a string if console command # None if not mapped (mostly on second key on console) # + +class _KeyLine(NamedTuple): + controlCode: Union[str, int, None] + singlePlayer: bool + multiPlayer: bool + + gKM1ControlCodesRow1 = { - kKMEditLine1Row1 : (PlasmaControlKeys.kKeyMoveForward,1,1) ,\ - kKMEditLine2Row1 : (PlasmaControlKeys.kKeyMoveBackward,1,1) ,\ - kKMEditLine3Row1 : (PlasmaControlKeys.kKeyRotateLeft,1,1) ,\ - kKMEditLine4Row1 : (PlasmaControlKeys.kKeyRotateRight,1,1) ,\ - kKMEditLine5Row1 : (PlasmaControlKeys.kKeyJump,1,1) ,\ - kKMEditLine6Row1 : (PlasmaControlKeys.kKeyStrafeLeft,1,1) ,\ - kKMEditLine7Row1 : (PlasmaControlKeys.kKeyStrafeRight,1,1) ,\ - kKMEditLine8Row1 : (PlasmaControlKeys.kKeyExitMode,1,1) ,\ - kKMEditLine9Row1 : (PlasmaControlKeys.kKeySetFirstPersonMode,1,1) ,\ - kKMEditLine10Row1 : ("Game.KIOpenYeeshaBook",1,1),\ - kKMEditLine11Row1 : ("Game.KIHelp",1,1) ,\ - kKMEditLine12Row1 : ("Game.KIOpenKI",0,1) ,\ - kKMEditLine13Row1 : ("Game.KITakePicture",0,1),\ - kKMEditLine14Row1 : ("Game.KICreateJournal",0,1),\ - kKMEditLine15Row1 : (PlasmaControlKeys.kKeyPushToTalk,0,1) ,\ - kKMEditLine16Row1 : ("Game.EnterChatMode",0,1) ,\ - kKMEditLine17Row1 : ("Game.KICreateMarkerFolder",0,1) ,\ - kKMEditLine18Row1 : ("Game.KICreateMarker",0,1) ,\ - } + kKMEditLine1Row1: _KeyLine(PlasmaControlKeys.kKeyMoveForward, True, True), + kKMEditLine2Row1: _KeyLine(PlasmaControlKeys.kKeyMoveBackward, True, True), + kKMEditLine3Row1: _KeyLine(PlasmaControlKeys.kKeyRotateLeft, True, True), + kKMEditLine4Row1: _KeyLine(PlasmaControlKeys.kKeyRotateRight, True, True), + kKMEditLine5Row1: _KeyLine(PlasmaControlKeys.kKeyJump, True, True), + kKMEditLine6Row1: _KeyLine(PlasmaControlKeys.kKeyStrafeLeft, True, True), + kKMEditLine7Row1: _KeyLine(PlasmaControlKeys.kKeyStrafeRight, True, True), + kKMEditLine8Row1: _KeyLine(PlasmaControlKeys.kKeyExitMode, True, True), + kKMEditLine9Row1: _KeyLine(PlasmaControlKeys.kKeySetFirstPersonMode, True, True), + kKMEditLine10Row1: _KeyLine("Game.KIOpenYeeshaBook", True, True), + kKMEditLine11Row1: _KeyLine("Game.KIHelp", True, True), + kKMEditLine12Row1: _KeyLine("Game.KIOpenKI", False, True), + kKMEditLine13Row1: _KeyLine("Game.KITakePicture", False, True), + kKMEditLine14Row1: _KeyLine("Game.KICreateJournal", False, True), + kKMEditLine15Row1: _KeyLine(PlasmaControlKeys.kKeyPushToTalk, False, True), + kKMEditLine16Row1: _KeyLine("Game.EnterChatMode", False, True), + kKMEditLine17Row1: _KeyLine("Game.KICreateMarkerFolder", False, True), + kKMEditLine18Row1: _KeyLine("Game.KICreateMarker", False, True), +} + gKM1ControlCodesRow2 = { - kKMEditLine1Row2 : (PlasmaControlKeys.kKeyMoveForward,1,1) ,\ - kKMEditLine2Row2 : (PlasmaControlKeys.kKeyMoveBackward,1,1) ,\ - kKMEditLine3Row2 : (PlasmaControlKeys.kKeyRotateLeft,1,1) ,\ - kKMEditLine4Row2 : (PlasmaControlKeys.kKeyRotateRight,1,1) ,\ - kKMEditLine5Row2 : (PlasmaControlKeys.kKeyJump,1,1) ,\ - kKMEditLine6Row2 : (PlasmaControlKeys.kKeyStrafeLeft,1,1) ,\ - kKMEditLine7Row2 : (PlasmaControlKeys.kKeyStrafeRight,1,1) ,\ - kKMEditLine8Row2 : (PlasmaControlKeys.kKeyExitMode,1,1) ,\ - kKMEditLine9Row2 : (PlasmaControlKeys.kKeySetFirstPersonMode,1,1) ,\ - kKMEditLine10Row2 : (None,0,0),\ - kKMEditLine11Row2 : (None,0,0) ,\ - kKMEditLine12Row2 : (None,0,0),\ - kKMEditLine13Row2 : (None,0,0) ,\ - kKMEditLine14Row2 : (None,0,0) ,\ - kKMEditLine15Row2 : (PlasmaControlKeys.kKeyPushToTalk,0,1) ,\ - kKMEditLine16Row2 : (None,0,0) ,\ - kKMEditLine17Row2 : (None,0,0) ,\ - kKMEditLine18Row2 : (None,0,0) ,\ - } - -defaultControlCodeBinds = { PlasmaControlKeys.kKeyMoveForward : ( "UpArrow","(unmapped)" ) ,\ - PlasmaControlKeys.kKeyMoveBackward : ( "DownArrow","(unmapped)" ),\ - PlasmaControlKeys.kKeyRotateLeft : ( "LeftArrow","(unmapped)" ) ,\ - PlasmaControlKeys.kKeyRotateRight : ( "RightArrow","(unmapped)" ) ,\ - PlasmaControlKeys.kKeyJump : ( "SpaceBar","(unmapped)" ),\ - PlasmaControlKeys.kKeyStrafeLeft : ( "Comma","(unmapped)" ) ,\ - PlasmaControlKeys.kKeyStrafeRight : ( "Period","(unmapped)" ) ,\ - PlasmaControlKeys.kKeyExitMode : ( "Backspace","Esc" ) ,\ - PlasmaControlKeys.kKeySetFirstPersonMode : ( "F1","F_C" ) ,\ - "Game.KIOpenYeeshaBook" : ("F3","(unmapped)"),\ - "Game.KIHelp" : ("F4","(unmapped)"),\ - "Game.KIOpenKI" : ("F2","(unmapped)"),\ - "Game.KITakePicture" : ("F5","(unmapped)"),\ - "Game.KICreateJournal" : ("F6","(unmapped)"),\ - PlasmaControlKeys.kKeyPushToTalk : ( "Tab","(unmapped)" ) ,\ - "Game.EnterChatMode" : ("(unmapped)","(unmapped)"),\ - "Game.KICreateMarkerFolder" : ("F8","(unmapped)"),\ - "Game.KICreateMarker" : ("F7","(unmapped)"),\ - } - -defaultControlCodeBindsOrdered = [ PlasmaControlKeys.kKeyMoveForward, PlasmaControlKeys.kKeyMoveBackward, PlasmaControlKeys.kKeyRotateLeft, PlasmaControlKeys.kKeyRotateRight, PlasmaControlKeys.kKeyJump, PlasmaControlKeys.kKeyStrafeLeft, PlasmaControlKeys.kKeyStrafeRight, PlasmaControlKeys.kKeyExitMode, PlasmaControlKeys.kKeySetFirstPersonMode, "Game.KIOpenYeeshaBook", "Game.KIHelp", "Game.KIOpenKI", "Game.KITakePicture", "Game.KICreateJournal", PlasmaControlKeys.kKeyPushToTalk, "Game.EnterChatMode", "Game.KICreateMarkerFolder", "Game.KICreateMarker"] + kKMEditLine1Row2: _KeyLine(PlasmaControlKeys.kKeyMoveForward, True, True), + kKMEditLine2Row2: _KeyLine(PlasmaControlKeys.kKeyMoveBackward, True, True), + kKMEditLine3Row2: _KeyLine(PlasmaControlKeys.kKeyRotateLeft, True, True), + kKMEditLine4Row2: _KeyLine(PlasmaControlKeys.kKeyRotateRight, True, True), + kKMEditLine5Row2: _KeyLine(PlasmaControlKeys.kKeyJump, True, True), + kKMEditLine6Row2: _KeyLine(PlasmaControlKeys.kKeyStrafeLeft, True, True), + kKMEditLine7Row2: _KeyLine(PlasmaControlKeys.kKeyStrafeRight, True, True), + kKMEditLine8Row2: _KeyLine(PlasmaControlKeys.kKeyExitMode, True, True), + kKMEditLine9Row2: _KeyLine(PlasmaControlKeys.kKeySetFirstPersonMode, True, True), + kKMEditLine10Row2: _KeyLine(None, False, False), + kKMEditLine11Row2: _KeyLine(None, False, False), + kKMEditLine12Row2: _KeyLine(None, False, False), + kKMEditLine13Row2: _KeyLine(None, False, False), + kKMEditLine14Row2: _KeyLine(None, False, False), + kKMEditLine15Row2: _KeyLine(PlasmaControlKeys.kKeyPushToTalk, False, True), + kKMEditLine16Row2: _KeyLine(None, False, False), + kKMEditLine17Row2: _KeyLine(None, False, False), + kKMEditLine18Row2: _KeyLine(None, False, False), +} + +defaultControlCodeBinds = { + PlasmaControlKeys.kKeyMoveForward: ("UpArrow", "(unmapped)"), + PlasmaControlKeys.kKeyMoveBackward: ("DownArrow", "(unmapped)"), + PlasmaControlKeys.kKeyRotateLeft: ("LeftArrow", "(unmapped)"), + PlasmaControlKeys.kKeyRotateRight: ("RightArrow", "(unmapped)"), + PlasmaControlKeys.kKeyJump: ("SpaceBar", "(unmapped)"), + PlasmaControlKeys.kKeyStrafeLeft: ("Comma", "(unmapped)"), + PlasmaControlKeys.kKeyStrafeRight: ("Period", "(unmapped)"), + PlasmaControlKeys.kKeyExitMode: ("Backspace", "Esc"), + PlasmaControlKeys.kKeySetFirstPersonMode: ("F1", "F_C"), + "Game.KIOpenYeeshaBook": ("F3", "(unmapped)"), + "Game.KIHelp": ("F4", "(unmapped)"), + "Game.KIOpenKI": ("F2", "(unmapped)"), + "Game.KITakePicture": ("F5", "(unmapped)"), + "Game.KICreateJournal": ("F6", "(unmapped)"), + PlasmaControlKeys.kKeyPushToTalk: ( "Tab", "(unmapped)" ), + "Game.EnterChatMode": ("(unmapped)", "(unmapped)"), + "Game.KICreateMarkerFolder": ("F8", "(unmapped)"), + "Game.KICreateMarker": ("F7", "(unmapped)"), +} + +defaultControlCodeBindsOrdered = [ + PlasmaControlKeys.kKeyMoveForward, + PlasmaControlKeys.kKeyMoveBackward, + PlasmaControlKeys.kKeyRotateLeft, + PlasmaControlKeys.kKeyRotateRight, + PlasmaControlKeys.kKeyJump, + PlasmaControlKeys.kKeyStrafeLeft, + PlasmaControlKeys.kKeyStrafeRight, + PlasmaControlKeys.kKeyExitMode, + PlasmaControlKeys.kKeySetFirstPersonMode, + "Game.KIOpenYeeshaBook", + "Game.KIHelp", + "Game.KIOpenKI", + "Game.KITakePicture", + "Game.KICreateJournal", + PlasmaControlKeys.kKeyPushToTalk, + "Game.EnterChatMode", + "Game.KICreateMarkerFolder", + "Game.KICreateMarker", +] kVideoQuality = ["Low", "Medium", "High", "Ultra"] kVideoTextureQuality = ["Low", "Medium", "High"] From 94a0b3d3ad1c5c2866763ef5dd69fc7e30f08f4f Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 9 Mar 2024 17:44:43 -0500 Subject: [PATCH 2/7] Fix type mismatch in ptGUIEditControl. --- .../Plasma/FeatureLib/pfPython/pyGUIControlEditBoxGlue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Plasma/FeatureLib/pfPython/pyGUIControlEditBoxGlue.cpp b/Sources/Plasma/FeatureLib/pfPython/pyGUIControlEditBoxGlue.cpp index 1692302a27..4bab21f400 100644 --- a/Sources/Plasma/FeatureLib/pfPython/pyGUIControlEditBoxGlue.cpp +++ b/Sources/Plasma/FeatureLib/pfPython/pyGUIControlEditBoxGlue.cpp @@ -167,12 +167,12 @@ PYTHON_METHOD_DEFINITION(ptGUIControlEditBox, setSpecialCaptureKeyMode, args) PYTHON_METHOD_DEFINITION_NOARGS(ptGUIControlEditBox, getLastKeyCaptured) { - return PyLong_FromLong(self->fThis->GetLastKeyCaptured()); + return PyLong_FromUnsignedLong(self->fThis->GetLastKeyCaptured()); } PYTHON_METHOD_DEFINITION_NOARGS(ptGUIControlEditBox, getLastModifiersCaptured) { - return PyLong_FromLong(self->fThis->GetLastModifiersCaptured()); + return PyLong_FromUnsignedLong(self->fThis->GetLastModifiersCaptured()); } PYTHON_METHOD_DEFINITION(ptGUIControlEditBox, setLastKeyCapture, args) From 78f151b1372523a0728d8c4c6e823a761705b11a Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 9 Mar 2024 17:45:53 -0500 Subject: [PATCH 3/7] Cleanup key binding code. Previously, it was possible to get the key map chronicle into an invalid state with the same key bound to multiple controls. You can reproduce that by binding UpArrow to "start chat" then rebinding UpArrow to "move forward". The chronicle will then have two entries for UpArrow in it. The bindings will behave as you expect until you quit and restart Uru, at which point UpArrow will be bound to "start chat" again. The only way to fix this is by resetting the key map to default. To fix this, I cleaned up the code to make the ownership of the key map more clear. Previously, the code half-handedly updated the vault chronicle value and the key map. Now, we bind any input directly, and completely rewrite the chronicle each time a key is bound. In this way, the UI display, key bindings, and key chronicle all have a single source of truth. This also includes general code cleanups, modernizing the Python. For example, we can now rely on the key dictionary being stored in the same order that it's initialized. --- Scripts/Python/xOptionsMenu.py | 194 ++++++++++++--------------------- 1 file changed, 68 insertions(+), 126 deletions(-) diff --git a/Scripts/Python/xOptionsMenu.py b/Scripts/Python/xOptionsMenu.py index c383edbbb3..f2b04f5a45 100644 --- a/Scripts/Python/xOptionsMenu.py +++ b/Scripts/Python/xOptionsMenu.py @@ -301,7 +301,7 @@ class _KeyLine(NamedTuple): kKMEditLine18Row2: _KeyLine(None, False, False), } -defaultControlCodeBinds = { +kDefaultControlCodeBinds = { PlasmaControlKeys.kKeyMoveForward: ("UpArrow", "(unmapped)"), PlasmaControlKeys.kKeyMoveBackward: ("DownArrow", "(unmapped)"), PlasmaControlKeys.kKeyRotateLeft: ("LeftArrow", "(unmapped)"), @@ -322,26 +322,7 @@ class _KeyLine(NamedTuple): "Game.KICreateMarker": ("F7", "(unmapped)"), } -defaultControlCodeBindsOrdered = [ - PlasmaControlKeys.kKeyMoveForward, - PlasmaControlKeys.kKeyMoveBackward, - PlasmaControlKeys.kKeyRotateLeft, - PlasmaControlKeys.kKeyRotateRight, - PlasmaControlKeys.kKeyJump, - PlasmaControlKeys.kKeyStrafeLeft, - PlasmaControlKeys.kKeyStrafeRight, - PlasmaControlKeys.kKeyExitMode, - PlasmaControlKeys.kKeySetFirstPersonMode, - "Game.KIOpenYeeshaBook", - "Game.KIHelp", - "Game.KIOpenKI", - "Game.KITakePicture", - "Game.KICreateJournal", - PlasmaControlKeys.kKeyPushToTalk, - "Game.EnterChatMode", - "Game.KICreateMarkerFolder", - "Game.KICreateMarker", -] +kControlCodes = tuple(kDefaultControlCodeBinds.keys()) kVideoQuality = ["Low", "Medium", "High", "Ultra"] kVideoTextureQuality = ["Low", "Medium", "High"] @@ -538,12 +519,6 @@ def OnServerInitComplete(self): if self.refreshBindings: self.refreshBindings = False - vault = ptVault() - entry = vault.findChronicleEntry("KeyMap") - if entry is None: - # not found... create defaults - self.ISetDefaultKeyMappings() - self.LoadAdvSettings() self.LoadKeyMap() GammaVal = self.getChronicleVar("gamma") @@ -723,80 +698,15 @@ def OnGUINotify(self,id,control,event): kmID = control.getTagID() if kmID == kKMOkBtn: KeyMapDlg.dialog.hide() - elif kmID in gKM1ControlCodesRow1.keys(): - NewKeyMapString = "" - # get the new keys and bind - km = ptKeyMap() - cCode,spFlag,mpFlag = gKM1ControlCodesRow1[kmID] - if isinstance(cCode, str): - key1 = km.convertVKeyToChar(control.getLastKeyCaptured(),control.getLastModifiersCaptured()) - km.bindKeyToConsoleCommand(key1,cCode) - KeyMapString = self.getChronicleVar("KeyMap") - KeyMapArray = KeyMapString.split() - KeyMapArray[(kmID-300)] = key1 - for key in KeyMapArray: - NewKeyMapString += key + " " - self.setNewChronicleVar("KeyMap", NewKeyMapString.rstrip()) - elif cCode is not None: - otherID = kmID + 100 - otherField = ptGUIControlEditBox(KeyMapDlg.dialog.getControlFromTag(otherID)) - key1 = km.convertVKeyToChar(control.getLastKeyCaptured(),control.getLastModifiersCaptured()) - key2 = km.convertVKeyToChar(otherField.getLastKeyCaptured(),otherField.getLastModifiersCaptured()) - controlStr = km.convertControlCodeToString(cCode) - km.bindKey(key1,key2,controlStr) - KeyMapString = self.getChronicleVar("KeyMap") - KeyMapArray = KeyMapString.split() - KeyMapArray[(kmID-300)] = key1 + "$" + key2 + " " - for key in KeyMapArray: - NewKeyMapString += key + " " - self.setNewChronicleVar("KeyMap", NewKeyMapString.rstrip()) - # lose the focus when done - KeyMapDlg.dialog.noFocus() - # force writing the keymap - km.writeKeyMap() - # re-show the keymap because they may have been stupid and map the same key to multiple actions - self.IShowMappedKeys(KeyMapDlg.dialog,gKM1ControlCodesRow1,gKM1ControlCodesRow2) - # need to re-set the ini file, in case something got unmapped - #self.IMatchIniToGame() - elif kmID in gKM1ControlCodesRow2.keys(): - NewKeyMapString = "" - # get the new keys and bind - km = ptKeyMap() - cCode,spFlag,mpFlag = gKM1ControlCodesRow2[kmID] - if isinstance(cCode, str): - # console command - this shouldn't really happen! - key1 = km.convertVKeyToChar(control.getLastKeyCaptured(),control.getLastModifiersCaptured()) - km.bindKeyToConsoleCommand(key1,cCode) - # console keys not in input.ini... yet - KeyMapString = self.getChronicleVar("KeyMap") - KeyMapArray = KeyMapString.split() - KeyMapArray[(kmID-300)] = key1 - for key in KeyMapArray: - NewKeyMapString += key + " " - self.setNewChronicleVar("KeyMap", NewKeyMapString.rstrip()) - #xIniInput.SetConsoleKey('"'+cCode+'"',key1+',') - elif cCode is not None: - otherID = kmID - 100 - otherField = ptGUIControlEditBox(KeyMapDlg.dialog.getControlFromTag(otherID)) - key2 = km.convertVKeyToChar(control.getLastKeyCaptured(),control.getLastModifiersCaptured()) - key1 = km.convertVKeyToChar(otherField.getLastKeyCaptured(),otherField.getLastModifiersCaptured()) - controlStr = km.convertControlCodeToString(cCode) - km.bindKey(key1,key2,controlStr) - KeyMapString = self.getChronicleVar("KeyMap") - KeyMapArray = KeyMapString.split() - KeyMapArray[(otherID-300)] = key1 + "$" + key2 + " " - for key in KeyMapArray: - NewKeyMapString += key + " " - self.setNewChronicleVar("KeyMap", NewKeyMapString.rstrip()) - #xIniInput.SetControlKey('"'+controlStr+'"',key1+',',key2+',') - # lose the focus when done + elif kmID in gKM1ControlCodesRow1 or kmID in gKM1ControlCodesRow2: + self.ISetKeyMapping( + kmID - 300, + control.getLastKeyCaptured(), + control.getLastModifiersCaptured(), + kmID in gKM1ControlCodesRow1 + ) KeyMapDlg.dialog.noFocus() - # force writing the keymap - km.writeKeyMap() - # re-show the keymap because they may have been stupid and map the same key to multiple actions - self.IShowMappedKeys(KeyMapDlg.dialog,gKM1ControlCodesRow1,gKM1ControlCodesRow2) - # need to re-set the ini file, in case something got unmapped - #self.IMatchIniToGame() + self.IShowMappedKeys(KeyMapDlg.dialog, gKM1ControlCodesRow1, gKM1ControlCodesRow2) elif kmID == kKMDefaultsBtn: self.ISetDefaultKeyMappings() self.IShowMappedKeys(KeyMapDlg.dialog,gKM1ControlCodesRow1,gKM1ControlCodesRow2) @@ -1855,23 +1765,20 @@ def LoadKeyMap(self): km = ptKeyMap() KeyMapString = self.getChronicleVar("KeyMap") if not KeyMapString: - PtDebugPrint("xOptionsMenu.LoadKeyMap():\tHmm... Empty chronicle...") + PtDebugPrint("xOptionsMenu.LoadKeyMap():\tHmm... Empty chronicle... Setting to default.") + self.ISetDefaultKeyMappings() return - KeyMapArray = KeyMapString.split() # set the key binds back to the saved - for counter, control_code in enumerate(defaultControlCodeBindsOrdered): - if isinstance(control_code, str): - key1 = KeyMapArray[counter] - PtDebugPrint("Binding " + key1 + " to " + control_code) - km.bindKeyToConsoleCommand(key1,control_code) + for controlCode, mappedKey in zip(kDefaultControlCodeBinds, KeyMapString.split(" ")): + if isinstance(controlCode, str): + PtDebugPrint(f"xOptionsMenu.LoadKeyMap(): Binding {mappedKey=} to {controlCode=}", level=kWarningLevel) + km.bindKeyToConsoleCommand(mappedKey, controlCode) else: - controlStr = km.convertControlCodeToString(control_code) - SubArray = KeyMapArray[counter].split("$") - key1 = SubArray[0] - key2 = SubArray[1] - PtDebugPrint("Binding " + key1 + " & " + key2 + " to " + controlStr) - km.bindKey(key1,key2,controlStr) + controlStr = km.convertControlCodeToString(controlCode) + keys = mappedKey.split("$") + PtDebugPrint(f"xOptionsMenu.LoadKeyMap(): Binding {keys=} to {controlStr=}", level=kWarningLevel) + km.bindKey(*keys, controlStr) def IsThereACover(self,bookHtml): # search the bookhtml string looking for a cover @@ -1880,6 +1787,48 @@ def IsThereACover(self,bookHtml): return 1 return 0 + def IUpdateKeyMapChron(self) -> None: + keyMapStr = " ".join( + self.IGetBoundKey(controlCode) if isinstance(controlCode, str) else f"{self.IGetBoundKey(controlCode, 0)}${self.IGetBoundKey(controlCode, 1)}" + for controlCode in kDefaultControlCodeBinds + ) + self.setNewChronicleVar("KeyMap", keyMapStr) + + def IGetBoundKey(self, controlCode: Union[int, str], keyIdx: int = 0) -> str: + km = ptKeyMap() + if isinstance(controlCode, str): + assert keyIdx == 0 + return km.convertVKeyToChar(km.getBindingKeyConsole(controlCode), km.getBindingFlagsConsole(controlCode)) + elif keyIdx == 0: + return km.convertVKeyToChar(km.getBindingKey1(controlCode), km.getBindingFlags1(controlCode)) + elif keyIdx == 1: + return km.convertVKeyToChar(km.getBindingKey2(controlCode), km.getBindingFlags2(controlCode)) + else: + raise ValueError(f"{keyIdx=}") + + def ISetKeyMapping(self, controlCodeId: int, vkey: int, modifiers: int, isPrimary: bool) -> None: + km = ptKeyMap() + newKeyStr = km.convertVKeyToChar(vkey, modifiers) + + # This will cause any previous uses of the key to be unbound. + controlCode = kControlCodes[controlCodeId] + if isinstance(controlCode, str): + PtDebugPrint(f"xOptionsMenu.ISetKeyMapping(): Binding {newKeyStr=} to console command {controlCode=}") + km.bindKeyToConsoleCommand(newKeyStr, controlCode) + else: + if isPrimary: + primaryStr = newKeyStr + secondaryStr = km.convertVKeyToChar(km.getBindingKey2(controlCode), km.getBindingFlags2(controlCode)) + else: + primaryStr = km.convertVKeyToChar(km.getBindingKey1(controlCode), km.getBindingFlags1(controlCode)) + secondaryStr = newKeyStr + + controlStr = km.convertControlCodeToString(controlCode) + PtDebugPrint(f"xOptionsMenu.ISetKeyMapping(): Binding {primaryStr=} {secondaryStr=} to {controlStr=}") + km.bindKey(primaryStr, secondaryStr, controlStr) + + self.IUpdateKeyMapChron() + def IShowMappedKeys(self,dlg,mapRow1,mapRow2): km = ptKeyMap() for cID in mapRow1.keys(): @@ -1919,20 +1868,13 @@ def IShowMappedKeys(self,dlg,mapRow1,mapRow2): def ISetDefaultKeyMappings(self): km = ptKeyMap() - KeyMapString = "" - # set the key binds back to the defaults - for control_code in defaultControlCodeBindsOrdered: - if isinstance(control_code, str): - key1 = defaultControlCodeBinds[control_code][0] - km.bindKeyToConsoleCommand(key1,control_code) - KeyMapString += key1 + " " + for controlCode, (key1, key2) in kDefaultControlCodeBinds.items(): + if isinstance(controlCode, str): + km.bindKeyToConsoleCommand(key1, controlCode) else: - controlStr = km.convertControlCodeToString(control_code) - key1, key2 = defaultControlCodeBinds[control_code] - km.bindKey(key1,key2,controlStr) - KeyMapString += key1 + "$" + key2 + " " - - self.setNewChronicleVar("KeyMap", KeyMapString.rstrip()) + controlStr = km.convertControlCodeToString(controlCode) + km.bindKey(key1, key2, controlStr) + self.IUpdateKeyMapChron() def res_comp(elem1, elem2): elem1w = int(elem1[:elem1.find("x")]) From 3e60e767ff0ae6f9c35c2ac630b255e2749cadaa Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 9 Mar 2024 18:01:15 -0500 Subject: [PATCH 4/7] Fix "Unused" appearing in the key map dialog. This entry in the key conversion LUT is hiding the expected value of "(unmapped)". I fixed the captialization to match the other localizations. --- Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp b/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp index 9ef59f81d3..1c88124c50 100644 --- a/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp +++ b/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp @@ -659,7 +659,7 @@ ST::string plKeyMap::GetStringUnmapped() default: break; } - return ST_LITERAL("(unmapped)"); + return ST_LITERAL("(Unmapped)"); } // If the binding has one of these keys, but not the other, go and bind the other @@ -784,7 +784,6 @@ const std::map plKeyMap::fKeyConversionEnglish = { KEY_BACKSLASH, ST_LITERAL("Backslash")}, { KEY_RBRACKET, ST_LITERAL("RightBracket")}, { KEY_QUOTE, ST_LITERAL("Quote")}, - { 0xffffffff, ST_LITERAL("Unused")}, }; const std::map plKeyMap::fKeyConversionFrench = From 2c6e943a89f6f5e978b9de1e1b919c52ccca1c08 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 9 Mar 2024 18:21:26 -0500 Subject: [PATCH 5/7] Allow unbinding keys by pressing the same key. This is useful if you want to remove the "start chat" binding. --- Scripts/Python/xOptionsMenu.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Scripts/Python/xOptionsMenu.py b/Scripts/Python/xOptionsMenu.py index f2b04f5a45..855dd7e327 100644 --- a/Scripts/Python/xOptionsMenu.py +++ b/Scripts/Python/xOptionsMenu.py @@ -1810,8 +1810,12 @@ def ISetKeyMapping(self, controlCodeId: int, vkey: int, modifiers: int, isPrimar km = ptKeyMap() newKeyStr = km.convertVKeyToChar(vkey, modifiers) - # This will cause any previous uses of the key to be unbound. + # If this is the same key as before, unmap the binding. controlCode = kControlCodes[controlCodeId] + if self.IGetBoundKey(controlCode, keyIdx=0 if isPrimary else 1) == newKeyStr: + newKeyStr = "(unmapped)" + + # This will cause any previous uses of the key to be unbound. if isinstance(controlCode, str): PtDebugPrint(f"xOptionsMenu.ISetKeyMapping(): Binding {newKeyStr=} to console command {controlCode=}") km.bindKeyToConsoleCommand(newKeyStr, controlCode) From 8bcc25c971ae07d33263e4ebf35553093ebf2678 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 9 Mar 2024 20:10:52 -0500 Subject: [PATCH 6/7] Use `str.partition()`for robustness. Co-authored-by: dgelessus --- Scripts/Python/xOptionsMenu.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Scripts/Python/xOptionsMenu.py b/Scripts/Python/xOptionsMenu.py index 855dd7e327..64722ec7a5 100644 --- a/Scripts/Python/xOptionsMenu.py +++ b/Scripts/Python/xOptionsMenu.py @@ -1776,9 +1776,9 @@ def LoadKeyMap(self): km.bindKeyToConsoleCommand(mappedKey, controlCode) else: controlStr = km.convertControlCodeToString(controlCode) - keys = mappedKey.split("$") - PtDebugPrint(f"xOptionsMenu.LoadKeyMap(): Binding {keys=} to {controlStr=}", level=kWarningLevel) - km.bindKey(*keys, controlStr) + key1, _, key2 = mappedKey.partition("$") + PtDebugPrint(f"xOptionsMenu.LoadKeyMap(): Binding {key1=} & {key2=} to {controlStr=}", level=kWarningLevel) + km.bindKey(key1, key2, controlStr) def IsThereACover(self,bookHtml): # search the bookhtml string looking for a cover From 5f492a744643dedd95c45466951271df718c54ba Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sat, 9 Mar 2024 20:11:32 -0500 Subject: [PATCH 7/7] Revert captialization change. --- Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp b/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp index 1c88124c50..338b6a34a1 100644 --- a/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp +++ b/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp @@ -659,7 +659,7 @@ ST::string plKeyMap::GetStringUnmapped() default: break; } - return ST_LITERAL("(Unmapped)"); + return ST_LITERAL("(unmapped)"); } // If the binding has one of these keys, but not the other, go and bind the other