From 193932300ba2e7c93c5a0f0adbd2586964d3fce4 Mon Sep 17 00:00:00 2001 From: michl Date: Sun, 25 Feb 2018 14:13:12 +0000 Subject: [PATCH] LCL: ShortCutToText faster, with array. Issue #30992. Patch by AlexeyT git-svn-id: trunk@57373 - --- lcl/lclproc.pas | 466 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 308 insertions(+), 158 deletions(-) diff --git a/lcl/lclproc.pas b/lcl/lclproc.pas index c0d015427d..e4086dc5df 100644 --- a/lcl/lclproc.pas +++ b/lcl/lclproc.pas @@ -415,10 +415,278 @@ var MenuKeyCaps: array[TMenuKeyCap] of string; MenuKeyCapsInited: boolean = false; +const + // MS documentation: + // https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx + // + // Note: ShortcutToText must ignore single key Ctrl, Alt, Shift, Win, + // so these items have empty str here + // + KeyCodeStrings: array[1..$FF] of string = ( + 'Mouse_Left', // 0x1 - VK_LBUTTON + 'Mouse_Right', // 0x2 - VK_RBUTTON + 'Cancel', // 0x3 - VK_CANCEL - generated by Ctrl+Break + 'Mouse_Middle', // 0x4 - VK_MBUTTON + 'Mouse_X1', // 0x5 - VK_XBUTTON1 + 'Mouse_X2', // 0x6 - VK_XBUTTON2 + '', // 0x7 + 'Backspace', // 0x8 - VK_BACK + 'Tab', // 0x9 - VK_TAB + '', // 0xa + '', // 0xb + 'NumClear', // 0xc - VK_CLEAR - generated by Num5 (NumLock off) + 'Enter', // 0xd - VK_RETURN + '', // 0xe + '', // 0xf + '', //'Shift', // 0x10 - VK_SHIFT + '', //'Ctrl', // 0x11 - VK_CONTROL + '', //'Alt', // 0x12 - VK_MENU + 'Break', // 0x13 - VK_PAUSE - Pause/Break key + 'CapsLock', // 0x14 - VK_CAPITAL + 'IME_Kana', // 0x15 - VK_KANA + '', // 0x16 + 'IME_Junja', // 0x17 - VK_JUNJA + 'IME_final', // 0x18 - VK_FINAL + 'IME_Hanja', // 0x19 - VK_HANJA + '', // 0x1a + 'Esc', // 0x1b - VK_ESCAPE + 'IME_convert', // 0x1c - VK_CONVERT + 'IME_nonconvert', // 0x1d - VK_NONCONVERT + 'IME_accept', // 0x1e - VK_ACCEPT + 'IME_mode_change', // 0x1f - VK_MODECHANGE + 'Space', // 0x20 - VK_SPACE + 'PgUp', // 0x21 - VK_PRIOR + 'PgDown', // 0x22 - VK_NEXT + 'End', // 0x23 - VK_END + 'Home', // 0x24 - VK_HOME + 'Left', // 0x25 - VK_LEFT + 'Up', // 0x26 - VK_UP + 'Right', // 0x27 - VK_RIGHT + 'Down', // 0x28 - VK_DOWN + 'Select', // 0x29 - VK_SELECT + 'Print', // 0x2a - VK_PRINT + 'Execute', // 0x2b - VK_EXECUTE + 'PrintScreen', // 0x2c - VK_SNAPSHOT + 'Ins', // 0x2d - VK_INSERT + 'Del', // 0x2e - VK_DELETE + 'Help', // 0x2f - VK_HELP + '0', // 0x30 + '1', // 0x31 + '2', // 0x32 + '3', // 0x33 + '4', // 0x34 + '5', // 0x35 + '6', // 0x36 + '7', // 0x37 + '8', // 0x38 + '9', // 0x39 + '', // 0x3a + '', // 0x3b + '', // 0x3c + '', // 0x3d + '', // 0x3e + '', // 0x3f + '', // 0x40 + 'A', // 0x41 + 'B', // 0x42 + 'C', // 0x43 + 'D', // 0x44 + 'E', // 0x45 + 'F', // 0x46 + 'G', // 0x47 + 'H', // 0x48 + 'I', // 0x49 + 'J', // 0x4a + 'K', // 0x4b + 'L', // 0x4c + 'M', // 0x4d + 'N', // 0x4e + 'O', // 0x4f + 'P', // 0x50 + 'Q', // 0x51 + 'R', // 0x52 + 'S', // 0x53 + 'T', // 0x54 + 'U', // 0x55 + 'V', // 0x56 + 'W', // 0x57 + 'X', // 0x58 + 'Y', // 0x59 + 'Z', // 0x5a + '', //'LWindows', // 0x5b - VK_LWIN + '', //'RWindows', // 0x5c - VK_RWIN + 'PopUp', // 0x5d - VK_APPS - PC, key near right Ctrl + '', // 0x5e + 'Sleep', // 0x5f - VK_SLEEP + 'Num0', // 0x60 - VK_NUMPAD0 + 'Num1', // 0x61 + 'Num2', // 0x62 + 'Num3', // 0x63 + 'Num4', // 0x64 + 'Num5', // 0x65 + 'Num6', // 0x66 + 'Num7', // 0x67 + 'Num8', // 0x68 + 'Num9', // 0x69 - VK_NUMPAD9 + 'NumMul', // 0x6a - VK_MULTIPLY + 'NumPlus', // 0x6b - VK_ADD + 'NumSepar', // 0x6c - VK_SEPARATOR + 'NumMinus', // 0x6d - VK_SUBTRACT + 'NumDot', // 0x6e - VK_DECIMAL + 'NumDiv', // 0x6f - VK_DIVIDE + 'F1', // 0x70 - VK_F1 + 'F2', // 0x71 + 'F3', // 0x72 + 'F4', // 0x73 + 'F5', // 0x74 + 'F6', // 0x75 + 'F7', // 0x76 + 'F8', // 0x77 + 'F9', // 0x78 + 'F10', // 0x79 + 'F11', // 0x7a + 'F12', // 0x7b + 'F13', // 0x7c + 'F14', // 0x7d + 'F15', // 0x7e + 'F16', // 0x7f + 'F17', // 0x80 + 'F18', // 0x81 + 'F19', // 0x82 + 'F20', // 0x83 + 'F21', // 0x84 + 'F22', // 0x85 + 'F23', // 0x86 + 'F24', // 0x87 - VK_F24 + '', // 0x88 + '', // 0x89 + '', // 0x8a + '', // 0x8b + '', // 0x8c + '', // 0x8d + '', // 0x8e + '', // 0x8f + 'NumLock', // 0x90 - VK_NUMLOCK + 'ScrollLock', // 0x91 - VK_SCROLL + 'OEM_0x92', // 0x92 + 'OEM_0x93', // 0x93 + 'OEM_0x94', // 0x94 + 'OEM_0x95', // 0x95 + 'OEM_0x96', // 0x96 + '', // 0x97 + '', // 0x98 + '', // 0x99 + '', // 0x9a + '', // 0x9b + '', // 0x9c + '', // 0x9d + '', // 0x9e + '', // 0x9f + '', //'LShift', // 0xa0 - VK_LSHIFT + '', //'RShift', // 0xa1 - VK_RSHIFT + '', //'LCtrl', // 0xa2 - VK_LCONTROL + '', //'RCtrl', // 0xa3 - VK_RCONTROL + '', //'LAlt', // 0xa4 - VK_LMENU + '', //'RAlt', // 0xa5 - VK_RMENU + 'BrowserBack', // 0xa6 - VK_BROWSER_BACK + 'BrowserForward', // 0xa7 - VK_BROWSER_FORWARD + 'BrowserRefresh', // 0xa8 - VK_BROWSER_REFRESH + 'BrowserStop', // 0xa9 - VK_BROWSER_STOP + 'BrowserSearch', // 0xaa - VK_BROWSER_SEARCH + 'BrowserFav', // 0xab - VK_BROWSER_FAVORITES + 'BrowserHome', // 0xac - VK_BROWSER_HOME + 'VolumeMute', // 0xad - VK_VOLUME_MUTE + 'VolumeDown', // 0xae - VK_VOLUME_DOWN + 'VolumeUp', // 0xaf - VK_VOLUME_UP + 'MediaNext', // 0xb0 - VK_MEDIA_NEXT_TRACK + 'MediaPrev', // 0xb1 - VK_MEDIA_PREV_TRACK + 'MediaStop', // 0xb2 - VK_MEDIA_STOP + 'MediaPlayPause', // 0xb3 - VK_MEDIA_PLAY_PAUSE + 'LaunchMail', // 0xb4 - VK_LAUNCH_MAIL + 'LaunchMedia', // 0xb5 - VK_LAUNCH_MEDIA_SELECT + 'LaunchApp1', // 0xb6 - VK_LAUNCH_APP1 + 'LaunchApp2', // 0xb7 - VK_LAUNCH_APP2 + '', // 0xb8 + '', // 0xb9 + ';', // 0xba - VK_OEM_1 - Can vary by keyboard, US keyboard, the ';:' key + '+', // 0xbb - VK_OEM_PLUS - For any country/region, the '+' key + ',', // 0xbc - VK_OEM_COMMA - For any country/region, the ',' key + '-', // 0xbd - VK_OEM_MINUS - For any country/region, the '-' key + '.', // 0xbe - VK_OEM_PERIOD - For any country/region, the '.' key + '/', // 0xbf - VK_OEM_2 - Can vary by keyboard, US keyboard, the '/?' key + '`', // 0xc0 - VK_OEM_3 - Can vary by keyboard, US keyboard, the '`~' key + '', // 0xc1 + '', // 0xc2 + '', // 0xc3 + '', // 0xc4 + '', // 0xc5 + '', // 0xc6 + '', // 0xc7 + '', // 0xc8 + '', // 0xc9 + '', // 0xca + '', // 0xcb + '', // 0xcc + '', // 0xcd + '', // 0xce + '', // 0xcf + '', // 0xd0 + '', // 0xd1 + '', // 0xd2 + '', // 0xd3 + '', // 0xd4 + '', // 0xd5 + '', // 0xd6 + '', // 0xd7 + '', // 0xd8 + '', // 0xd9 + '', // 0xda + '[', // 0xdb - VK_OEM_4 - Can vary by keyboard, US keyboard, the '[{' key + '\', // 0xdc - VK_OEM_5 - Can vary by keyboard, US keyboard, the '\|' key + ']', // 0xdd - VK_OEM_6 - Can vary by keyboard, US keyboard, the ']}' key + '''', // 0xde - VK_OEM_7 - Can vary by keyboard, US keyboard, the 'single-quote/double-quote' key + 'OEM_8', // 0xdf - VK_OEM_8 + '', // 0xe0 + 'OEM_0xE1', // 0xe1 + '\', // 0xe2 - VK_OEM_102 - Either the angle bracket key or the backslash key on the RT 102-key keyboard + 'OEM_0xE3', // 0xe3 + 'OEM_0xE4', // 0xe4 + 'IME_process', // 0xe5 - VK_PROCESSKEY + 'OEM_0xE6', // 0xe6 + 'UnicodePacket', // 0xe7 - VK_PACKET + '', // 0xe8 + 'OEM_0xE9', // 0xe9 + 'OEM_0xEA', // 0xea + 'OEM_0xEB', // 0xeb + 'OEM_0xEC', // 0xec + 'OEM_0xED', // 0xed + 'OEM_0xEE', // 0xee + 'OEM_0xEF', // 0xef + 'OEM_0xF0', // 0xf0 + 'OEM_0xF1', // 0xf1 + 'OEM_0xF2', // 0xf2 + 'OEM_0xF3', // 0xf3 + 'OEM_0xF4', // 0xf4 + 'OEM_0xF5', // 0xf5 + 'Attn', // 0xf6 - VK_ATTN + 'CrSel', // 0xf7 - VK_CRSEL + 'ExSel', // 0xf8 - VK_EXSEL + 'EraseEOF', // 0xf9 - VK_EREOF + 'Play', // 0xfa - VK_PLAY + 'Zoom', // 0xfb - VK_ZOOM + '', // 0xfc + 'PA1', // 0xfd - VK_PA1 + 'OEM_Clear', // 0xfe - VK_OEM_CLEAR + '' // 0xff + ); + + procedure InitializeMenuKeyCaps; begin - if MenuKeyCapsInited=false then + if not MenuKeyCapsInited then begin + MenuKeyCapsInited:=true; + MenuKeyCaps[mkcBkSp]:=SmkcBkSp; MenuKeyCaps[mkcTab]:=SmkcTab; MenuKeyCaps[mkcEsc]:=SmkcEsc; @@ -438,58 +706,26 @@ begin MenuKeyCaps[mkcCtrl]:=SmkcCtrl; MenuKeyCaps[mkcAlt]:=SmkcAlt; MenuKeyCaps[mkcMeta]:=SmkcMeta; - MenuKeyCapsInited:=true; - end; -end; -function GetSpecialShortCutName(Key: integer): string; -begin - Result := ''; - case Key of - VK_CANCEL: Result := 'Cancel'; //generated by Ctrl+Break - VK_CLEAR: Result := 'NumClear'; //generated by Num5 (NumLock off) - VK_PAUSE: Result := 'Break'; - VK_CAPITAL: Result := 'CapsLock'; - VK_APPS: Result := 'PopUp'; //PC, near right Ctrl - VK_MULTIPLY: Result := 'NumMul'; - VK_ADD: Result := 'NumPlus'; - VK_SUBTRACT: Result := 'NumMinus'; - VK_DECIMAL: Result := 'NumDot'; - VK_DIVIDE: Result := 'NumDiv'; - VK_NUMLOCK: Result := 'NumLock'; - VK_SCROLL: Result := 'ScrollLock'; - VK_OEM_1: Result := ';'; // Can vary by keyboard, US keyboard, the ';:' key - VK_OEM_PLUS: Result := '+'; // For any country/region, the '+' key - VK_OEM_COMMA: Result := ','; // For any country/region, the ',' key - VK_OEM_MINUS: Result := '-'; // For any country/region, the '-' key - VK_OEM_PERIOD: Result := '.'; // For any country/region, the '.' key - VK_OEM_2: Result := '/'; // Can vary by keyboard, US keyboard, the '/?' key - VK_OEM_3: Result := '`'; // Can vary by keyboard, US keyboard, the '`~' key - VK_OEM_4: Result := '['; // Can vary by keyboard, US keyboard, the '[{' key - VK_OEM_5: Result := '\'; // Can vary by keyboard, US keyboard, the '\|' key - VK_OEM_6: Result := ']'; // Can vary by keyboard, US keyboard, the ']}' key - VK_OEM_7: Result := ''''; // Can vary by keyboard, US keyboard, the 'single-quote/double-quote' key - VK_OEM_102: Result := '\'; // Either the angle bracket key or the backslash key on the RT 102-key keyboard - - //Windows keyboard special: - $A6: Result := 'BrowserBack'; - $A7: Result := 'BrowserForward'; - $A8: Result := 'BrowserRefresh'; - $A9: Result := 'BrowserStop'; - $AA: Result := 'BrowserSearch'; - $AB: Result := 'BrowserFav'; - $AC: Result := 'BrowserHome'; - $AD: Result := 'VolumeMute'; - $AE: Result := 'VolumeDown'; - $AF: Result := 'VolumeUp'; - $B0: Result := 'MediaNext'; - $B1: Result := 'MediaPrev'; - $B2: Result := 'MediaStop'; - $B3: Result := 'MediaPlay'; - $B4: Result := 'LaunchMail'; - $B5: Result := 'LaunchMedia'; - $B6: Result := 'LaunchApp1'; - $B7: Result := 'LaunchApp2'; + KeyCodeStrings[VK_BACK]:=SmkcBkSp; + KeyCodeStrings[VK_TAB]:=SmkcTab; + KeyCodeStrings[VK_ESCAPE]:=SmkcEsc; + KeyCodeStrings[VK_RETURN]:=SmkcEnter; + KeyCodeStrings[VK_SPACE]:=SmkcSpace; + KeyCodeStrings[VK_PRIOR]:=SmkcPgUp; + KeyCodeStrings[VK_NEXT]:=SmkcPgDn; + KeyCodeStrings[VK_END]:=SmkcEnd; + KeyCodeStrings[VK_HOME]:=SmkcHome; + KeyCodeStrings[VK_LEFT]:=SmkcLeft; + KeyCodeStrings[VK_UP]:=SmkcUp; + KeyCodeStrings[VK_RIGHT]:=SmkcRight; + KeyCodeStrings[VK_DOWN]:=SmkcDown; + KeyCodeStrings[VK_INSERT]:=SmkcIns; + KeyCodeStrings[VK_DELETE]:=SmkcDel; + // must ignore single Shift, Alt, Ctrl in KeyCodeStrings + //KeyCodeStrings[VK_SHIFT]:=SmkcShift; + //KeyCodeStrings[VK_CONTROL]:=SmkcCtrl; + //KeyCodeStrings[VK_MENU]:=SmkcAlt; end; end; @@ -523,6 +759,14 @@ begin Result:=DefaultValue; end; +function KeyCodeToKeyString(Key: integer): string; +begin + if (Key >= Low(KeyCodeStrings)) and (Key <= High(KeyCodeStrings)) then + Result := KeyCodeStrings[Key] + else + Result := ''; +end; + // Used also by TWidgetSet.GetAcceleratorString function KeyAndShiftStateToKeyString(Key: word; ShiftState: TShiftState): String; @@ -533,79 +777,8 @@ function KeyAndShiftStateToKeyString(Key: word; ShiftState: TShiftState): String Result := Result + APart; end; - // Tricky routine. This only works for western languages - procedure AddKey; - begin - case Key of - VK_UNKNOWN :AddPart(ifsVK_UNKNOWN); - VK_LBUTTON :AddPart(ifsVK_LBUTTON); - VK_RBUTTON :AddPart(ifsVK_RBUTTON); - VK_CANCEL :AddPart(ifsVK_CANCEL); - VK_MBUTTON :AddPart(ifsVK_MBUTTON); - VK_BACK :AddPart(ifsVK_BACK); - VK_TAB :AddPart(ifsVK_TAB); - VK_CLEAR :AddPart(ifsVK_CLEAR); - VK_RETURN :AddPart(ifsVK_RETURN); - VK_SHIFT :AddPart(ifsVK_SHIFT); - VK_CONTROL :AddPart(ifsVK_CONTROL); - VK_MENU :AddPart(ifsVK_MENU); - VK_PAUSE :AddPart(ifsVK_PAUSE); - VK_CAPITAL :AddPart(ifsVK_CAPITAL); - VK_KANA :AddPart(ifsVK_KANA); - // VK_HANGUL :AddPart('Hangul'); - VK_JUNJA :AddPart(ifsVK_JUNJA); - VK_FINAL :AddPart(ifsVK_FINAL); - VK_HANJA :AddPart(ifsVK_HANJA ); - // VK_KANJI :AddPart('Kanji'); - VK_ESCAPE :AddPart(ifsVK_ESCAPE); - VK_CONVERT :AddPart(ifsVK_CONVERT); - VK_NONCONVERT :AddPart(ifsVK_NONCONVERT); - VK_ACCEPT :AddPart(ifsVK_ACCEPT); - VK_MODECHANGE :AddPart(ifsVK_MODECHANGE); - VK_SPACE :AddPart(ifsVK_SPACE); - VK_PRIOR :AddPart(ifsVK_PRIOR); - VK_NEXT :AddPart(ifsVK_NEXT); - VK_END :AddPart(ifsVK_END); - VK_HOME :AddPart(ifsVK_HOME); - VK_LEFT :AddPart(ifsVK_LEFT); - VK_UP :AddPart(ifsVK_UP); - VK_RIGHT :AddPart(ifsVK_RIGHT); - VK_DOWN :AddPart(ifsVK_DOWN); - VK_SELECT :AddPart(ifsVK_SELECT); - VK_PRINT :AddPart(ifsVK_PRINT); - VK_EXECUTE :AddPart(ifsVK_EXECUTE); - VK_SNAPSHOT :AddPart(ifsVK_SNAPSHOT); - VK_INSERT :AddPart(ifsVK_INSERT); - VK_DELETE :AddPart(ifsVK_DELETE); - VK_HELP :AddPart(ifsVK_HELP); - VK_0..VK_9 :AddPart(chr(ord('0')+Key-VK_0)); - VK_A..VK_Z :AddPart(chr(ord('A')+Key-VK_A)); - VK_LWIN :AddPart(ifsVK_LWIN); - VK_RWIN :AddPart(ifsVK_RWIN); - VK_APPS :AddPart(ifsVK_APPS); - VK_NUMPAD0..VK_NUMPAD9: AddPart(Format(ifsVK_NUMPAD,[Key-VK_NUMPAD0])); - VK_MULTIPLY :AddPart('*'); - VK_ADD :AddPart('+'); - VK_OEM_PLUS :AddPart('+'); - VK_SEPARATOR :AddPart('|'); - VK_SUBTRACT :AddPart('-'); - VK_OEM_MINUS :AddPart('-'); - VK_DECIMAL :AddPart('.'); - VK_OEM_PERIOD :AddPart('.'); - VK_OEM_COMMA :AddPart(','); - VK_DIVIDE :AddPart('/'); - VK_F1..VK_F24: AddPart('F'+IntToStr(Key-VK_F1+1)); - VK_NUMLOCK :AddPart(ifsVK_NUMLOCK); - VK_SCROLL :AddPart(ifsVK_SCROLL); - VK_OEM_2 :AddPart('OEM2'); - VK_OEM_3 :AddPart('OEM3'); -// VK_EQUAL :AddPart('='); -// VK_AT :AddPart('@'); - else - AddPart(UNKNOWN_VK_PREFIX + IntToStr(Key) + UNKNOWN_VK_POSTFIX); - end; - end; - +var + s: string; begin Result := ''; if ssCtrl in ShiftState then AddPart(ifsCtrl); @@ -618,7 +791,12 @@ begin AddPart(ifsVK_META); {$ENDIF} if ssSuper in ShiftState then AddPart(ifsVK_SUPER); - AddKey; + + s := KeyCodeToKeyString(Key); + // function returned "Word(nnn)" previously, keep this + if s = '' then + s := UNKNOWN_VK_PREFIX + IntToStr(Key) + UNKNOWN_VK_POSTFIX; + AddPart(s); end; function KeyStringIsIrregular(const s: string): boolean; @@ -627,36 +805,6 @@ begin (AnsiStrLComp(PChar(s),PChar(UNKNOWN_VK_PREFIX),length(UNKNOWN_VK_PREFIX))=0); end; -function KeyCodeToKeyString(Key: integer): string; -begin - case Key of - VK_BACK: - Result := MenuKeyCaps[mkcBkSp]; - VK_TAB: - Result := MenuKeyCaps[mkcTab]; - VK_RETURN: - Result := MenuKeyCaps[mkcEnter]; - VK_ESCAPE: - Result := MenuKeyCaps[mkcEsc]; - VK_SPACE..VK_SPACE+8: - Result := MenuKeyCaps[TMenuKeyCap(Key - VK_SPACE + Ord(mkcSpace))]; - VK_INSERT: - Result := MenuKeyCaps[mkcIns]; - VK_DELETE: - Result := MenuKeyCaps[mkcDel]; - VK_0..VK_9: - Result := Chr(Key - VK_0 + Ord('0')); - VK_A..VK_Z: - Result := Chr(Key - VK_A + Ord('A')); - VK_NUMPAD0..VK_NUMPAD9: - Result := 'Num' + Chr(Key - VK_NUMPAD0 + Ord('0')); // Delphi differs it from 0..9 - VK_F1..VK_F24: - Result := 'F' + IntToStr(Key - (VK_F1-1)); - else - Result := GetSpecialShortCutName(Key); - end; -end; - function ShortCutToText(ShortCut: TShortCut): string; var Name: string; @@ -713,8 +861,10 @@ begin else Break; end; - for Key := $08 to $FF do begin { Copy range from table in ShortCutToText } - Name := ShortCutToText(Key); + + for Key := Low(KeyCodeStrings) to High(KeyCodeStrings) do + begin + Name := KeyCodeToKeyString(Key); if (Name<>'') and (length(Name)=length(ShortCutText)-StartPos+1) and (AnsiStrLIComp(@ShortCutText[StartPos], PChar(Name), length(Name)) = 0) then begin