Beispiel #1
0
 public static bool IsValidSequence(KeySequence sequence, bool ignore_case) => m_sequences.IsValidSequence(sequence, ignore_case);
Beispiel #2
0
 public static string GetSequenceResult(KeySequence sequence, bool ignore_case) => m_sequences.GetSequenceResult(sequence, ignore_case);
Beispiel #3
0
 public static bool IsFavorite(KeySequence sequence, string result)
 => m_dict.TryGet(sequence, result)?.Favorite ?? false;
Beispiel #4
0
 public SequenceIdentifier(KeySequence sequence, string result)
 {
     Sequence = sequence;
     Result   = result;
 }
Beispiel #5
0
        /// <summary>
        /// Add a key to the sequence currently being built. If necessary, output
        /// the finished sequence or trigger actions for invalid sequences.
        /// </summary>
        private static bool AddToSequence(Key key)
        {
            KeySequence old_sequence = new KeySequence(m_sequence);

            m_sequence.Add(key);

            // We try the following, in this order:
            //  1. if m_sequence + key is a valid sequence, we don't go further,
            //     we append key to m_sequence and output the result.
            //  2. if m_sequence + key is a valid prefix, it means the user
            //     could type other characters to build a longer sequence,
            //     so just append key to m_sequence.
            //  3. if m_sequence + key is a valid generic prefix, continue as well.
            //  4. if m_sequence + key is a valid sequence, send it.
            //  5. (optionally) try again 1. and 2. ignoring case.
            //  6. none of the characters make sense, output all of them as if
            //     the user didn't press Compose.
            foreach (bool ignore_case in Settings.CaseInsensitive.Value ?
                     new bool[] { false, true } : new bool[] { false })
            {
                if (Settings.IsValidSequence(m_sequence, ignore_case))
                {
                    string tosend = Settings.GetSequenceResult(m_sequence,
                                                               ignore_case);
                    SendString(tosend);
                    Log.Debug("Valid sequence! Sent “{0}”", tosend);
                    Stats.AddSequence(m_sequence);
                    ResetSequence();
                    return(true);
                }

                if (Settings.IsValidPrefix(m_sequence, ignore_case))
                {
                    // Still a valid prefix, continue building sequence
                    return(true);
                }

                if (!ignore_case)
                {
                    if (Settings.IsValidGenericPrefix(m_sequence))
                    {
                        return(true);
                    }

                    if (Settings.GetGenericSequenceResult(m_sequence, out var tosend))
                    {
                        SendString(tosend);
                        Log.Debug("Valid generic sequence! Sent “{0}”", tosend);
                        Stats.AddSequence(m_sequence);
                        ResetSequence();
                        return(true);
                    }
                }

                // Try to swap characters if the corresponding option is set
                if (m_sequence.Count == 2 && Settings.SwapOnInvalid.Value)
                {
                    var other_sequence = new KeySequence()
                    {
                        m_sequence[1], m_sequence[0]
                    };
                    if (Settings.IsValidSequence(other_sequence, ignore_case))
                    {
                        string tosend = Settings.GetSequenceResult(other_sequence,
                                                                   ignore_case);
                        SendString(tosend);
                        Log.Debug("Found swapped sequence! Sent “{0}”", tosend);
                        Stats.AddSequence(other_sequence);
                        ResetSequence();
                        return(true);
                    }
                }
            }

            // FIXME: At this point we know the key can’t be part of a valid
            // sequence, but this should not be a hard error if the key is a
            // modifier key.

            // Unknown characters for sequence, print them if necessary
            if (!Settings.DiscardOnInvalid.Value)
            {
                string tosend = "";
                foreach (Key k in m_sequence)
                {
                    if (k.IsPrintable) // FIXME: what if the key is e.g. left arrow?
                    {
                        tosend += k.PrintableResult;
                    }
                }

                if (!string.IsNullOrEmpty(tosend))
                {
                    SendString(tosend);
                    Log.Debug("Invalid sequence! Sent “{0}”", tosend);
                }
            }

            if (Settings.BeepOnInvalid.Value)
            {
                SystemSounds.Beep.Play();
            }

            ResetSequence();
            return(true);
        }
Beispiel #6
0
        public static void IncrementUsage(KeySequence sequence, string result)
        {
            var data = m_dict.GetOrAdd(sequence, result);

            ++data.UsageCount;
        }
