private static SiStateEx InitSendKeys() { SiStateEx si = new SiStateEx(); try { EnsureSameKeyboardLayout(si); // Do not use SendKeys.Flush here, use Application.DoEvents // instead; SendKeys.Flush might run into an infinite loop here // if a previous auto-type process failed with throwing an // exception (SendKeys.Flush is waiting in a loop for an internal // queue being empty, however the queue is never processed) Application.DoEvents(); List<int> lMod = GetActiveKeyModifiers(); ActivateKeyModifiers(lMod, false); SpecialReleaseModifiers(lMod); si.InputBlocked = NativeMethods.BlockInput(true); } catch(Exception) { Debug.Assert(false); } return si; }
// private const ushort LangIDGerman = 0x0407; public static void SendKeysWait(string strKeys, bool bObfuscate) { SiStateEx si = InitSendKeys(); bool bUnix = KeePassLib.Native.NativeLib.IsUnix(); try { if (!bUnix) { Debug.Assert(GetActiveKeyModifiers().Count == 0); } strKeys = ExtractGlobalDelay(strKeys, si); // Before TCATO splitting if (bObfuscate) { try { SendObfuscated(strKeys, si); } catch (Exception) { SendKeysWithSpecial(strKeys, si); } } else { SendKeysWithSpecial(strKeys, si); } } catch { FinishSendKeys(si); throw; } FinishSendKeys(si); }
/// <summary> /// This method searches for a <c>{DELAY=X}</c> placeholder, /// removes it from the sequence and sets the global delay in /// <paramref name="siState" /> to X. /// </summary> private static string ExtractGlobalDelay(string strSequence, SiStateEx siState) { if (string.IsNullOrEmpty(strSequence)) { return(string.Empty); } const string strDefDelay = @"(\{[Dd][Ee][Ll][Aa][Yy]\s*=\s*)(\d+)(\})"; Match mDefDelay = Regex.Match(strSequence, strDefDelay); if (mDefDelay.Success) { string strTime = mDefDelay.Groups[2].Value; strSequence = Regex.Replace(strSequence, strDefDelay, string.Empty); uint uTime; if (uint.TryParse(strTime, out uTime)) { siState.DefaultDelay = uTime; } else { Debug.Assert(false); } } return(strSequence); }
private static void FinishSendKeys(SiStateEx si) { if (KeePassLib.Native.NativeLib.IsUnix()) { return; } try { // Do not restore original modifier keys here, otherwise // modifier keys are restored even when the user released // them while KeePass is auto-typing! // ActivateKeyModifiers(lRestore, true); if (si.InputBlocked) { NativeMethods.BlockInput(false); // Unblock } // if(si.ThreadInputAttached) // NativeMethods.AttachThreadInput(si.ThisThreadID, // si.TargetThreadID, false); // Detach if (si.OriginalKeyboardLayout != IntPtr.Zero) { NativeMethods.ActivateKeyboardLayout(si.OriginalKeyboardLayout, 0); } Application.DoEvents(); } catch (Exception) { Debug.Assert(false); } }
private static void EnsureSameKeyboardLayout(SiStateEx si) { IntPtr hWndTarget = NativeMethods.GetForegroundWindow(); uint uTargetProcessId; uint uTargetThreadId = NativeMethods.GetWindowThreadProcessId(hWndTarget, out uTargetProcessId); IntPtr hklSelf = NativeMethods.GetKeyboardLayout(0); IntPtr hklTarget = NativeMethods.GetKeyboardLayout(uTargetThreadId); si.CurrentKeyboardLayout = hklSelf; if (hklSelf != hklTarget) { si.OriginalKeyboardLayout = NativeMethods.ActivateKeyboardLayout( hklTarget, 0); si.CurrentKeyboardLayout = hklTarget; Debug.Assert(si.OriginalKeyboardLayout == hklSelf); } // ushort uLangID = (ushort)(si.CurrentKeyboardLayout.ToInt64() & 0xFFFF); // si.EnableCaretWorkaround = (uLangID == LangIDGerman); }
private static SiStateEx InitSendKeys() { SiStateEx si = new SiStateEx(); try { EnsureSameKeyboardLayout(si); // Do not use SendKeys.Flush here, use Application.DoEvents // instead; SendKeys.Flush might run into an infinite loop here // if a previous auto-type process failed with throwing an // exception (SendKeys.Flush is waiting in a loop for an internal // queue being empty, however the queue is never processed) Application.DoEvents(); List <int> lMod = GetActiveKeyModifiers(); ActivateKeyModifiers(lMod, false); SpecialReleaseModifiers(lMod); si.InputBlocked = NativeMethods.BlockInput(true); } catch (Exception) { Debug.Assert(false); } return(si); }
// private const ushort LangIDGerman = 0x0407; public static void SendKeysWait(string strKeys, bool bObfuscate) { if (KeePassLib.Native.NativeLib.IsUnix()) { try { OSSendKeys(strKeys); } catch (Exception) { Debug.Assert(false); } return; } SiStateEx si = InitSendKeys(); try { Debug.Assert(GetActiveKeyModifiers().Count == 0); if (bObfuscate) { try { SendObfuscated(strKeys, si); } catch (Exception) { SendKeysWithSpecial(strKeys, si); } } else { SendKeysWithSpecial(strKeys, si); } } catch { FinishSendKeys(si); throw; } FinishSendKeys(si); }
private static bool ValidateTargetWindow(SiStateEx siState) { if (siState.Cancelled) { return(false); } if (!Program.Config.Integration.AutoTypeCancelOnWindowChange) { return(true); } if (KeePassLib.Native.NativeLib.IsUnix()) { return(true); } bool bValid = true; try { IntPtr h = NativeMethods.GetForegroundWindowHandle(); if (h != siState.TargetHWnd) { siState.Cancelled = true; bValid = false; } } catch (Exception) { Debug.Assert(false); } return(bValid); }
private static void SendKeysWithSpecial(string strSequence, SiStateEx siState) { Debug.Assert(strSequence != null); if (string.IsNullOrEmpty(strSequence)) { return; } strSequence = ApplyGlobalDelay(strSequence, siState); while (true) { int nDelayStart = strSequence.IndexOf("{DELAY ", StrUtil.CaseIgnoreCmp); if (nDelayStart >= 0) { int nDelayEnd = strSequence.IndexOf('}', nDelayStart); if (nDelayEnd >= 0) { uint uDelay; string strDelay = strSequence.Substring(nDelayStart + 7, nDelayEnd - (nDelayStart + 7)); if (uint.TryParse(strDelay, out uDelay)) { string strFirstPart = strSequence.Substring(0, nDelayStart); string strSecondPart = strSequence.Substring( nDelayEnd + 1); if (!string.IsNullOrEmpty(strFirstPart)) { OSSendKeys(strFirstPart); } SendKeys.Flush(); Thread.Sleep((int)uDelay); strSequence = strSecondPart; } else { Debug.Assert(false); break; } } else { Debug.Assert(false); break; } } else { break; } } if (!string.IsNullOrEmpty(strSequence)) { OSSendKeys(strSequence); } }
private static void SendKeysWithSpecial(string strSequence, SiStateEx siState) { Debug.Assert(strSequence != null); if (string.IsNullOrEmpty(strSequence)) { return; } strSequence = ExtractGlobalDelay(strSequence, siState); // Update strSequence = ApplyGlobalDelay(strSequence, siState); List <string> v = SplitSpecialSequence(strSequence); foreach (string strPart in v) { string strParam = GetParamIfSpecial(strPart, SkcDelay); if (strParam != null) // Might be empty (invalid parameter) { uint uDelay; if (uint.TryParse(strParam, out uDelay)) { if (uDelay == 0) { uDelay = 1; } if ((uDelay <= (uint)int.MaxValue) && !siState.Cancelled) { Thread.Sleep((int)uDelay); } } continue; } strParam = GetParamIfSpecial(strPart, SkcVKey); if (strParam != null) // Might be empty (invalid parameter) { int vKey; if (int.TryParse(strParam, out vKey) && !KeePassLib.Native.NativeLib.IsUnix()) { SendVKeyNative(vKey, true); SendVKeyNative(vKey, false); Application.DoEvents(); } continue; } OSSendKeys(strPart, siState); Application.DoEvents(); // SendKeys.SendWait uses SendKeys.Flush if (siState.Cancelled) { break; } } }
private static void MixedTransfer(string strText, SiStateEx siState) { StringBuilder sbKeys = new StringBuilder(); StringBuilder sbClip = new StringBuilder(); // The string should be split randomly, but the same each // time this function is called. Otherwise an attacker could // get information by observing different splittings each // time auto-type is performed. Therefore, compute the random // seed based on the string to be auto-typed. Random r = new Random(GetRandomSeed(strText)); foreach (char ch in strText) { if (r.Next(0, 2) == 0) { sbClip.Append(ch); sbKeys.Append(@"{RIGHT}"); } else { sbKeys.Append(ch); } } string strClip = sbClip.ToString(); string strKeys = sbKeys.ToString(); if (strClip.Length > 0) { StringBuilder sbNav = new StringBuilder(); sbNav.Append(@"^v"); for (int iLeft = 0; iLeft < strClip.Length; ++iLeft) { sbNav.Append(@"{LEFT}"); } strKeys = sbNav.ToString() + strKeys; } if (strClip.Length > 0) { ClipboardUtil.Copy(strClip, false, false, null, null, IntPtr.Zero); } else { ClipboardUtil.Clear(); } if (strKeys.Length > 0) { SendKeysWithSpecial(strKeys, siState); } ClipboardUtil.Clear(); }
private static void SendObfuscated(string strKeys, SiStateEx siState) { Debug.Assert(strKeys != null); if (strKeys == null) { throw new ArgumentNullException("strKeys"); } if (strKeys.Length == 0) { return; } ClipboardEventChainBlocker cev = new ClipboardEventChainBlocker(); ClipboardContents cnt = new ClipboardContents(true, true); Exception excpInner = null; char[] vSpecial = new char[] { '{', '}', '(', ')', '+', '^', '%', ' ', '\t', '\r', '\n' }; try { List <string> vParts = SplitKeySequence(strKeys); foreach (string strPart in vParts) { if (string.IsNullOrEmpty(strPart)) { continue; } if (strPart.IndexOfAny(vSpecial) >= 0) { SendKeysWithSpecial(strPart, siState); } else { MixedTransfer(strPart, siState); } } } catch (Exception ex) { excpInner = ex; } cnt.SetData(); cev.Release(); if (excpInner != null) { throw excpInner; } }
private static SiStateEx InitSendKeys() { SiStateEx si = new SiStateEx(); if (KeePassLib.Native.NativeLib.IsUnix()) { si.DefaultDelay /= 3; // Starting external program takes time return(si); } try { si.TargetHWnd = NativeMethods.GetForegroundWindowHandle(); si.ThisThreadID = NativeMethods.GetCurrentThreadId(); uint uTargetProcessID; si.TargetThreadID = NativeMethods.GetWindowThreadProcessId( si.TargetHWnd, out uTargetProcessID); si.TargetProcessID = uTargetProcessID; EnsureSameKeyboardLayout(si); // Do not use SendKeys.Flush here, use Application.DoEvents // instead; SendKeys.Flush might run into an infinite loop here // if a previous auto-type process failed with throwing an // exception (SendKeys.Flush is waiting in a loop for an internal // queue being empty, however the queue is never processed) Application.DoEvents(); // if(si.ThisThreadID != si.TargetThreadID) // { // si.ThreadInputAttached = NativeMethods.AttachThreadInput( // si.ThisThreadID, si.TargetThreadID, true); // Debug.Assert(si.ThreadInputAttached); // } // else { Debug.Assert(false); } List <int> lMod = GetActiveKeyModifiers(); ActivateKeyModifiers(lMod, false); SpecialReleaseModifiers(lMod); Debug.Assert(GetActiveKeyModifiers().Count == 0); si.InputBlocked = NativeMethods.BlockInput(true); } catch (Exception) { Debug.Assert(false); } return(si); }
private static void OSSendKeys(string strSequence, SiStateEx siState) { if (!ValidateTargetWindow(siState)) { return; } if (!KeePassLib.Native.NativeLib.IsUnix()) { OSSendKeysWindows(strSequence); } else // Unix { OSSendKeysUnix(strSequence); } }
private static void EnsureSameKeyboardLayout(SiStateEx si) { IntPtr hklSelf = NativeMethods.GetKeyboardLayout(0); IntPtr hklTarget = NativeMethods.GetKeyboardLayout(si.TargetThreadID); si.CurrentKeyboardLayout = hklSelf; if(hklSelf != hklTarget) { si.OriginalKeyboardLayout = NativeMethods.ActivateKeyboardLayout( hklTarget, 0); si.CurrentKeyboardLayout = hklTarget; Debug.Assert(si.OriginalKeyboardLayout == hklSelf); } // ushort uLangID = (ushort)(si.CurrentKeyboardLayout.ToInt64() & 0xFFFF); // si.EnableCaretWorkaround = (uLangID == LangIDGerman); }
private static string ApplyGlobalDelay(string strSequence, SiStateEx siState) { if (string.IsNullOrEmpty(strSequence)) { return(string.Empty); } // strSequence = Regex.Replace(strSequence, @"(\{.+?\}+?|.+?)", // @"{delay " + strTime + @"}$1"); // strSequence = Regex.Replace(strSequence, @"(\{.+?\}+?|([\+\^%]\(.+?\))|[\+\^%].+?|.+?)", // @"{delay " + strTime + @"}$1"); if (siState.DefaultDelay > 0) { // const string strRx = @"(\{.+?\}+?|([\+\^%]\(.+?\))|([\+\^%]\{.+?\})|[\+\^%].+?|.+?)"; const string strRx = @"(\{.+?\}+?|([\+\^%]+\(.+?\))|([\+\^%]+\{.+?\})|[\+\^%]+.+?|.+?)"; strSequence = Regex.Replace(strSequence, strRx, @"{DELAY " + siState.DefaultDelay.ToString() + @"}$1"); } return(strSequence); }
private static string ApplyGlobalDelay(string strSequence, SiStateEx siState) { if (string.IsNullOrEmpty(strSequence)) { return(string.Empty); } const string strDefDelay = @"(\{[Dd][Ee][Ll][Aa][Yy]\s*=\s*)(\d+)(\})"; Match mDefDelay = Regex.Match(strSequence, strDefDelay); if (mDefDelay.Success) { string strTime = mDefDelay.Groups[2].Value; strSequence = Regex.Replace(strSequence, strDefDelay, string.Empty); uint uTime; if (uint.TryParse(strTime, out uTime)) { siState.DefaultDelay = uTime; } else { Debug.Assert(false); } } // strSequence = Regex.Replace(strSequence, @"(\{.+?\}+?|.+?)", // @"{delay " + strTime + @"}$1"); // strSequence = Regex.Replace(strSequence, @"(\{.+?\}+?|([\+\^%]\(.+?\))|[\+\^%].+?|.+?)", // @"{delay " + strTime + @"}$1"); if (siState.DefaultDelay > 0) { // const string strRx = @"(\{.+?\}+?|([\+\^%]\(.+?\))|([\+\^%]\{.+?\})|[\+\^%].+?|.+?)"; const string strRx = @"(\{.+?\}+?|([\+\^%]+\(.+?\))|([\+\^%]+\{.+?\})|[\+\^%]+.+?|.+?)"; strSequence = Regex.Replace(strSequence, strRx, @"{DELAY " + siState.DefaultDelay.ToString() + @"}$1"); } return(strSequence); }
private static void FinishSendKeys(SiStateEx si) { try { // Do not restore original modifier keys here, otherwise // modifier keys are restored even when the user released // them while KeePass is auto-typing! // ActivateKeyModifiers(lRestore, true); if (si.InputBlocked) { NativeMethods.BlockInput(false); // Unblock } if (si.OriginalKeyboardLayout != IntPtr.Zero) { NativeMethods.ActivateKeyboardLayout(si.OriginalKeyboardLayout, 0); } Application.DoEvents(); } catch (Exception) { Debug.Assert(false); } }
private static void EnsureSameKeyboardLayout(SiStateEx si) { IntPtr hklSelf = NativeMethods.GetKeyboardLayout(0); IntPtr hklTarget = NativeMethods.GetKeyboardLayout(si.TargetThreadID); si.CurrentKeyboardLayout = hklSelf; if (!Program.Config.Integration.AutoTypeAdjustKeyboardLayout) { return; } if (hklSelf != hklTarget) { si.OriginalKeyboardLayout = NativeMethods.ActivateKeyboardLayout( hklTarget, 0); si.CurrentKeyboardLayout = hklTarget; Debug.Assert(si.OriginalKeyboardLayout == hklSelf); } // ushort uLangID = (ushort)(si.CurrentKeyboardLayout.ToInt64() & 0xFFFF); // si.EnableCaretWorkaround = (uLangID == LangIDGerman); }
private static string ApplyGlobalDelay(string strSequence, SiStateEx siState) { if(string.IsNullOrEmpty(strSequence)) return string.Empty; const string strDefDelay = @"(\{[Dd][Ee][Ll][Aa][Yy]\s*=\s*)(\d+)(\})"; Match mDefDelay = Regex.Match(strSequence, strDefDelay); if(mDefDelay.Success) { string strTime = mDefDelay.Groups[2].Value; strSequence = Regex.Replace(strSequence, strDefDelay, string.Empty); uint uTime; if(uint.TryParse(strTime, out uTime)) siState.DefaultDelay = uTime; else { Debug.Assert(false); } } // strSequence = Regex.Replace(strSequence, @"(\{.+?\}+?|.+?)", // @"{delay " + strTime + @"}$1"); // strSequence = Regex.Replace(strSequence, @"(\{.+?\}+?|([\+\^%]\(.+?\))|[\+\^%].+?|.+?)", // @"{delay " + strTime + @"}$1"); if(siState.DefaultDelay > 0) { // const string strRx = @"(\{.+?\}+?|([\+\^%]\(.+?\))|([\+\^%]\{.+?\})|[\+\^%].+?|.+?)"; const string strRx = @"(\{.+?\}+?|([\+\^%]+\(.+?\))|([\+\^%]+\{.+?\})|[\+\^%]+.+?|.+?)"; strSequence = Regex.Replace(strSequence, strRx, @"{DELAY " + siState.DefaultDelay.ToString() + @"}$1"); } return strSequence; }
private static void FinishSendKeys(SiStateEx si) { try { // Do not restore original modifier keys here, otherwise // modifier keys are restored even when the user released // them while KeePass is auto-typing! // ActivateKeyModifiers(lRestore, true); if(si.InputBlocked) NativeMethods.BlockInput(false); // Unblock if(si.OriginalKeyboardLayout != IntPtr.Zero) NativeMethods.ActivateKeyboardLayout(si.OriginalKeyboardLayout, 0); Application.DoEvents(); } catch(Exception) { Debug.Assert(false); } }
private static void SendObfuscated(string strKeys, SiStateEx siState) { if(string.IsNullOrEmpty(strKeys)) return; ClipboardEventChainBlocker cev = new ClipboardEventChainBlocker(); ClipboardContents cnt = new ClipboardContents(true, true); Exception excpInner = null; char[] vSpecial = new char[]{ '{', '}', '(', ')', '+', '^', '%', ' ', '\t', '\r', '\n' }; try { List<string> vParts = SplitKeySequence(strKeys); foreach(string strPart in vParts) { if(string.IsNullOrEmpty(strPart)) continue; if(strPart.IndexOfAny(vSpecial) >= 0) SendKeysWithSpecial(strPart, siState); else MixedTransfer(strPart, siState); } } catch(Exception ex) { excpInner = ex; } cnt.SetData(); cev.Release(); if(excpInner != null) throw excpInner; }
private static bool ValidateTargetWindow(SiStateEx siState) { if(siState.Cancelled) return false; if(!Program.Config.Integration.AutoTypeCancelOnWindowChange) return true; if(KeePassLib.Native.NativeLib.IsUnix()) return true; bool bValid = true; try { IntPtr h = NativeMethods.GetForegroundWindowHandle(); if(h != siState.TargetHWnd) { siState.Cancelled = true; bValid = false; } } catch(Exception) { Debug.Assert(false); } return bValid; }
private static void OSSendKeys(string strSequence, SiStateEx siState) { if(!ValidateTargetWindow(siState)) return; if(!KeePassLib.Native.NativeLib.IsUnix()) OSSendKeysWindows(strSequence); else // Unix OSSendKeysUnix(strSequence); }
private static void SendKeysWithSpecial(string strSequence, SiStateEx siState) { Debug.Assert(strSequence != null); if(string.IsNullOrEmpty(strSequence)) return; strSequence = ExtractGlobalDelay(strSequence, siState); // Update strSequence = ApplyGlobalDelay(strSequence, siState); List<string> v = SplitSpecialSequence(strSequence); foreach(string strPart in v) { string strParam = GetParamIfSpecial(strPart, SkcDelay); if(strParam != null) // Might be empty (invalid parameter) { uint uDelay; if(uint.TryParse(strParam, out uDelay)) { if(uDelay == 0) uDelay = 1; if((uDelay <= (uint)int.MaxValue) && !siState.Cancelled) Thread.Sleep((int)uDelay); } continue; } strParam = GetParamIfSpecial(strPart, SkcVKey); if(strParam != null) // Might be empty (invalid parameter) { int vKey; if(int.TryParse(strParam, out vKey) && !KeePassLib.Native.NativeLib.IsUnix()) { SendVKeyNative(vKey, true); SendVKeyNative(vKey, false); Application.DoEvents(); } continue; } OSSendKeys(strPart, siState); Application.DoEvents(); // SendKeys.SendWait uses SendKeys.Flush if(siState.Cancelled) break; } }
private static SiStateEx InitSendKeys() { SiStateEx si = new SiStateEx(); if(KeePassLib.Native.NativeLib.IsUnix()) { si.DefaultDelay /= 2; // Starting external program takes time return si; } try { si.TargetHWnd = NativeMethods.GetForegroundWindowHandle(); si.ThisThreadID = NativeMethods.GetCurrentThreadId(); uint uTargetProcessID; si.TargetThreadID = NativeMethods.GetWindowThreadProcessId( si.TargetHWnd, out uTargetProcessID); si.TargetProcessID = uTargetProcessID; EnsureSameKeyboardLayout(si); // Do not use SendKeys.Flush here, use Application.DoEvents // instead; SendKeys.Flush might run into an infinite loop here // if a previous auto-type process failed with throwing an // exception (SendKeys.Flush is waiting in a loop for an internal // queue being empty, however the queue is never processed) Application.DoEvents(); // if(si.ThisThreadID != si.TargetThreadID) // { // si.ThreadInputAttached = NativeMethods.AttachThreadInput( // si.ThisThreadID, si.TargetThreadID, true); // Debug.Assert(si.ThreadInputAttached); // } // else { Debug.Assert(false); } List<int> lMod = GetActiveKeyModifiers(); ActivateKeyModifiers(lMod, false); SpecialReleaseModifiers(lMod); Debug.Assert(GetActiveKeyModifiers().Count == 0); si.InputBlocked = NativeMethods.BlockInput(true); } catch(Exception) { Debug.Assert(false); } return si; }
private static void MixedTransfer(string strText, SiStateEx siState) { StringBuilder sbKeys = new StringBuilder(); StringBuilder sbClip = new StringBuilder(); // The string should be split randomly, but the same each // time this function is called. Otherwise an attacker could // get information by observing different splittings each // time auto-type is performed. Therefore, compute the random // seed based on the string to be auto-typed. Random r = new Random(GetRandomSeed(strText)); foreach(char ch in strText) { if(r.Next(0, 2) == 0) { sbClip.Append(ch); sbKeys.Append(@"{RIGHT}"); } else sbKeys.Append(ch); } string strClip = sbClip.ToString(); string strKeys = sbKeys.ToString(); if(strClip.Length > 0) { StringBuilder sbNav = new StringBuilder(); sbNav.Append(@"^v"); for(int iLeft = 0; iLeft < strClip.Length; ++iLeft) sbNav.Append(@"{LEFT}"); strKeys = sbNav.ToString() + strKeys; } if(strClip.Length > 0) ClipboardUtil.Copy(strClip, false, false, null, null, IntPtr.Zero); else ClipboardUtil.Clear(); if(strKeys.Length > 0) SendKeysWithSpecial(strKeys, siState); ClipboardUtil.Clear(); }
private static void FinishSendKeys(SiStateEx si) { if(KeePassLib.Native.NativeLib.IsUnix()) return; try { // Do not restore original modifier keys here, otherwise // modifier keys are restored even when the user released // them while KeePass is auto-typing! // ActivateKeyModifiers(lRestore, true); if(si.InputBlocked) NativeMethods.BlockInput(false); // Unblock // if(si.ThreadInputAttached) // NativeMethods.AttachThreadInput(si.ThisThreadID, // si.TargetThreadID, false); // Detach if(si.OriginalKeyboardLayout != IntPtr.Zero) NativeMethods.ActivateKeyboardLayout(si.OriginalKeyboardLayout, 0); Application.DoEvents(); } catch(Exception) { Debug.Assert(false); } }
/// <summary> /// This method searches for a <c>{DELAY=X}</c> placeholder, /// removes it from the sequence and sets the global delay in /// <paramref name="siState" /> to X. /// </summary> private static string ExtractGlobalDelay(string strSequence, SiStateEx siState) { if(string.IsNullOrEmpty(strSequence)) return string.Empty; const string strDefDelay = @"(\{[Dd][Ee][Ll][Aa][Yy]\s*=\s*)(\d+)(\})"; Match mDefDelay = Regex.Match(strSequence, strDefDelay); if(mDefDelay.Success) { string strTime = mDefDelay.Groups[2].Value; strSequence = Regex.Replace(strSequence, strDefDelay, string.Empty); uint uTime; if(uint.TryParse(strTime, out uTime)) siState.DefaultDelay = uTime; else { Debug.Assert(false); } } return strSequence; }
private static string ApplyGlobalDelay(string strSequence, SiStateEx siState) { if(string.IsNullOrEmpty(strSequence)) return string.Empty; // strSequence = Regex.Replace(strSequence, @"(\{.+?\}+?|.+?)", // @"{delay " + strTime + @"}$1"); // strSequence = Regex.Replace(strSequence, @"(\{.+?\}+?|([\+\^%]\(.+?\))|[\+\^%].+?|.+?)", // @"{delay " + strTime + @"}$1"); if(siState.DefaultDelay > 0) { // const string strRx = @"(\{.+?\}+?|([\+\^%]\(.+?\))|([\+\^%]\{.+?\})|[\+\^%].+?|.+?)"; const string strRx = @"(\{.+?\}+?|([\+\^%]+\(.+?\))|([\+\^%]+\{.+?\})|[\+\^%]+.+?|.+?)"; strSequence = Regex.Replace(strSequence, strRx, @"{DELAY " + siState.DefaultDelay.ToString() + @"}$1"); } return strSequence; }
private static bool ValidateTargetWindow(SiStateEx siState) { if(siState.Cancelled) return false; if(KeePassLib.Native.NativeLib.IsUnix()) return true; bool bChkWnd = Program.Config.Integration.AutoTypeCancelOnWindowChange; bool bChkTitle = Program.Config.Integration.AutoTypeCancelOnTitleChange; if(!bChkWnd && !bChkTitle) return true; bool bValid = true; try { IntPtr h; string strTitle; NativeMethods.GetForegroundWindowInfo(out h, out strTitle, false); if(bChkWnd && (h != siState.TargetHWnd)) { siState.Cancelled = true; bValid = false; } if(bChkTitle && ((strTitle ?? string.Empty) != siState.TargetWindowTitle)) { siState.Cancelled = true; bValid = false; } } catch(Exception) { Debug.Assert(false); } return bValid; }
private static void SendKeysWithSpecial(string strSequence, SiStateEx siState) { Debug.Assert(strSequence != null); if(string.IsNullOrEmpty(strSequence)) return; strSequence = ApplyGlobalDelay(strSequence, siState); while(true) { int nDelayStart = strSequence.IndexOf("{DELAY ", StrUtil.CaseIgnoreCmp); if(nDelayStart >= 0) { int nDelayEnd = strSequence.IndexOf('}', nDelayStart); if(nDelayEnd >= 0) { uint uDelay; string strDelay = strSequence.Substring(nDelayStart + 7, nDelayEnd - (nDelayStart + 7)); if(uint.TryParse(strDelay, out uDelay)) { string strFirstPart = strSequence.Substring(0, nDelayStart); string strSecondPart = strSequence.Substring( nDelayEnd + 1); if(!string.IsNullOrEmpty(strFirstPart)) OSSendKeys(strFirstPart); SendKeys.Flush(); Thread.Sleep((int)uDelay); strSequence = strSecondPart; } else { Debug.Assert(false); break; } } else { Debug.Assert(false); break; } } else break; } if(!string.IsNullOrEmpty(strSequence)) OSSendKeys(strSequence); }