Beispiel #1
0
        private void PrepareSend()
        {
            IntPtr hWnd = NativeMethods.GetForegroundWindowHandle();

            m_swiCurrent = GetWindowInfo(hWnd);

            EnsureSameKeyboardLayout();
        }
Beispiel #2
0
        private void InitForEnv()
        {
#if DEBUG
            Stopwatch sw = Stopwatch.StartNew();
#endif

            try
            {
                m_hklCurrent  = NativeMethods.GetKeyboardLayout(0);
                m_hklOriginal = m_hklCurrent;
                Debug.Assert(m_hklOriginal != IntPtr.Zero);

                Process[] vProcesses = Process.GetProcesses();
                foreach (Process p in vProcesses)
                {
                    if (p == null)
                    {
                        Debug.Assert(false); continue;
                    }

                    try
                    {
                        string strName = SiWindowInfo.GetProcessName(p);

                        // If the Neo keyboard layout is being used, we must
                        // send Unicode characters; keypresses are converted
                        // and thus do not lead to the expected result
                        if (SiWindowInfo.ProcessNameMatches(strName, "Neo20"))
                        {
                            FileVersionInfo fvi = p.MainModule.FileVersionInfo;
                            if (((fvi.ProductName ?? string.Empty).Trim().Length == 0) &&
                                ((fvi.FileDescription ?? string.Empty).Trim().Length == 0))
                            {
                                m_osmEnforced = SiSendMethod.UnicodePacket;
                            }
                            else
                            {
                                Debug.Assert(false);
                            }
                        }
                        else if (SiWindowInfo.ProcessNameMatches(strName, "KbdNeo_Ahk"))
                        {
                            m_osmEnforced = SiSendMethod.UnicodePacket;
                        }
                    }
                    catch (Exception) { Debug.Assert(false); }

                    try { p.Dispose(); }
                    catch (Exception) { Debug.Assert(false); }
                }
            }
            catch (Exception) { Debug.Assert(false); }

#if DEBUG
            sw.Stop();
            Debug.Assert(sw.ElapsedMilliseconds < 100);
#endif
        }
Beispiel #3
0
        private SiSendMethod GetSendMethod(SiWindowInfo swi)
        {
            if (m_osmEnforced.HasValue)
            {
                return(m_osmEnforced.Value);
            }

            return(swi.SendMethod);
        }
Beispiel #4
0
        private SiWindowInfo PrepareSend()
        {
            IntPtr       hWnd = NativeMethods.GetForegroundWindowHandle();
            SiWindowInfo swi  = GetWindowInfo(hWnd);

            EnsureSameKeyboardLayout(swi);

            return(swi);
        }
Beispiel #5
0
        private SiWindowInfo GetWindowInfo(IntPtr hWnd)
        {
            SiWindowInfo swi;

            if (m_dWindowInfos.TryGetValue(hWnd, out swi))
            {
                return(swi);
            }

            swi = new SiWindowInfo(hWnd);
            m_dWindowInfos[hWnd] = swi;
            return(swi);
        }
Beispiel #6
0
        private SiWindowInfo GetWindowInfo(IntPtr hWnd)
        {
            SiWindowInfo swi;

            if (m_dWindowInfos.TryGetValue(hWnd, out swi))
            {
                return(swi);
            }

            swi = new SiWindowInfo(hWnd);

            Process p = null;

            try
            {
                uint uPID;
                uint uTID = NativeMethods.GetWindowThreadProcessId(hWnd, out uPID);

                swi.KeyboardLayout = NativeMethods.GetKeyboardLayout(uTID);

                p = Process.GetProcessById((int)uPID);
                string strName = GetProcessName(p);

                foreach (KeyValuePair <string, SiSendMethod> kvp in g_dProcessSendMethods)
                {
                    if (ProcessNameMatches(strName, kvp.Key))
                    {
                        swi.SendMethod = kvp.Value;
                        break;
                    }
                }
            }
            catch (Exception) { Debug.Assert(false); }
            finally
            {
                try { if (p != null)
                      {
                          p.Dispose();
                      }
                }
                catch (Exception) { Debug.Assert(false); }
            }

            m_dWindowInfos[hWnd] = swi;
            return(swi);
        }
