func (i *imagelist) apply(hwnd C.HWND, uMsg C.UINT) { width := C.GetSystemMetrics(C.SM_CXSMICON) height := C.GetSystemMetrics(C.SM_CYSMICON) il := C.newImageList(width, height) for index := range i.list { C.addImage(il, hwnd, i.list[index], C.int(i.width[index]), C.int(i.height[index]), width, height) } C.SendMessageW(hwnd, uMsg, 0, C.LPARAM(uintptr(unsafe.Pointer(il)))) }
//export finishAreaMouseEvent func finishAreaMouseEvent(data unsafe.Pointer, cbutton C.DWORD, up C.BOOL, heldButtons C.uintptr_t, xpos C.int, ypos C.int) { var me MouseEvent a := (*area)(data) button := uint(cbutton) me.Pos = image.Pt(int(xpos), int(ypos)) if !me.Pos.In(image.Rect(0, 0, a.width, a.height)) { // outside the actual Area; no event return } if up != C.FALSE { me.Up = button } else if button != 0 { // don't run the click counter if the mouse was only moved me.Down = button // this returns a LONG, which is int32, but we don't need to worry about the signedness because for the same bit widths and two's complement arithmetic, s1-s2 == u1-u2 if bits(s1)==bits(s2) and bits(u1)==bits(u2) (and Windows requires two's complement: http://blogs.msdn.com/b/oldnewthing/archive/2005/05/27/422551.aspx) // signedness isn't much of an issue for these calls anyway because http://stackoverflow.com/questions/24022225/what-are-the-sign-extension-rules-for-calling-windows-api-functions-stdcall-t and that we're only using unsigned values (think back to how you (didn't) handle signedness in assembly language) AND because of the above AND because the statistics below (time interval and width/height) really don't make sense if negative time := C.GetMessageTime() maxTime := C.GetDoubleClickTime() // ignore zero returns and errors; MSDN says zero will be returned on error but that GetLastError() is meaningless xdist := C.GetSystemMetrics(C.SM_CXDOUBLECLK) ydist := C.GetSystemMetrics(C.SM_CYDOUBLECLK) me.Count = a.clickCounter.click(button, me.Pos.X, me.Pos.Y, uintptr(time), uintptr(maxTime), int(xdist/2), int(ydist/2)) } // though wparam will contain control and shift state, let's use just one function to get modifiers for both keyboard and mouse events; it'll work the same anyway since we have to do this for alt and windows key (super) me.Modifiers = getModifiers() if button != 1 && (heldButtons&C.MK_LBUTTON) != 0 { me.Held = append(me.Held, 1) } if button != 2 && (heldButtons&C.MK_MBUTTON) != 0 { me.Held = append(me.Held, 2) } if button != 3 && (heldButtons&C.MK_RBUTTON) != 0 { me.Held = append(me.Held, 3) } if button != 4 && (heldButtons&C.MK_XBUTTON1) != 0 { me.Held = append(me.Held, 4) } if button != 5 && (heldButtons&C.MK_XBUTTON2) != 0 { me.Held = append(me.Held, 5) } a.handler.Mouse(me) }
func (b *button) preferredSize(d *sizing) (width, height int) { // comctl32.dll version 6 thankfully provides a method to grab this... var size C.SIZE size.cx = 0 // explicitly ask for ideal size size.cy = 0 if C.SendMessageW(b._hwnd, C.BCM_GETIDEALSIZE, 0, C.LPARAM(uintptr(unsafe.Pointer(&size)))) != C.FALSE { return int(size.cx), int(size.cy) } // that failed, fall back println("message failed; falling back") // don't worry about the error return from GetSystemMetrics(); there's no way to tell (explicitly documented as such) xmargins := 2 * int(C.GetSystemMetrics(C.SM_CXEDGE)) return xmargins + int(b._textlen), fromdlgunitsY(buttonHeight, d) }
func mouseIsLeft() bool { return C.GetSystemMetrics(C.SM_SWAPBUTTON) == C.TRUE }
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 }