Beispiel #7
0
        /// <summary>
        /// Add a key to the sequence currently being built. If necessary, output
        /// the finished sequence or trigger actions for invalid sequences.
        /// </summary>
        private static bool AddToSequence(Key key)
        {
            KeySequence old_sequence = new KeySequence(m_sequence);

            m_sequence.Add(key);

            // We try the following, in this order:
            //  1. if m_sequence + key is a valid prefix, it means the user
            //     could type other characters to build a longer sequence,
            //     so just append key to m_sequence.
            //  2. if m_sequence + key is a valid sequence, we can't go further,
            //     we append key to m_sequence and output the result.
            //  3. if m_sequence is a valid sequence, the user didn't type a
            //     valid key, so output the m_sequence result _and_ process key.
            //  4. (optionally) try again 1. 2. and 3. ignoring case.
            //  5. none of the characters make sense, output all of them as if
            //     the user didn't press Compose.
            foreach (bool ignore_case in Settings.CaseInsensitive.Value ?
                     new bool[] { false, true } : new bool[] { false })
            {
                if (Settings.IsValidPrefix(m_sequence, ignore_case))
                {
                    // Still a valid prefix, continue building sequence
                    return(true);
                }

                if (Settings.IsValidSequence(m_sequence, ignore_case))
                {
                    string tosend = Settings.GetSequenceResult(m_sequence,
                                                               ignore_case);
                    Stats.AddSequence(m_sequence);
                    Log.Debug("Valid sequence! Sending {0}", tosend);
                    ResetSequence();
                    SendString(tosend);
                    return(true);
                }

                // Some code duplication with the above block, but this way
                // what we are doing is more clear.
                if (Settings.IsValidSequence(old_sequence, ignore_case))
                {
                    string tosend = Settings.GetSequenceResult(old_sequence,
                                                               ignore_case);
                    Stats.AddSequence(old_sequence);
                    Log.Debug("Sending previously valid sequence {0}", tosend);
                    ResetSequence();
                    SendString(tosend);
                    return(false);
                }
            }

            // Unknown characters for sequence, print them if necessary
            if (!Settings.DiscardOnInvalid.Value)
            {
                foreach (Key k in m_sequence)
                {
                    // FIXME: what if the key is e.g. left arrow?
                    if (k.IsPrintable())
                    {
                        SendString(k.ToString());
                    }
                }
            }

            if (Settings.BeepOnInvalid.Value)
            {
                SystemSounds.Beep.Play();
            }

            ResetSequence();
            return(true);
        }
Beispiel #8
0
        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.Add(keysyms[i]))
                    {
                        Logger.Warn($"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, @"\\([0-7]{3}|0x[0-7a-fA-F]{4}|.)", m =>
                {
                    var s = m.Value;

                    if (s.Length == 4) // Octal escape
                    {
                        return(((char)Convert.ToInt32(s.Substring(1), 8)).ToString());
                    }

                    if (s.Length == 7) // Hex escape
                    {
                        return(((char)Convert.ToInt32(s.Substring(3), 16)).ToString());
                    }

                    switch (s[1])
                    {
                    // These sequences are converted to their known value
                    case 'n': return("\n");

                    case 'r': return("\r");

                    case 't': return("\t");

                    case '"': return("\"");

                    case '\\': return("\\");

                    default: return(s);
                    }
                });
            }
            else
            {
                var result_key = Key.FromKeySymOrChar(result);
                if (result_key == null)
                {
                    Logger.Warn($"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;
        }
Beispiel #9
0
        private static void ParseRule(string line)
        {
            // If this is an include directive, use LoadSequenceFile() 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", 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 = m_r1.Match(line);

            if (!m1.Success)
            {
                return;
            }

            var keysyms = m_r2.Split(m1.Groups[1].Captures[0].Value);

            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].Value;
            string description = m1.Groups.Count >= 5 ? m1.Groups[4].Captures[0].Value : "";

            // 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 (!string.IsNullOrEmpty(alt_desc))
                {
                    description = alt_desc;
                }
            }

            m_sequences.Add(seq, result, utf32, description);
            ++m_sequence_count;
        }
Beispiel #10
0
 public static string GetSequenceResult(KeySequence sequence, bool ignore_case)
 {
     return(m_sequences.GetSequenceResult(sequence, ignore_case));
 }
Beispiel #11
0
 public static bool IsValidSequence(KeySequence sequence, bool ignore_case)
 {
     return(m_sequences.IsValidSequence(sequence, ignore_case));
 }