Beispiel #7
0
        public override void SendCharImpl(char ch, bool?bDown)
        {
            SiWindowInfo swi = PrepareSend();

            if (TrySendCharByKeypresses(ch, bDown, swi))
            {
                return;
            }

            if (bDown.HasValue)
            {
                SendCharNative(ch, bDown.Value);
                return;
            }

            SendCharNative(ch, true);
            SendCharNative(ch, false);
        }
Beispiel #8
0
        private void EnsureSameKeyboardLayout(SiWindowInfo swi)
        {
            if (!Program.Config.Integration.AutoTypeAdjustKeyboardLayout)
            {
                return;
            }

            IntPtr hklTarget = swi.KeyboardLayout;

            Debug.Assert(hklTarget != IntPtr.Zero);
            Debug.Assert(NativeMethods.GetKeyboardLayout(0) == m_hklCurrent);

            if ((m_hklCurrent != hklTarget) && (hklTarget != IntPtr.Zero))
            {
                if (NativeMethods.ActivateKeyboardLayout(hklTarget, 0) != m_hklCurrent)
                {
                    Debug.Assert(false);
                }
                m_hklCurrent = hklTarget;

                Thread.Sleep(1);
                Application.DoEvents();
            }
        }
Beispiel #9
0
        private bool TrySendCharByKeypresses(char ch, bool? bDown, SiWindowInfo swi)
        {
            if(ch == char.MinValue) { Debug.Assert(false); return false; }

            SiSendMethod sm = GetSendMethod(swi);
            if(sm == SiSendMethod.UnicodePacket) return false;

            if(m_vForcedUniChars == null)
                m_vForcedUniChars = new char[] {
                    // All of the following diacritics are spacing / non-combining

                    '\u00B4', // Acute accent
                    '\u02DD', // Double acute accent
                    '\u0060', // Grave accent
                    '\u02D8', // Breve
                    '\u00B8', // Cedilla
                    '\u005E', // Circumflex ^
                    '\u00A8', // Diaeresis
                    '\u02D9', // Dot above
                    '\u00AF', // Macron above, long
                    '\u02C9', // Macron above, modifier, short
                    '\u02CD', // Macron below, modifier, short
                    '\u02DB', // Ogonek

                    // E.g. for US-International;
                    // https://sourceforge.net/p/keepass/discussion/329220/thread/5708e5ef/
                    '\u0027', // Apostrophe
                    '\u0022', // Quotation mark
                    '\u007E' // Tilde
                };
            if(sm != SiSendMethod.KeyEvent) // If Unicode packets allowed
            {
                if(Array.IndexOf<char>(m_vForcedUniChars, ch) >= 0) return false;
            }

            IntPtr hKL = swi.KeyboardLayout;
            ushort u = ((hKL == IntPtr.Zero) ? NativeMethods.VkKeyScan(ch) :
                NativeMethods.VkKeyScanEx(ch, hKL));
            if(u == 0xFFFFU) return false;

            int vKey = (int)(u & 0xFFU);

            Keys kMod = Keys.None;
            int nMods = 0;
            if((u & 0x100U) != 0U) { ++nMods; kMod |= Keys.Shift; }
            if((u & 0x200U) != 0U) { ++nMods; kMod |= Keys.Control; }
            if((u & 0x400U) != 0U) { ++nMods; kMod |= Keys.Alt; }
            if((u & 0x800U) != 0U) return false; // Hankaku unsupported

            // Do not send a key combination that is registered as hot key;
            // https://sourceforge.net/p/keepass/bugs/1235/
            // Windows shortcut hot keys involve at least 2 modifiers
            if(nMods >= 2)
            {
                Keys kFull = (kMod | (Keys)vKey);
                if(HotKeyManager.IsHotKeyRegistered(kFull, true))
                    return false;
            }

            Keys kModDiff = (kMod & ~m_kModCur);
            if(kModDiff != Keys.None)
            {
                // Send RAlt for better AltGr compatibility;
                // https://sourceforge.net/p/keepass/bugs/1475/
                SetKeyModifierImplEx(kModDiff, true, true);

                Thread.Sleep(1);
                Application.DoEvents();
            }

            SendKeyImpl(vKey, null, bDown);

            if(kModDiff != Keys.None)
            {
                Thread.Sleep(1);
                Application.DoEvents();

                SetKeyModifierImplEx(kModDiff, false, true);
            }

            return true;
        }
