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(MouseInput mouseInput) { // denormalize coordinates into client coordinates (we should always expect normalized coordinates, whether coordinates are absolute or relative) ushort x = (ushort)Math.Ceiling((double)(mouseInput.Point.X) * ((double)ClientWindowRect.Width / 65536.0)); ushort y = (ushort)Math.Ceiling((double)(mouseInput.Point.Y) * ((double)ClientWindowRect.Height / 65536.0)); var clientRelativeCoordinates = WinAPI.MACROS.MAKELPARAM(x, y); var wm = WinAPI.WM.USER; switch ((mouseInput.Flags | WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_ABSOLUTE) ^ WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_ABSOLUTE) { case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_MOVE: wm = WinAPI.WM.MOUSEMOVE; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_LEFTDOWN: //WinAPI.Cursor.SetCapture(ClientWindowHandle); wm = WinAPI.WM.LBUTTONDOWN; CurrentMK |= WinAPI.Windows.MK.MK_LBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_LEFTUP: //var priorCapture = WinAPI.Cursor.GetCapture(); //if (priorCapture == IntPtr.Zero) //{ // ("GetCapture Fail").LogWarn(); //} //else //{ // WinAPI.Cursor.ReleaseCapture(); //} wm = WinAPI.WM.LBUTTONUP; CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_LBUTTON) ^ WinAPI.Windows.MK.MK_LBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_RIGHTDOWN: //WinAPI.Cursor.SetCapture(ClientWindowHandle); wm = WinAPI.WM.RBUTTONDOWN; CurrentMK |= WinAPI.Windows.MK.MK_RBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_RIGHTUP: //var priorCapture = WinAPI.Cursor.GetCapture(); //if (priorCapture == IntPtr.Zero) //{ // ("GetCapture Fail").LogWarn(); //} //else //{ // WinAPI.Cursor.ReleaseCapture(); //} wm = WinAPI.WM.RBUTTONUP; CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_RBUTTON) ^ WinAPI.Windows.MK.MK_RBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_MIDDLEDOWN: wm = WinAPI.WM.MBUTTONDOWN; CurrentMK |= WinAPI.Windows.MK.MK_MBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_MIDDLEUP: wm = WinAPI.WM.MBUTTONUP; CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_MBUTTON) ^ WinAPI.Windows.MK.MK_MBUTTON; break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_XDOWN: wm = WinAPI.WM.XBUTTONDOWN; switch (WinAPI.MACROS.GET_XBUTTON_WPARAM(mouseInput.MouseData)) { case WinAPI.MACROS.XBUTTONS.XBUTTON1: CurrentMK |= WinAPI.Windows.MK.MK_XBUTTON1; break; case WinAPI.MACROS.XBUTTONS.XBUTTON2: CurrentMK |= WinAPI.Windows.MK.MK_XBUTTON2; break; } break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_XUP: wm = WinAPI.WM.XBUTTONUP; switch (WinAPI.MACROS.GET_XBUTTON_WPARAM(mouseInput.MouseData)) { case WinAPI.MACROS.XBUTTONS.XBUTTON1: CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_XBUTTON1) ^ WinAPI.Windows.MK.MK_XBUTTON1; break; case WinAPI.MACROS.XBUTTONS.XBUTTON2: CurrentMK = (CurrentMK | WinAPI.Windows.MK.MK_XBUTTON2) ^ WinAPI.Windows.MK.MK_XBUTTON2; break; } break; case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_WHEEL: case WinAPI.SendInputApi.MouseEventFlags.MOUSEEVENTF_HWHEEL: wm = WinAPI.WM.MOUSEWHEEL; break; default: wm = mouseInput.WM; break; } WinAPI.Windows.PostMessage(ClientWindowHandle, wm, new UIntPtr(mouseInput.MouseData), new UIntPtr(clientRelativeCoordinates)); }