private static void ValidateComposeKeys() { KeySequence compose_keys = new KeySequence(); if (ComposeKeys.Value?.Count == 0) { // The default compose key for the first time WinCompose is launched compose_keys.Add(m_default_compose_key); } else { // Validate the list of compose keys, ensuring there are only valid keys // and there are no duplicates. Also remove VK.DISABLED from the list // but re-add it if there are no valid keys at all. foreach (Key k in ComposeKeys.Value) { bool is_valid = (k.VirtualKey >= VK.F1 && k.VirtualKey <= VK.F24) || m_valid_compose_keys.Contains(k); if (is_valid && k.VirtualKey != VK.DISABLED && !compose_keys.Contains(k)) { compose_keys.Add(k); } } if (compose_keys.Count == 0) { compose_keys.Add(new Key(VK.DISABLED)); } } ComposeKeys.Value = compose_keys; }
/// <summary> /// If the first key of <see cref="sequences"/> matches a known child, /// return that child. Otherwise, return null. /// If <see cref="flags"/> has the <see cref="Search.Prefixes"/> flag /// and we are a rule with no children, we return null. This lets us /// check for strict prefixes. /// If <see cref="flags"/> has the <see cref="Search.Sequences"/> flag /// and we are not a rule (just a node in the tree), we do not return /// the current node (but we do return children sequences). /// </summary> private SequenceNode GetSubtree(KeySequence sequence, Search flags) { if (sequence.Count == 0) { if ((flags & Search.Prefixes) != 0 && m_children.Count == 0) { return(null); } if ((flags & Search.Sequences) != 0 && m_results.Count == 0) { return(null); } return(this); } KeySequence keys = new KeySequence { sequence[0] }; if ((flags & Search.IgnoreCase) != 0 && sequence[0].IsPrintable) { Key upper = new Key(sequence[0].PrintableResult.ToUpper()); if (upper != sequence[0]) { keys.Add(upper); } Key lower = new Key(sequence[0].PrintableResult.ToLower()); if (lower != sequence[0]) { keys.Add(lower); } } foreach (Key k in keys) { if (!m_children.ContainsKey(k)) { continue; } var subsequence = sequence.GetRange(1, sequence.Count - 1); var subtree = m_children[k].GetSubtree(subsequence, flags); if (subtree != null) { return(subtree); } } return(null); }
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object val) { var list_str = val as string; if (list_str == null) { return(base.ConvertFrom(context, culture, val)); } KeySequence ret = new KeySequence(); foreach (string str in Array.ConvertAll(list_str.Split(','), x => x.Trim())) { Key k = new Key(str); if (str.StartsWith("VK.")) { try { var enum_val = Enum.Parse(typeof(VK), str.Substring(3)); k = new Key((VK)enum_val); } catch { } // Silently catch parsing exception. } ret.Add(k); } return(ret); }
private static void LoadSequenceString(string line) { // Only bother with sequences that start with <Multi_key> var m1 = Regex.Match(line, @"^\s*<Multi_key>\s*([^:]*):[^""]*""(([^""]|\\"")*)""[^#]*#?\s*(.*)"); // ^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^ // keys result desc if (m1.Groups.Count < 4) { return; } var keysyms = Regex.Split(m1.Groups[1].Captures[0].ToString(), @"[\s<>]+"); if (keysyms.Length < 4) // We need 2 empty strings + at least 2 keysyms { return; } KeySequence seq = new KeySequence(); for (int i = 1; i < keysyms.Length; ++i) { if (keysyms[i] == String.Empty) { continue; } Key k = Key.FromKeySym(keysyms[i]); if (k == null) { //Console.WriteLine("Unknown key name <{0}>, ignoring sequence", keysyms[i]); return; // Unknown key name! Better bail out } seq.Add(k); } string result = m1.Groups[2].Captures[0].ToString(); string description = m1.Groups.Count >= 5 ? m1.Groups[4].Captures[0].ToString() : ""; // Replace \\ and \" in the string output result = new Regex(@"\\(\\|"")").Replace(result, "$1"); // Try to translate the description if appropriate int utf32 = StringToCodepoint(result); if (utf32 >= 0) { string key = String.Format("U{0:X04}", utf32); string alt_desc = unicode.Char.ResourceManager.GetString(key); if (alt_desc != null && alt_desc.Length > 0) { description = alt_desc; } } m_sequences.Add(seq, result, utf32, description); ++m_sequence_count; }
private static void ValidateComposeKeys() { // Validate the list of compose keys, ensuring there are only valid keys // and there are no duplicates. KeySequence compose_keys = new KeySequence(); foreach (Key k in ComposeKeys.Value) { if (m_valid_compose_keys.Contains(k) && !compose_keys.Contains(k)) { compose_keys.Add(k); } } if (compose_keys.Count == 0) { compose_keys.Add(m_default_compose_key); } ComposeKeys.Value = compose_keys; }
/// <summary> /// Construct a key sequence from an XML attr string. /// </summary> public static KeySequence FromXmlAttr(string str) { KeySequence ret = new KeySequence(); foreach (Match match in re_xml.Matches(str)) { ret.Add(Key.FromXmlAttr(match.Value)); } return(ret); }
KeySequence UnicodeKeySequence(string keys) { var keySequence = new KeySequence(); foreach (var ch in keys) { keySequence.Add(Key.FromKeySymOrChar(Convert.ToString(ch))); } return(keySequence); }
private static void ValidateSettings() { // Check that the configured compose key(s) are legal KeySequence compose_keys = new KeySequence(); if (ComposeKeys.Value?.Count == 0) { // The default compose key for the first time WinCompose is launched compose_keys.Add(m_default_compose_key); } else { // Validate the list of compose keys, ensuring there are only valid keys // and there are no duplicates. Also remove VK.DISABLED from the list // but re-add it if there are no valid keys at all. foreach (Key k in ComposeKeys.Value) { bool is_valid = (k.VirtualKey >= VK.F1 && k.VirtualKey <= VK.F24) || m_valid_compose_keys.Contains(k); if (is_valid && k.VirtualKey != VK.DISABLED && !compose_keys.Contains(k)) { compose_keys.Add(k); } } if (compose_keys.Count == 0) { compose_keys.Add(new Key(VK.DISABLED)); } } ComposeKeys.Value = compose_keys; // Check that the keyboard LED key is legal if (LedKey.Value.Count != 1 || !ValidLedKeys.Contains(LedKey.Value[0])) { LedKey.Value = new KeySequence() { new Key(VK.COMPOSE) }; } }
/// <summary> /// Build a list of sequence descriptions by recursively adding our /// children to <see cref="list"/>. The output structure is suitable /// for the GUI. /// </summary> private void BuildSequenceDescriptions(List <SequenceDescription> list, KeySequence path) { list.AddRange(m_results); foreach (var pair in m_children) { var newpath = new KeySequence(path); newpath.Add(pair.Key); pair.Value.BuildSequenceDescriptions(list, newpath); } }
/// <summary> /// Construct a key sequence from a serialized string. /// </summary> public static KeySequence FromString(string str) { KeySequence ret = new KeySequence(); // Be sure to call Trim() because older WinCompose versions would add a // space after the comma. foreach (string s in Array.ConvertAll(str.Split(','), x => x.Trim())) { ret.Add(Key.FromString(s)); } return(ret); }
private static void ValidateComposeKeys() { // Validate the list of compose keys, ensuring there are only valid keys // and there are no duplicates. KeySequence compose_keys = new KeySequence(); foreach (Key k in ComposeKeys.Value) { bool is_valid = (k.VirtualKey >= VK.F1 && k.VirtualKey <= VK.F24) || m_valid_compose_keys.Contains(k); if (is_valid && !compose_keys.Contains(k)) { compose_keys.Add(k); } } if (compose_keys.Count == 0) { compose_keys.Add(m_default_compose_key); } ComposeKeys.Value = compose_keys; }
private static void ValidateComposeKeys() { // Validate the list of compose keys, ensuring there are only valid keys // and there are no duplicates. Also remove VK.DISABLED from the list // unless there are no valid keys at all. KeySequence compose_keys = new KeySequence(); foreach (Key k in ComposeKeys.Value ?? compose_keys) { bool is_valid = (k.VirtualKey >= VK.F1 && k.VirtualKey <= VK.F24) || m_valid_compose_keys.Contains(k); if (is_valid && k.VirtualKey != VK.DISABLED && !compose_keys.Contains(k)) { compose_keys.Add(k); } } if (compose_keys.Count == 0) { compose_keys.Add(new Key(VK.DISABLED)); } ComposeKeys.Value = compose_keys; }
/// <summary> /// Build a list of sequence descriptions by recursively adding our /// children to <see cref="list"/>. The output structure is suitable /// for the GUI. /// </summary> private void BuildSequenceDescriptions(List <SequenceDescription> list, KeySequence path) { if (m_result != null) { var item = new SequenceDescription(); item.Sequence = path; item.Result = m_result; item.Description = m_description; item.Utf32 = m_utf32; list.Add(item); } foreach (var pair in m_children) { var newpath = new KeySequence(path); newpath.Add(pair.Key); pair.Value.BuildSequenceDescriptions(list, newpath); } }
private void ParseRule(string line) { // If this is an include directive, use LoadFile() again Match m0 = m_r0.Match(line); if (m0.Success) { string file = m0.Groups[1].Captures[0].Value; // We support %H (user directory) but not %L (locale-specific dir) if (file.Contains("%L")) { return; } file = file.Replace("%H", Utils.UserDir); // Also if path is not absolute, prepend user directory if (!Path.IsPathRooted(file)) { file = Path.Combine(Utils.UserDir, file); } // Prevent against include recursion if (!m_loaded_files.Contains(file)) { LoadFile(file); } return; } var m1 = m_r1.Match(line); if (!m1.Success) { return; } KeySequence seq = new KeySequence(); var keysyms = m_r2.Split(m1.Groups[1].Captures[0].Value); for (int i = 1; i < keysyms.Length - 1; ++i) { Key k = Key.FromKeySymOrChar(keysyms[i]); if (k == null) { if (!m_invalid_keys.ContainsKey(keysyms[i])) { m_invalid_keys[keysyms[i]] = true; Log.Debug($"Unknown key name <{keysyms[i]}>, ignoring sequence"); } return; // Unknown key name! Better bail out } seq.Add(k); } // Only bother with sequences of length >= 2 that start with <Multi_key> if (seq.Count < 2 || seq[0].VirtualKey != VK.COMPOSE) { return; } string result = m1.Groups[2].Captures[0].Value; if (result[0] == '"') { result = result.Trim('"'); // Unescape \n \\ \" and more in the string output result = Regex.Replace(result, @"\\.", m => { switch (m.Value) { // These sequences are converted to their known value case @"\n": return("\n"); case @"\r": return("\r"); case @"\t": return("\t"); // For all other sequences, just strip the leading \ default: return(m.Value.Substring(1)); } }); } else { var result_key = Key.FromKeySymOrChar(result); if (result_key == null) { Log.Debug($"Unknown key name {result}, ignoring sequence"); return; } result = result_key.PrintableResult; } string description = m1.Groups.Count >= 5 ? m1.Groups[4].Captures[0].Value : ""; // Try to translate the description if appropriate int utf32 = StringToCodepoint(result); if (utf32 >= 0) { string key = $"U{utf32:X04}"; string alt_desc = unicode.Char.ResourceManager.GetString(key); if (!string.IsNullOrEmpty(alt_desc)) { description = alt_desc; } } // HACK: remove the first key (Multi_key) for now, because the // rest of the code cannot handle it. seq.RemoveAt(0); InsertSequence(seq, result, utf32, description); ++Count; }
private static void LoadSequenceString(string line) { // If this is an include directive, use LoadSequenceFile() again var m0 = Regex.Match(line, @"^\s*include\s*""([^""]*)"""); if (m0.Groups.Count > 1) { string file = m0.Groups[1].Captures[0].ToString(); // We support %H (user directory) but not %L (locale-specific dir) if (file.Contains("%L")) { return; } file = file.Replace("%H", GetUserDir()); // Also if path is not absolute, prepend user directory if (!Path.IsPathRooted(file)) { file = Path.Combine(GetUserDir(), file); } LoadSequenceFile(file); return; } // Only bother with sequences that start with <Multi_key> var m1 = Regex.Match(line, @"^\s*<Multi_key>\s*([^:]*):[^""]*""(([^""]|\\"")*)""[^#]*#?\s*(.*)"); // ^^^^^^^ ^^^^^^^^^^^^^^^ ^^^^ // keys result desc if (m1.Groups.Count < 4) { return; } var keysyms = Regex.Split(m1.Groups[1].Captures[0].ToString(), @"[\s<>]+"); if (keysyms.Length < 4) // We need 2 empty strings + at least 2 keysyms { return; } KeySequence seq = new KeySequence(); for (int i = 1; i < keysyms.Length; ++i) { if (keysyms[i] == String.Empty) { continue; } Key k = Key.FromKeySym(keysyms[i]); if (k == null) { //Console.WriteLine("Unknown key name <{0}>, ignoring sequence", keysyms[i]); return; // Unknown key name! Better bail out } seq.Add(k); } string result = m1.Groups[2].Captures[0].ToString(); string description = m1.Groups.Count >= 5 ? m1.Groups[4].Captures[0].ToString() : ""; // Unescape \n \\ \" and more in the string output result = Regex.Replace(result, @"\\.", m => { switch (m.Value) { // These sequences are converted to their known value case @"\n": return("\n"); case @"\r": return("\r"); case @"\t": return("\t"); // For all other sequences, just strip the leading \ default: return(m.Value.Substring(1).ToString()); } }); // Try to translate the description if appropriate int utf32 = StringToCodepoint(result); if (utf32 >= 0) { string key = String.Format("U{0:X04}", utf32); string alt_desc = unicode.Char.ResourceManager.GetString(key); if (alt_desc != null && alt_desc.Length > 0) { description = alt_desc; } } m_sequences.Add(seq, result, utf32, description); ++m_sequence_count; }