Beispiel #10
0
        private SiWindowInfo GetWindowInfo(IntPtr hWnd)
        {
            SiWindowInfo swi;
            if(m_dWindowInfos.TryGetValue(hWnd, out swi)) return swi;

            swi = new SiWindowInfo(hWnd);

            Process p = null;
            try
            {
                uint uPID;
                uint uTID = NativeMethods.GetWindowThreadProcessId(hWnd, out uPID);

                swi.KeyboardLayout = NativeMethods.GetKeyboardLayout(uTID);

                p = Process.GetProcessById((int)uPID);
                string strName = GetProcessName(p);

                foreach(KeyValuePair<string, SiSendMethod> kvp in g_dProcessSendMethods)
                {
                    if(ProcessNameMatches(strName, kvp.Key))
                    {
                        swi.SendMethod = kvp.Value;
                        break;
                    }
                }
            }
            catch(Exception) { Debug.Assert(false); }
            finally
            {
                try { if(p != null) p.Dispose(); }
                catch(Exception) { Debug.Assert(false); }
            }

            m_dWindowInfos[hWnd] = swi;
            return swi;
        }
Beispiel #11
0
        private SiSendMethod GetSendMethod(SiWindowInfo swi)
        {
            if(m_osmEnforced.HasValue) return m_osmEnforced.Value;

            return swi.SendMethod;
        }
Beispiel #12
0
        private void EnsureSameKeyboardLayout(SiWindowInfo swi)
        {
            if(!Program.Config.Integration.AutoTypeAdjustKeyboardLayout) return;

            IntPtr hklTarget = swi.KeyboardLayout;
            Debug.Assert(hklTarget != IntPtr.Zero);
            Debug.Assert(NativeMethods.GetKeyboardLayout(0) == m_hklCurrent);

            if((m_hklCurrent != hklTarget) && (hklTarget != IntPtr.Zero))
            {
                if(NativeMethods.ActivateKeyboardLayout(hklTarget, 0) != m_hklCurrent)
                {
                    Debug.Assert(false);
                }
                m_hklCurrent = hklTarget;

                Thread.Sleep(1);
                Application.DoEvents();
            }
        }
Beispiel #13
0
        private SiWindowInfo GetWindowInfo(IntPtr hWnd)
        {
            SiWindowInfo swi;

            if (m_dWindowInfos.TryGetValue(hWnd, out swi))
            {
                return(swi);
            }

            swi = new SiWindowInfo(hWnd);

            Process p = null;

            try
            {
                uint uPID;
                uint uTID = NativeMethods.GetWindowThreadProcessId(hWnd, out uPID);

                swi.KeyboardLayout = NativeMethods.GetKeyboardLayout(uTID);

                p = Process.GetProcessById((int)uPID);
                string strName = GetProcessName(p);

                foreach (KeyValuePair <string, SiSendMethod> kvp in g_dProcessSendMethods)
                {
                    if (ProcessNameMatches(strName, kvp.Key))
                    {
                        swi.SendMethod = kvp.Value;
                        break;
                    }
                }

                // The workaround attempt for Edge below doesn't work;
                // Edge simply ignores Unicode packets for '@', Euro sign, etc.

                /* if(swi.SendMethod == SiSendMethod.Default)
                 * {
                 *      string strTitle = NativeMethods.GetWindowText(hWnd, true);
                 *
                 *      // Workaround for Edge;
                 *      // https://sourceforge.net/p/keepass/discussion/329220/thread/fd3a6776/
                 *      // The window title is:
                 *      // Page name + Space + U+200E (left-to-right mark) + "- Microsoft Edge"
                 *      if(strTitle.EndsWith("- Microsoft Edge", StrUtil.CaseIgnoreCmp))
                 *              swi.SendMethod = SiSendMethod.UnicodePacket;
                 * } */
            }
            catch (Exception) { Debug.Assert(false); }
            finally
            {
                try { if (p != null)
                      {
                          p.Dispose();
                      }
                }
                catch (Exception) { Debug.Assert(false); }
            }

            m_dWindowInfos[hWnd] = swi;
            return(swi);
        }
