func virtualKeyCodeToSF(vkey C.WPARAM, flags C.LPARAM) Key { if key, ok := keyboard_vkeys_map[C.int(vkey)]; ok { return key } switch vkey { // Check the scancode to distinguish between left and right shift case C.VK_SHIFT: scancode := C.UINT((flags & (0xFF << 16)) >> 16) if scancode == lShift { return KeyLShift } return KeyRShift // Check the "extended" flag to distinguish between left and right alt case C.VK_MENU: if C.__HIWORD(C.DWORD(flags))&C.KF_EXTENDED != 0 { return KeyRAlt } return KeyLAlt // Check the "extended" flag to distinguish between left and right control case C.VK_CONTROL: if C.__HIWORD(C.DWORD(flags))&C.KF_EXTENDED != 0 { return KeyRControl } return KeyLControl } return KeyUnknown }
func (wi *windowInternal) processEvent(message C.UINT, wParam C.WPARAM, lParam C.LPARAM) (events []Event, eventErrors []ThreadError) { // Don't process any message until window is created if wi.window.Handle == nil { return } switch message { case C.WM_DESTROY: // Destroy event // Here we must cleanup resources ! wi.cleanup() case C.WM_ACTIVATE: // TODO fullscreen handling if wi.monitor == nil || !wi.monitor.IsValid() { break } // Were we deactivated/iconified? wi.inactive = C.__LOWORD(C.DWORD(wParam)) == C.WA_INACTIVE minimized := C.__HIWORD(C.DWORD(wParam)) != 0 if (wi.inactive || minimized) && !wi.minimized { // _glfwInputDeactivation(); // If we are in fullscreen mode we need to iconify if wi.monitor != nil && wi.monitor.IsValid() { // Do we need to manually iconify? if err := ChangeDisplaySettingsExW(&wi.monitor.internal.info.szDevice[0], nil, nil, 0, nil); err != nil { // TODO: Error handling panic(err) } if !minimized { // Minimize window // C.SetWindowULong(wi.window.Handle, C.GWL_STYLE, C.WS_POPUP) // C.SetWindowLong(wi.window.Handle, C.GWL_EXSTYLE, 0) // C.SetWindowPos(wi.window.Handle, HWND_BOTTOM, 1, 1, 10, 10, C.SWP_HIDEWINDOW) C.ShowWindow(wi.window.Handle, C.SW_MINIMIZE) minimized = true } // Restore the original desktop resolution if err := ChangeDisplaySettingsExW(&wi.monitor.internal.info.szDevice[0], nil, nil, 0, nil); err != nil { // TODO: Error handling panic(err) } } // Unlock mouse if locked // if !_glfwWin.oldMouseLockValid { // _glfwWin.oldMouseLock = _glfwWin.mouseLock; // _glfwWin.oldMouseLockValid = GL_TRUE; // glfwEnable( GLFW_MOUSE_CURSOR ); // } } else if !wi.inactive || !minimized { // If we are in fullscreen mode we need to maximize if wi.monitor != nil && wi.monitor.IsValid() && wi.minimized { // Change display settings to the user selected mode if err := ChangeDisplaySettingsExW(&wi.monitor.internal.info.szDevice[0], wi.devMode, nil, C.CDS_FULLSCREEN, nil); err != nil { // TODO error handling panic(err) } // Do we need to manually restore window? if minimized { // Restore window C.ShowWindow(wi.window.Handle, C.SW_RESTORE) minimized = false // Activate window C.ShowWindow(wi.window.Handle, C.SW_SHOW) // setForegroundWindow( _glfwWin.window ); C.SetFocus(wi.window.Handle) } // Lock mouse, if necessary // if _glfwWin.oldMouseLockValid && _glfwWin.oldMouseLock { // glfwDisable( GLFW_MOUSE_CURSOR ); // } // _glfwWin.oldMouseLockValid = GL_FALSE; } } wi.minimized = minimized case C.WM_SETCURSOR: // Set cursor event // The mouse has moved, if the cursor is in our window we must refresh the cursor if C.__LOWORD(C.DWORD(lParam)) == C.HTCLIENT { C.SetCursor(wi.cursor) } case C.WM_CLOSE: // Close event events = append(events, WindowClosedEvent{}) case C.WM_SIZE: // Resize event // Consider only events triggered by a maximize or a un-maximize if wParam == C.SIZE_MINIMIZED || wi.resizing { break } // Ignore cases where the window has only been moved if x, y := wi.getSize(); wi.lastSizeX == x && wi.lastSizeY == y { break } events = append(events, WindowResizeEvent{ Width: wi.lastSizeX, Height: wi.lastSizeY, }) case C.WM_ENTERSIZEMOVE: // Start resizing wi.resizing = true case C.WM_EXITSIZEMOVE: // Stop resizing wi.resizing = false // Ignore cases where the window has only been moved if x, y := wi.getSize(); wi.lastSizeX == x && wi.lastSizeY == y { break } else { wi.lastSizeX, wi.lastSizeY = x, y } events = append(events, WindowResizeEvent{ Width: wi.lastSizeX, Height: wi.lastSizeY, }) case C.WM_KILLFOCUS: // Lost focus event events = append(events, WindowGainedFocusEvent{}) case C.WM_SETFOCUS: // Gain focus event events = append(events, WindowLostFocusEvent{}) case C.WM_CHAR: // Text event if !wi.keyRepeatEnabled && lParam&(1<<30) != 0 { break } events = append(events, TextEnteredEvent{ Character: rune(wParam), }) case C.WM_KEYDOWN, C.WM_SYSKEYDOWN: // Keydown event if !wi.keyRepeatEnabled && C.__HIWORD(C.DWORD(lParam))&C.KF_REPEAT != 0 { break } events = append(events, KeyPressedEvent{ Code: virtualKeyCodeToSF(wParam, lParam), Alt: C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_MENU))) != 0, Control: C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_CONTROL))) != 0, Shift: C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_SHIFT))) != 0, System: C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_LWIN))) != 0 || C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_RWIN))) != 0, }) case C.WM_KEYUP, C.WM_SYSKEYUP: // Keyup event events = append(events, KeyReleasedEvent{ Code: virtualKeyCodeToSF(wParam, lParam), Alt: C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_MENU))) != 0, Control: C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_CONTROL))) != 0, Shift: C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_SHIFT))) != 0, System: C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_LWIN))) != 0 || C.__HIWORD(C.DWORD(C.GetAsyncKeyState(C.VK_RWIN))) != 0, }) case C.WM_MOUSEWHEEL: // Mouse wheel event // Mouse position is in screen coordinates, convert it to window coordinates position := C.POINT{ x: C.LONG(C.__LOWORD(C.DWORD(lParam))), y: C.LONG(C.__HIWORD(C.DWORD(lParam))), } C.__ScreenToClient(wi.window.Handle, &position) events = append(events, MouseWheelEvent{ Delta: int(int16(C.__HIWORD(C.DWORD(wParam))) / 120), X: int(position.x), Y: int(position.y), }) case C.WM_LBUTTONDOWN, C.WM_RBUTTONDOWN: // Mouse left/right button down event button := mouse_vkeys_handed_map[mouseKey{message, C.GetSystemMetrics(C.SM_SWAPBUTTON) == C.TRUE}] events = append(events, MouseButtonPressedEvent{ Button: button, X: int(C.__LOWORD(C.DWORD(lParam))), Y: int(C.__HIWORD(C.DWORD(lParam))), }) case C.WM_LBUTTONUP, C.WM_RBUTTONUP: // Mouse left/right button up event button := mouse_vkeys_handed_map[mouseKey{message, C.GetSystemMetrics(C.SM_SWAPBUTTON) == C.TRUE}] events = append(events, MouseButtonReleasedEvent{ Button: button, X: int(C.__LOWORD(C.DWORD(lParam))), Y: int(C.__HIWORD(C.DWORD(lParam))), }) case C.WM_MBUTTONDOWN: // Mouse wheel button down event events = append(events, MouseButtonPressedEvent{ Button: MouseMiddle, X: int(C.__LOWORD(C.DWORD(lParam))), Y: int(C.__HIWORD(C.DWORD(lParam))), }) case C.WM_MBUTTONUP: // Mouse wheel button up event events = append(events, MouseButtonReleasedEvent{ Button: MouseMiddle, X: int(C.__LOWORD(C.DWORD(lParam))), Y: int(C.__HIWORD(C.DWORD(lParam))), }) case C.WM_XBUTTONDOWN: // Mouse X button down event event := MouseButtonPressedEvent{ X: int(C.__LOWORD(C.DWORD(lParam))), Y: int(C.__HIWORD(C.DWORD(lParam))), } switch C.__HIWORD(C.DWORD(wParam)) { default: fallthrough case C.XBUTTON1: event.Button = MouseXButton1 case C.XBUTTON2: event.Button = MouseXButton2 } events = append(events, event) case C.WM_XBUTTONUP: // Mouse X button up event event := MouseButtonPressedEvent{ X: int(C.__LOWORD(C.DWORD(lParam))), Y: int(C.__HIWORD(C.DWORD(lParam))), } switch C.__HIWORD(C.DWORD(wParam)) { default: fallthrough case C.XBUTTON1: event.Button = MouseXButton1 case C.XBUTTON2: event.Button = MouseXButton2 } events = append(events, event) case C.WM_MOUSEMOVE: // Mouse move event // Check if we need to generate a MouseEntered event if !wi.isCursorIn { mouseEvent := C.TRACKMOUSEEVENT{ cbSize: C.TRACKMOUSEEVENT_size, hwndTrack: wi.window.Handle, dwFlags: C.TME_LEAVE, } C.__TrackMouseEvent(&mouseEvent) wi.isCursorIn = true events = append(events, MouseEnteredEvent{}) } events = append(events, MouseMoveEvent{ X: int(C.__LOWORD(C.DWORD(lParam))), Y: int(C.__HIWORD(C.DWORD(lParam))), }) case C.WM_MOUSELEAVE: // Mouse leave event wi.isCursorIn = false events = append(events, MouseLeftEvent{}) } return }