/// <summary> /// Returns true if pathOrFilename looks like a DOS filename or path. /// Examples: <c>"abcde~12"</c>, <c>"abcde~12.txt"</c>, <c>@"c:\path\abcde~12.txt"</c>, <c>"c:\abcde~12\path"</c>. /// </summary> /// <param name="s">Can be null.</param> internal static bool IsPossiblyDos_(string s) { //AOutput.Write(s); if (s != null && s.Length >= 8) { for (int i = 0; (i = s.IndexOf('~', i + 1)) > 0;) { int j = i + 1, k = 0; for (; k < 6 && j < s.Length; k++, j++) { if (!AChar.IsAsciiDigit(s[j])) { break; } } if (k == 0) { continue; } char c = j < s.Length ? s[j] : '\\'; if (c == '\\' || c == '/' || (c == '.' && j == s.Length - 4)) { for (j = i; j > 0; j--) { c = s[j - 1]; if (c == '\\' || c == '/') { break; } } if (j == i - (7 - k)) { return(true); } } } } return(false); }
/// <summary> /// Converts part of string to <see cref="KKey"/>. /// The substring should contain single key name, eg "Esc", "A", "=". /// Returns 0 if invalid key name. /// </summary> static unsafe KKey _KeynameToKey(string s, int i, int len) { //AOutput.Write(s, i, len); if (len < 1) { return(0); } char c = s[i]; //character keys, like K, 9, - if (len == 1) { if (c >= 'a' && c <= 'z') { return((KKey)(c - 32)); } if (c >= 'A' && c <= 'Z') { return((KKey)c); } if (c >= '0' && c <= '9') { return((KKey)c); } switch (c) { case '=': return(KKey.OemPlus); case '`': case '~': return(KKey.OemTilde); case '-': case '_': return(KKey.OemMinus); case '[': case '{': return(KKey.OemOpenBrackets); case ']': case '}': return(KKey.OemCloseBrackets); case '\\': case '|': return(KKey.OemPipe); case ';': case ':': return(KKey.OemSemicolon); case '\'': case '\"': return(KKey.OemQuotes); case ',': case '<': return(KKey.OemComma); case '.': case '>': return(KKey.OemPeriod); case '/': case '?': return(KKey.OemQuestion); } return(0); //special //+ //eg Ctrl+A //* //*nTimes, *down, *up //( //eg Alt+(A F) //) //# //numpad keys, eg #5, #* //$ //Shift+ //reserved //! @ % ^ & } //numpad keys if (c == '#') { if (len == 2) { switch (s[i + 1]) { case '.': return(KKey.Decimal); case '+': return(KKey.Add); case '/': return(KKey.Divide); case '*': return(KKey.Multiply); case '-': return(KKey.Subtract); case '0': return(KKey.NumPad0); case '1': return(KKey.NumPad1); case '2': return(KKey.NumPad2); case '3': return(KKey.NumPad3); case '4': return(KKey.NumPad4); case '5': return(KKey.NumPad5); case '6': return(KKey.NumPad6); case '7': return(KKey.NumPad7); case '8': return(KKey.NumPad8); case '9': return(KKey.NumPad9); } } return(0); } //F keys if (c == 'F' && AChar.IsAsciiDigit(s[i + 1])) { int n = s.ToInt(i + 1, out int e, STIFlags.NoHex); if (n > 0 && n <= 24 && e == i + len) { return((KKey)(0x6F + n)); } } //named keys //names start with an uppercase letter and must have at least 2 other anycase letters, except: Up, AltG (RAl), PageU (PgU), PageD (PgD), some alternative names (PU, PD, PB, PS, HM, SL, CL, NL, BS). KKey k = 0; char c1 = Char.ToLowerInvariant(s[i + 1]), //note: Util.Tables_.LowerCase would make startup slow c2 = len > 2 ? Char.ToLowerInvariant(s[i + 2]) : ' ', c3 = len > 3 ? Char.ToLowerInvariant(s[i + 3]) : ' ', c4 = len > 4 ? Char.ToLowerInvariant(s[i + 4]) : ' '; uint u = (uint)c1 << 16 | c2; switch (c) { case 'A': if (_U('l', 't')) { k = c3 == 'g' ? KKey.RAlt : KKey.Alt; } else if (_U('p', 'p')) { k = KKey.Apps; } break; case 'B': if (_U('a', 'c') || _U('s', ' ')) { k = KKey.Back; } break; case 'C': if (_U('t', 'r')) { k = KKey.Ctrl; } else if (_U('a', 'p') || _U('l', ' ')) { k = KKey.CapsLock; } break; case 'D': if (_U('e', 'l')) { k = KKey.Delete; } else if (_U('o', 'w')) { k = KKey.Down; } break; case 'E': if (_U('n', 't')) { k = KKey.Enter; } else if (_U('n', 'd')) { k = KKey.End; } else if (_U('s', 'c')) { k = KKey.Escape; } break; case 'H': if (_U('o', 'm') || _U('m', ' ')) { k = KKey.Home; } break; case 'I': if (_U('n', 's')) { k = KKey.Insert; } break; case 'L': if (_U('e', 'f')) { k = KKey.Left; } //don't need LShift etc break; case 'M': if (_U('e', 'n')) { k = KKey.Apps; } break; case 'N': if (_U('u', 'm') || _U('l', ' ')) { k = KKey.NumLock; } //for NumEnter use AKeys.Key((KKey.Enter, 0, true)) break; case 'P': if (_U('a', 'g') && c3 == 'e') { k = c4 == 'u' ? KKey.PageUp : (c4 == 'd' ? KKey.PageDown : 0); } else if (_U('g', 'u') || _U('u', ' ')) { k = KKey.PageUp; } else if (_U('g', 'd') || _U('d', ' ')) { k = KKey.PageDown; } else if (_U('a', 'u') || _U('b', ' ')) { k = KKey.Pause; } else if (_U('r', 'i') || _U('r', 't') || _U('s', ' ')) { k = KKey.PrintScreen; } break; case 'R': if (_U('i', 'g')) { k = KKey.Right; } else if (_U('a', 'l')) { k = KKey.RAlt; } else if (_U('c', 't')) { k = KKey.RCtrl; } else if (_U('s', 'h')) { k = KKey.RShift; } else if (_U('w', 'i')) { k = KKey.RWin; } break; case 'S': if (_U('h', 'i')) { k = KKey.Shift; } else if (_U('p', 'a')) { k = KKey.Space; } else if (_U('c', 'r') || _U('l', ' ')) { k = KKey.ScrollLock; } //SysRq not used on Windows break; case 'T': if (_U('a', 'b')) { k = KKey.Tab; } break; case 'U': if (c1 == 'p') { k = KKey.Up; } break; case 'V': if (c1 == 'k') { int v = s.ToInt(i + 2, out int end, STIFlags.DontSkipSpaces); if (end != i + len || (uint)v > 255) { v = 0; } return((KKey)v); } break; case 'W': if (_U('i', 'n')) { k = KKey.Win; } break; } if (k != 0) { for (int i2 = i + len; i < i2; i++) { if (!AChar.IsAsciiAlpha(s[i])) { return(0); } } return(k); } if (c >= 'A' && c <= 'Z') { var s1 = s.Substring(i, len); #if false if (Enum.TryParse(s1, true, out KKey r1)) { return(r1); } //if(Enum.TryParse(s1, true, out System.Windows.Forms.Keys r2) && (uint)r2 <= 0xff) return (KKey)r2; #else //20-50 times faster and less garbage. Good JIT speed. return(_FindKeyInEnums(s1)); #endif } return(0); bool _U(char cc1, char cc2) { return(u == ((uint)cc1 << 16 | cc2)); } }