Beispiel #14
0
        private bool TrySendCharByKeypresses(char ch, bool?bDown, SiWindowInfo swi)
        {
            if (ch == char.MinValue)
            {
                Debug.Assert(false); return(false);
            }

            SiSendMethod sm = GetSendMethod(swi);

            if (sm == SiSendMethod.UnicodePacket)
            {
                return(false);
            }

            if (m_vForcedUniChars == null)
            {
                m_vForcedUniChars = new char[] {
                    // All of the following diacritics are spacing / non-combining

                    '\u00B4',                     // Acute accent
                    '\u02DD',                     // Double acute accent
                    '\u0060',                     // Grave accent
                    '\u02D8',                     // Breve
                    '\u00B8',                     // Cedilla
                    '\u005E',                     // Circumflex ^
                    '\u00A8',                     // Diaeresis
                    '\u02D9',                     // Dot above
                    '\u00AF',                     // Macron above, long
                    '\u02C9',                     // Macron above, modifier, short
                    '\u02CD',                     // Macron below, modifier, short
                    '\u02DB',                     // Ogonek

                    // E.g. for US-International;
                    // https://sourceforge.net/p/keepass/discussion/329220/thread/5708e5ef/
                    '\u0027',                    // Apostrophe
                    '\u0022',                    // Quotation mark
                    '\u007E'                     // Tilde
                }
            }
            ;
            if (sm != SiSendMethod.KeyEvent)            // If Unicode packets allowed
            {
                if (Array.IndexOf <char>(m_vForcedUniChars, ch) >= 0)
                {
                    return(false);
                }
            }

            IntPtr hKL = swi.KeyboardLayout;
            ushort u   = ((hKL == IntPtr.Zero) ? NativeMethods.VkKeyScan(ch) :
                          NativeMethods.VkKeyScanEx(ch, hKL));

            if (u == 0xFFFFU)
            {
                return(false);
            }

            int vKey = (int)(u & 0xFFU);

            Keys kMod  = Keys.None;
            int  nMods = 0;

            if ((u & 0x100U) != 0U)
            {
                ++nMods; kMod |= Keys.Shift;
            }
            if ((u & 0x200U) != 0U)
            {
                ++nMods; kMod |= Keys.Control;
            }
            if ((u & 0x400U) != 0U)
            {
                ++nMods; kMod |= Keys.Alt;
            }
            if ((u & 0x800U) != 0U)
            {
                return(false);                               // Hankaku unsupported
            }
            // Do not send a key combination that is registered as hot key;
            // https://sourceforge.net/p/keepass/bugs/1235/
            // Windows shortcut hot keys involve at least 2 modifiers
            if (nMods >= 2)
            {
                Keys kFull = (kMod | (Keys)vKey);
                if (HotKeyManager.IsHotKeyRegistered(kFull, true))
                {
                    return(false);
                }
            }

            Keys kModDiff = (kMod & ~m_kModCur);

            if (kModDiff != Keys.None)
            {
                // Send RAlt for better AltGr compatibility;
                // https://sourceforge.net/p/keepass/bugs/1475/
                SetKeyModifierImplEx(kModDiff, true, true);

                Thread.Sleep(1);
                Application.DoEvents();
            }

            SendKeyImpl(vKey, null, bDown);

            if (kModDiff != Keys.None)
            {
                Thread.Sleep(1);
                Application.DoEvents();

                SetKeyModifierImplEx(kModDiff, false, true);
            }

            return(true);
        }