/// <summary> /// Presses Ctrl+key. Does not release. /// If enter is true, Release will press Enter. /// </summary> public void Press(KKey key, OptKey opt, AWnd wFocus, bool enter = false) { _scan = VkToSc(_vk = key, Api.GetKeyboardLayout(wFocus.ThreadId)); _enter = enter; _opt = opt; SendCtrl(true); Internal_.Sleep(opt.KeySpeedClipboard); //need 1 ms for IE address bar, 100 ms for BlueStacks SendKeyEventRaw(_vk, _scan, 0); }
/// <summary> /// Releases modifier keys if pressed and no option NoModOff. Turns off CapsLock if toggled and no option NoCapsOff. /// When releasing modifiers, if pressed Alt or Win without Ctrl, presses-releases Ctrl to avoid menu mode. /// Returns true if turned off CapsLock. /// Does not sleep, blockinput, etc. /// </summary> internal static bool ReleaseModAndCapsLock(OptKey opt) { //note: don't call Hook here, it does not make sense. bool R = !opt.NoCapsOff && IsCapsLock; if (R) { if (IsPressed(KKey.CapsLock)) { SendKey(KKey.CapsLock, 2); //never mind: in this case later may not restore CapsLock because of auto-repeat } SendKey(KKey.CapsLock); if (IsCapsLock) { //Probably Shift is set to turn off CapsLock in CP dialog "Text Services and Input Languages". // Win10: Settings -> Time & Language -> Language -> Input method -> Hot keys. AHookWin.IgnoreLShiftCaps_(2000); SendKey(KKey.Shift); AHookWin.IgnoreLShiftCaps_(0); R = !IsCapsLock; Debug.Assert(R); //note: need IgnoreLShiftCaps_, because when we send Shift, the BlockInput hook receives these events: //Left Shift down, not injected //!! //Caps Lock down, not injected //Caps Lock up, not injected //Left Shift up, injected //speed: often ~15 ms. Without Shift max 5 ms. //never mind: don't need to turn off CapsLock if there is only text, unless Options.TextOption == KTextOption.Keys. } } if (!opt.NoModOff) { ReleaseModAndDisableModMenu(); } return(R); }
//Caller should set k.scan; this func doesn't. unsafe static void _SendKey2(_KEvent k, _KEvent kNext, bool isLast, OptKey opt) { var ki = new Api.INPUTK(k.vk, k.scan, (uint)k.SIFlags); int count = 1, sleep = opt.KeySpeed; if (isLast) { if (!k.IsPair) { sleep = Internal_.LimitSleepTime(sleep) - opt.SleepFinally; } } else { if (kNext.IsRepeat) { count = kNext.repeat; } else if (!k.IsPair) { //If this is pair, sleep between down and up, and don't sleep after up. //Else if repeat, sleep always. //Else in most cases don't need to sleep. In some cases need, but can limit the time. // For example, in Ctrl+C normally would not need to sleep after Ctrl down and Ctrl up. // However some apps/controls then may not work. Maybe they process mod and nonmod keys somehow async. // For example, Ctrl+C in IE address bar often does not work if there is no sleep after Ctrl down. Always works if 1 ms. sleep = Internal_.LimitSleepTime(sleep); if (kNext.IsKey) { bool thisMod = KeyTypes_.IsMod(k.vk), nextMod = KeyTypes_.IsMod(kNext.vk); if (!k.IsUp) { if (kNext.IsUp) { sleep = opt.KeySpeed; } else if (thisMod == nextMod) { sleep = 0; } } else { if (!thisMod || nextMod) { sleep = 0; } } } else if (kNext.IsSleep) { sleep = sleep - kNext.sleep; } } } if (sleep < 0) { sleep = 0; } //var s = (k.vk).ToString(); //if(k.IsPair) AOutput.Write($"{s}<{sleep}>"); //else { var ud = k.IsUp ? '-' : '+'; if(sleep > 0) AOutput.Write($"{s}{ud} {sleep}"); else AOutput.Write($"{s}{ud}"); } for (int r = 0; r < count; r++) { //APerf.First(); Api.SendInput(&ki); //APerf.Next(); if (sleep > 0) { Internal_.Sleep(sleep); } if (k.IsPair) { ki.dwFlags |= Api.KEYEVENTF_KEYUP; Api.SendInput(&ki); ki.dwFlags &= ~Api.KEYEVENTF_KEYUP; } //APerf.NW(); //speed: min 400 mcs for each event. Often > 1000. Does not depend on whether all events sent by single SendInput call. } }
/// <param name="cloneOptions">Options to be copied to <see cref="Options"/> of this variable. If null, uses default options.</param> /// <example> /// <code><![CDATA[ /// var k = new AKeys(AOpt.Static.Key); /// k.Options.KeySpeed = 50; /// k.AddKeys("Tab // Space").AddRepeat(3).AddText("text").AddKey(KKey.Enter).AddSleep(500); /// k.Send(); //sends and clears the variable /// k.Add("Tab // Space*3", (KText)"text", KKey.Enter, 500); //the same as the above k.AddKeys... line /// for(int i = 0; i < 5; i++) k.Send(true); //does not clear the variable /// ]]></code> /// </example> public AKeys(OptKey cloneOptions) { Options = new OptKey(cloneOptions); }
/// <summary> /// Sends Enter. /// </summary> public static void Enter(OptKey opt) { var e = new _KEvent(true, KKey.Enter, 0, 0x1C); _SendKey2(e, default, true, opt);