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 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, }); } } }