public static KeyboardInput CreateFrom(WinAPI.WM wParam, Mubox.WinAPI.WindowHook.KBDLLHOOKSTRUCT hookStruct) { KeyboardInput e = new KeyboardInput(); e.VK = hookStruct.vkCode; e.Scan = hookStruct.scanCode; e.Flags = hookStruct.flags; e.Time = hookStruct.time; e.WM = wParam; return e; }
public static KeyboardInput CreateFrom(Win32.WM wParam, Mubox.Win32.WindowHook.KBDLLHOOKSTRUCT hookStruct) { KeyboardInput e = new KeyboardInput(); e.VK = hookStruct.vkCode; e.Scan = hookStruct.scanCode; e.Flags = hookStruct.flags; e.Time = hookStruct.time; e.WM = wParam; return(e); }
private static void OnKeyboardInputReceivedInternal(KeyboardInput e) { try { if (e != null) { KeyboardInputReceived(null, e); if (Performance.IsPerformanceEnabled) { KeyboardHandlerPerformance.Count((long)(e.CreatedTime - DateTime.Now).TotalMilliseconds); } } } catch (Exception ex) { ex.Log(); } }
public virtual void Dispatch(KeyboardInput e) { }
private void Process(KeyboardInput keyboardInput) { if (!UpdatePressedKeys(keyboardInput.VK, keyboardInput.Scan, keyboardInput.Flags, keyboardInput.Time)) { return; } switch ((WinAPI.VK)keyboardInput.VK) { case WinAPI.VK.Control: case WinAPI.VK.LeftControl: case WinAPI.VK.RightControl: if ((keyboardInput.Flags & WinAPI.WindowHook.LLKHF.UP) == WinAPI.WindowHook.LLKHF.UP) { CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_CONTROL) ^ WinAPI.Windows.MK.MK_CONTROL; } else { CurrentMK |= WinAPI.Windows.MK.MK_CONTROL; } break; case WinAPI.VK.Shift: case WinAPI.VK.LeftShift: case WinAPI.VK.RightShift: if ((keyboardInput.Flags & WinAPI.WindowHook.LLKHF.UP) == WinAPI.WindowHook.LLKHF.UP) { CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_SHIFT) ^ WinAPI.Windows.MK.MK_SHIFT; } else { CurrentMK |= WinAPI.Windows.MK.MK_CONTROL; } break; } var vk = keyboardInput.VK; var flags = keyboardInput.Flags; var scan = keyboardInput.Scan; var time = keyboardInput.Time; var cas = keyboardInput.CAS; var wParam = (uint)vk; WinAPI.WM wm = (((flags & WinAPI.WindowHook.LLKHF.UP) == WinAPI.WindowHook.LLKHF.UP) ? WinAPI.WM.KEYUP : WinAPI.WM.KEYDOWN); // TODO SYSKEYDOWN via Win32.WindowHook.LLKHF.AltKey ? uint lParam = 0x01; if (wm == WinAPI.WM.KEYUP) { lParam |= 0xC0000000; // TODO: this may need to change on 64bit platforms, not clear } uint scanCode = scan; if (scanCode > 0) { lParam |= ((scanCode & 0xFF) << 16); // TODO: this may need to change on 64bit platforms, not clear } if ((flags & WinAPI.WindowHook.LLKHF.UP) != WinAPI.WindowHook.LLKHF.UP) { // async Win32.GetKeyboardState or similar to capture actual/current CAS states if ((cas & WinAPI.CAS.CONTROL) != 0) { Process(new KeyboardInput { VK = WinAPI.VK.Control, Flags = (WinAPI.WindowHook.LLKHF)0, Scan = (uint)WinAPI.SendInputApi.MapVirtualKey(WinAPI.VK.Control, WinAPI.SendInputApi.MAPVK.MAPVK_VK_TO_VSC), Time = time, CAS = (WinAPI.CAS)0, }); } if ((cas & WinAPI.CAS.ALT) != 0) { Process(new KeyboardInput { VK = WinAPI.VK.Menu, Flags = (WinAPI.WindowHook.LLKHF)0, Scan = (uint)WinAPI.SendInputApi.MapVirtualKey(WinAPI.VK.Menu, WinAPI.SendInputApi.MAPVK.MAPVK_VK_TO_VSC), Time = time, CAS = (WinAPI.CAS)0, }); flags |= WinAPI.WindowHook.LLKHF.ALTDOWN; } if ((cas & WinAPI.CAS.SHIFT) != 0) { Process(new KeyboardInput { VK = WinAPI.VK.Shift, Flags = (WinAPI.WindowHook.LLKHF)0, Scan = (uint)WinAPI.SendInputApi.MapVirtualKey(WinAPI.VK.Shift, WinAPI.SendInputApi.MAPVK.MAPVK_VK_TO_VSC), Time = time, CAS = (WinAPI.CAS)0, }); } } // NOTE: some apps may actually rely on keyboard state, AttachInputThread will clobber keyboard state. now that we don't continually attach/detach we should be able to set keyboard correctly // TODO: this should be a game profile level option - some games exhibit 'double entry' of input when this is called WinAPI.SetKeyboardState(this.pressedKeys); /* REMOVED: key state becomes invalid for at least one game with this implemented - need to put it into an option if it needs to be re-added - was never noticed because for a while LeftMenu was not being translated into 'Menu' and this code was not executing if (this.pressedKeys[(int)WinAPI.VK.Menu] == 0x80 || keyboardInput.VK == WinAPI.VK.Menu) { switch (wm) { case WinAPI.WM.KEYDOWN: wm = WinAPI.WM.SYSKEYDOWN; break; case WinAPI.WM.KEYUP: wm = WinAPI.WM.SYSKEYUP; break; } } else { switch (wm) { case WinAPI.WM.SYSKEYDOWN: wm = WinAPI.WM.KEYDOWN; break; case WinAPI.WM.SYSKEYUP: wm = WinAPI.WM.KEYUP; break; } } */ WinAPI.Windows.SendMessage(ClientWindowHandle, wm, new UIntPtr(wParam), new UIntPtr(lParam)); // if keydown, translate message // TODO: this should be a game profile option - some games may exhibit 'double entry' of input when this is called, most games don't function correctly without it if (wm == WinAPI.WM.KEYDOWN || wm == WinAPI.WM.SYSKEYDOWN) { var msg = new WinAPI.Windows.MSG(); msg.hwnd = ClientWindowHandle; msg.lParam = lParam; msg.message = wm; msg.pt = new WinAPI.Windows.POINT(); msg.time = WinAPI.SendInputApi.GetTickCount(); msg.wParam = (int)vk; WinAPI.Windows.TranslateMessage(ref msg); //WinAPI.Windows.GetMessage(out msg, ClientWindowHandle, Mubox.WinAPI.WM.CHAR, WinAPI.WM.UNICHAR); //WinAPI.Windows.SendMessage(ClientWindowHandle, wm, new UIntPtr(wParam), new UIntPtr(lParam)); } // TODO: this expression should probably be checking for == UP, but the individual key states need to be refactored to check current state first) // NOTE: if subsequent keys still rely on this state, it will be re-set as expected because of the sister CASE code above if ((flags & WinAPI.WindowHook.LLKHF.UP) != WinAPI.WindowHook.LLKHF.UP) { if ((cas & WinAPI.CAS.CONTROL) != 0) { Process(new KeyboardInput { VK = WinAPI.VK.Control, Flags = WinAPI.WindowHook.LLKHF.UP, Scan = (uint)WinAPI.SendInputApi.MapVirtualKey(WinAPI.VK.Control, WinAPI.SendInputApi.MAPVK.MAPVK_VK_TO_VSC), Time = time, CAS = (WinAPI.CAS)0, }); } if ((cas & WinAPI.CAS.ALT) != 0) { Process(new KeyboardInput { VK = WinAPI.VK.Menu, Flags = WinAPI.WindowHook.LLKHF.UP, Scan = (uint)WinAPI.SendInputApi.MapVirtualKey(WinAPI.VK.Menu, WinAPI.SendInputApi.MAPVK.MAPVK_VK_TO_VSC), Time = time, CAS = (WinAPI.CAS)0, }); } if ((cas & WinAPI.CAS.SHIFT) != 0) { Process(new KeyboardInput { VK = WinAPI.VK.Shift, Flags = WinAPI.WindowHook.LLKHF.UP, Scan = (uint)WinAPI.SendInputApi.MapVirtualKey(WinAPI.VK.Shift, WinAPI.SendInputApi.MAPVK.MAPVK_VK_TO_VSC), Time = time, CAS = (WinAPI.CAS)0, }); } } }
private void KeyboardInputHook_KeyboardInputReceived(object sender, KeyboardInput e) { if (this.Keyboard_DefaultAction != null) { if (this.Keyboard_DefaultAction(e) || e.Handled) { return; } } Func<KeyboardInput, bool> action = null; var keyAction = Keyboard_ActionMap[(WinAPI.VK)e.VK]; if (keyAction != null) { if (keyAction.TryGetValue(e.WM, out action)) { if (action(e) || e.Handled) { return; } } //else //{ // Console.WriteLine("???? MISSING WM ACTION IN MESSAGE MAP - vk=" + (WinAPI.VK)e.VK + " wm=" + e.WM); //} } else { Console.WriteLine("???? MISSING KEY ACTION IN KEY MAP - vk=" + (WinAPI.VK)e.VK + " wm=" + e.WM); } if (!Mubox.Configuration.MuboxConfigSection.Default.IsCaptureEnabled) { return; } Mubox.Extensions.ExtensionManager.Instance.OnKeyboardInputReceived(sender, e); ClientBase activeClient = this.ActiveClient; if (Mubox.Configuration.MuboxConfigSection.Default.Profiles.ActiveProfile.EnableMulticast && !ActiveClientOnly(e)) { e.Handled = true; ClientBase[] clients = GetCachedClients(); KeySetting globalKeySetting; if (MuboxConfigSection.Default.Profiles.ActiveProfile.Keys.TryGetKeySetting((WinAPI.VK)e.VK, out globalKeySetting)) { if (globalKeySetting.RoundRobinKey) { if (clients.Length > 0) { int clientIndex = roundRobinTable[(int)e.VK]; if (e.Flags.HasFlag(WinAPI.WindowHook.LLKHF.UP)) { // we only update round-robin target on key-up, otherwise two different clients receive keydown vs. keyup events roundRobinTable[(int)e.VK] = (byte)clientIndex + 1; } ClientBase client = clients[clientIndex % clients.Length]; InputToClient(e, client); return; } } } foreach (ClientBase client in clients) { InputToClient(e, client); } } else if (activeClient != null) { e.Handled = true; ForwardEventToClient(e, activeClient); } }
private static void InputToClient(KeyboardInput e, ClientBase client) { // this method basically applies CAS settings and calls ForwardEventToClient byte cas = 0; var clientSettings = Mubox.Configuration.MuboxConfigSection.Default.Profiles.ActiveProfile.ActiveClient; if (clientSettings != null) { if (clientSettings.Name.Equals(client.DisplayName, StringComparison.InvariantCultureIgnoreCase)) { Mubox.Configuration.KeySetting keySetting; if (clientSettings.Keys.TryGetKeySetting((WinAPI.VK)e.VK, out keySetting) && keySetting.EnableNoModActiveClient) { cas = (byte)e.CAS; e.CAS = (WinAPI.CAS)0; } } } ForwardEventToClient(e, client); if (cas != 0) { e.CAS = (WinAPI.CAS)cas; } }
private static void ForwardEventToClient(KeyboardInput e, ClientBase clientBase) { try { e.WindowStationHandle = clientBase.WindowStationHandle; e.WindowDesktopHandle = clientBase.WindowDesktopHandle; e.WindowHandle = clientBase.WindowHandle; clientBase.Dispatch(e); } catch (Exception ex) { Mubox.Control.Network.Server.RemoveClient(clientBase); ex.Log(); } }
private static bool ActiveClientOnly(KeyboardInput e) { // TODO optimize !!! iterating 'all keys' looking for a match is a waste of CPU, perhaps a bitmap of Win32.VK makes sense, but it needs to be synchronized against the config (perhaps on Save) bool activeClientOnly = false; foreach (var item in Mubox.Configuration.MuboxConfigSection.Default.Profiles.ActiveProfile.Keys.Cast<Mubox.Configuration.KeySetting>()) { if (item.ActiveClientOnly && (WinAPI.VK)e.VK == item.InputKey) { activeClientOnly = true; break; } } return activeClientOnly; }
public override void Dispatch(KeyboardInput e) { #if DEBUG ("Dispatch(" + _displayName + ") " + Convert.ToString(e)).Log(); #endif ServerTxPerformanceIncrement("KB"); try { Send(e); base.Dispatch(e); } catch { Control.Network.Server.RemoveClient(this); } }