diff --git a/Scripts/Python/xOptionsMenu.py b/Scripts/Python/xOptionsMenu.py index eee1a991f2..64722ec7a5 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,77 @@ # 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), +} + +kDefaultControlCodeBinds = { + 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)"), +} + +kControlCodes = tuple(kDefaultControlCodeBinds.keys()) kVideoQuality = ["Low", "Medium", "High", "Ultra"] kVideoTextureQuality = ["Low", "Medium", "High"] @@ -517,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") @@ -702,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) @@ -1834,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) + 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 @@ -1859,6 +1787,52 @@ 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) + + # 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) + 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(): @@ -1898,20 +1872,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")]) 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) diff --git a/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp b/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp index 9ef59f81d3..338b6a34a1 100644 --- a/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp +++ b/Sources/Plasma/NucleusLib/pnInputCore/plInputMap.cpp @@ -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 =