void UpdateKeyboard() { for (byte i = 0; i < byte.MaxValue; i++) { bool pressed = (Functions.GetAsyncKeyState((VirtualKeys)i) >> 8) != 0; Key key; KeyMap.TryGetValue((VirtualKeys)i, out key); keyboard.SetKeyState(key, i, pressed); } }
unsafe IntPtr WindowProcedure(IntPtr handle, WindowMessage message, IntPtr wParam, IntPtr lParam) { switch (message) { #region Size / Move / Style events case WindowMessage.ACTIVATE: // See http://msdn.microsoft.com/en-us/library/ms646274(VS.85).aspx (WM_ACTIVATE notification): // wParam: The low-order word specifies whether the window is being activated or deactivated. bool wasFocused = Focused; Focused = (wParam.ToInt64() & 0xFFFF) != 0; if (Focused != wasFocused) { RaiseFocusedChanged(); } break; case WindowMessage.ENTERMENULOOP: case WindowMessage.ENTERSIZEMOVE: case WindowMessage.EXITMENULOOP: case WindowMessage.EXITSIZEMOVE: break; case WindowMessage.ERASEBKGND: RaiseRedraw(); return(new IntPtr(1)); case WindowMessage.WINDOWPOSCHANGED: WindowPosition *pos = (WindowPosition *)lParam; if (pos->hwnd == WinHandle) { Point new_location = new Point(pos->x, pos->y); if (Location != new_location) { bounds.Location = new_location; RaiseMove(); } Size new_size = new Size(pos->cx, pos->cy); if (Size != new_size) { bounds.Width = pos->cx; bounds.Height = pos->cy; UpdateClientSize(handle); API.SetWindowPos(WinHandle, IntPtr.Zero, bounds.X, bounds.Y, bounds.Width, bounds.Height, SetWindowPosFlags.NOZORDER | SetWindowPosFlags.NOOWNERZORDER | SetWindowPosFlags.NOACTIVATE | SetWindowPosFlags.NOSENDCHANGING); if (suppress_resize <= 0) { RaiseResize(); } } } break; case WindowMessage.STYLECHANGED: if (wParam.ToInt64() == (long)GetWindowLong.STYLE) { WindowStyle style = ((StyleStruct *)lParam)->New; if ((style & WindowStyle.Popup) != 0) { hiddenBorder = true; } else if ((style & WindowStyle.ThickFrame) != 0) { hiddenBorder = false; } } break; case WindowMessage.SIZE: SizeMessage state = (SizeMessage)wParam.ToInt64(); WindowState new_state = windowState; switch (state) { case SizeMessage.RESTORED: new_state = WindowState.Normal; break; case SizeMessage.MINIMIZED: new_state = WindowState.Minimized; break; case SizeMessage.MAXIMIZED: new_state = hiddenBorder ? WindowState.Fullscreen : WindowState.Maximized; break; } if (new_state != windowState) { windowState = new_state; RaiseWindowStateChanged(); } break; #endregion #region Input events case WindowMessage.CHAR: RaiseKeyPress((char)wParam.ToInt64()); break; case WindowMessage.MOUSEMOVE: // set before position change, in case mouse buttons changed when outside window uint mouse_flags = (uint)wParam.ToInt64(); Mouse.Set(MouseButton.Left, (mouse_flags & 0x01) != 0); Mouse.Set(MouseButton.Right, (mouse_flags & 0x02) != 0); Mouse.Set(MouseButton.Middle, (mouse_flags & 0x10) != 0); // TODO: do we need to set XBUTTON1 / XBUTTON 2 here uint mouse_xy = (uint)lParam.ToInt32(); Mouse.SetPos((short)(mouse_xy & 0x0000FFFF), (short)((mouse_xy & 0xFFFF0000) >> 16)); break; case WindowMessage.MOUSEWHEEL: // This is due to inconsistent behavior of the WParam value on 64bit arch, whese // wparam = 0xffffffffff880000 or wparam = 0x00000000ff100000 Mouse.SetWheel(Mouse.Wheel + (((long)wParam << 32 >> 48) / 120.0f)); return(IntPtr.Zero); case WindowMessage.LBUTTONDOWN: Mouse.Set(MouseButton.Left, true); break; case WindowMessage.MBUTTONDOWN: Mouse.Set(MouseButton.Middle, true); break; case WindowMessage.RBUTTONDOWN: Mouse.Set(MouseButton.Right, true); break; case WindowMessage.XBUTTONDOWN: Keyboard.Set((((ulong)wParam.ToInt64() >> 16) & 0xFFFF) == 1 ? Key.XButton1 : Key.XButton2, true); break; case WindowMessage.LBUTTONUP: Mouse.Set(MouseButton.Left, false); break; case WindowMessage.MBUTTONUP: Mouse.Set(MouseButton.Middle, false); break; case WindowMessage.RBUTTONUP: Mouse.Set(MouseButton.Right, false); break; case WindowMessage.XBUTTONUP: Keyboard.Set((((ulong)wParam.ToInt64() >> 16) & 0xFFFF) == 1 ? Key.XButton1 : Key.XButton2, false); break; // Keyboard events: case WindowMessage.KEYDOWN: case WindowMessage.KEYUP: case WindowMessage.SYSKEYDOWN: case WindowMessage.SYSKEYUP: bool pressed = message == WindowMessage.KEYDOWN || message == WindowMessage.SYSKEYDOWN; // Shift/Control/Alt behave strangely when e.g. ShiftRight is held down and ShiftLeft is pressed // and released. It looks like neither key is released in this case, or that the wrong key is // released in the case of Control and Alt. // To combat this, we are going to release both keys when either is released. Hacky, but should work. // Win95 does not distinguish left/right key constants (GetAsyncKeyState returns 0). // In this case, both keys will be reported as pressed. bool extended = (lParam.ToInt64() & ExtendedBit) != 0; switch ((int)wParam) { case VirtualKeys.SHIFT: // The behavior of this key is very strange. Unlike Control and Alt, there is no extended bit // to distinguish between left and right keys. Moreover, pressing both keys and releasing one // may result in both keys being held down (but not always). bool lShiftDown = (API.GetKeyState((int)VirtualKeys.LSHIFT) >> 15) == 1; bool rShiftDown = (API.GetKeyState((int)VirtualKeys.RSHIFT) >> 15) == 1; if (!pressed || lShiftDown != rShiftDown) { Keyboard.Set(Key.ShiftLeft, lShiftDown); Keyboard.Set(Key.ShiftRight, rShiftDown); } return(IntPtr.Zero); case VirtualKeys.CONTROL: if (extended) { Keyboard.Set(Key.ControlRight, pressed); } else { Keyboard.Set(Key.ControlLeft, pressed); } return(IntPtr.Zero); case VirtualKeys.MENU: if (extended) { Keyboard.Set(Key.AltRight, pressed); } else { Keyboard.Set(Key.AltLeft, pressed); } return(IntPtr.Zero); case VirtualKeys.RETURN: if (extended) { Keyboard.Set(Key.KeypadEnter, pressed); } else { Keyboard.Set(Key.Enter, pressed); } return(IntPtr.Zero); default: Key tkKey; if (!KeyMap.TryGetValue((int)wParam, out tkKey)) { Debug.Print("Virtual key {0} ({1}) not mapped.", wParam, lParam.ToInt64()); break; } else { Keyboard.Set(tkKey, pressed); } return(IntPtr.Zero); } break; case WindowMessage.SYSCHAR: return(IntPtr.Zero); case WindowMessage.KILLFOCUS: Keyboard.ClearKeys(); break; #endregion #region Creation / Destruction events case WindowMessage.CREATE: CreateStruct cs = (CreateStruct)Marshal.PtrToStructure(lParam, typeof(CreateStruct)); if (cs.hwndParent == IntPtr.Zero) { bounds.X = cs.x; bounds.Y = cs.y; bounds.Width = cs.cx; bounds.Height = cs.cy; UpdateClientSize(handle); invisible_since_creation = true; } break; case WindowMessage.CLOSE: RaiseClosing(); DestroyWindow(); break; case WindowMessage.DESTROY: Exists = false; API.UnregisterClass(ClassName, Instance); Dispose(); RaiseClosed(); break; #endregion } return(API.DefWindowProc(handle, message, wParam, lParam)); }
public bool ProcessKeyboardEvent(RawInput rin) { bool processed = false; bool pressed = rin.Data.Keyboard.Message == (int)WindowMessage.KEYDOWN || rin.Data.Keyboard.Message == (int)WindowMessage.SYSKEYDOWN; ContextHandle handle = new ContextHandle(rin.Header.Device); KeyboardState keyboard; if (!rawids.ContainsKey(handle)) { RefreshDevices(); } if (keyboards.Count == 0) { return(false); } // Note:For some reason, my Microsoft Digital 3000 keyboard reports 0 // as rin.Header.Device for the "zoom-in/zoom-out" buttons. // That's problematic, because no device has a "0" id. // As a workaround, we'll add those buttons to the first device (if any). int keyboard_handle = rawids.ContainsKey(handle) ? rawids[handle] : 0; keyboard = keyboards[keyboard_handle]; // Generic control, shift, alt keys may be sent instead of left/right. // It seems you have to explicitly register left/right events. switch (rin.Data.Keyboard.VKey) { case VirtualKeys.SHIFT: keyboard.SetKeyState(Key.ShiftLeft, (byte)WinGLNative.ShiftLeftScanCode, pressed); keyboard.SetKeyState(Key.ShiftRight, (byte)WinGLNative.ShiftRightScanCode, pressed); processed = true; break; case VirtualKeys.CONTROL: keyboard.SetKeyState(Key.ControlLeft, (byte)WinGLNative.ControlLeftScanCode, pressed); keyboard.SetKeyState(Key.ControlRight, (byte)WinGLNative.ControlRightScanCode, pressed); processed = true; break; case VirtualKeys.MENU: keyboard.SetKeyState(Key.AltLeft, (byte)WinGLNative.AltLeftScanCode, pressed); keyboard.SetKeyState(Key.AltRight, (byte)WinGLNative.AltRightScanCode, pressed); processed = true; break; default: Key key; KeyMap.TryGetValue(rin.Data.Keyboard.VKey, out key); if (key == Key.Unknown) { Debug.Print("Virtual key {0} ({1}) not mapped.", rin.Data.Keyboard.VKey, (int)rin.Data.Keyboard.VKey); } keyboard.SetKeyState(key, BitConverter.GetBytes(rin.Data.Keyboard.MakeCode)[0], pressed); processed = true; break; } lock (UpdateLock) { keyboards[keyboard_handle] = keyboard; return(processed); } }