From 582e3b4644c25c273e790bc646fd5a28c3a9a85c Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Fri, 23 May 2014 17:01:56 -0400 Subject: [PATCH] Implemented triple-clicks and up on Windows. --- area_windows.go | 63 ++++++++++++++++++++++++--------------------- events_notdarwin.go | 2 +- sysdata_windows.go | 1 + 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/area_windows.go b/area_windows.go index b0f8e74..4270046 100644 --- a/area_windows.go +++ b/area_windows.go @@ -459,7 +459,18 @@ func getModifiers() (m Modifiers) { return m } -func areaMouseEvent(s *sysData, button uint, up bool, count uint, wparam _WPARAM, lparam _LPARAM) { +const ( + _SM_CXDOUBLECLK = 36 + _SM_CYDOUBLECLK = 37 +) + +var ( + _getMessageTime = user32.NewProc("GetMessageTime") + _getDoubleClickTime = user32.NewProc("GetDoubleClickTime") + _getSystemMetrics = user32.NewProc("GetSystemMetrics") +) + +func areaMouseEvent(s *sysData, button uint, up bool, wparam _WPARAM, lparam _LPARAM) { var me MouseEvent xpos, ypos := getScrollPos(s.hwnd) // mouse coordinates are relative to control; make them relative to Area @@ -471,9 +482,19 @@ func areaMouseEvent(s *sysData, button uint, up bool, count uint, wparam _WPARAM } if up { me.Up = button - } else { + } else if button != 0 { // don't run the click counter if the mouse was only moved me.Down = button - me.Count = count + // 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) + // TODO actually will this break with negative numbers on systems where uintptr is 64 bits wide? only if the ABI doesn't sign-extend... + time, _, _ := _getMessageTime.Call() + // this returns a UINT, which is uint32; don't worry about the smaller size as sign extension won't matter here (see the above) + maxTime, _, _ := _getDoubleClickTime.Call() + // ignore zero returns and errors; MSDN says zero will be returned on error but that GetLastError() is meaningless + // these should be unsigned... TODO MSDN doesn't say and GetSystemMetrics() returns an int (int32) + xdist, _, _ := _getSystemMetrics.Call(_SM_CXDOUBLECLK) + ydist, _, _ := _getSystemMetrics.Call(_SM_CYDOUBLECLK) + me.Count = s.clickCounter.click(button, me.Pos.X, me.Pos.Y, + time, 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() @@ -633,46 +654,33 @@ func areaWndProc(s *sysData) func(hwnd _HWND, uMsg uint32, wParam _WPARAM, lPara } return defwndproc() case _WM_MOUSEMOVE: - areaMouseEvent(s, 0, false, 0, wParam, lParam) + areaMouseEvent(s, 0, false, wParam, lParam) return 0 case _WM_LBUTTONDOWN: - areaMouseEvent(s, 1, false, 1, wParam, lParam) - return 0 - case _WM_LBUTTONDBLCLK: - areaMouseEvent(s, 1, false, 2, wParam, lParam) + areaMouseEvent(s, 1, false, wParam, lParam) return 0 case _WM_LBUTTONUP: - areaMouseEvent(s, 1, true, 0, wParam, lParam) + areaMouseEvent(s, 1, true, wParam, lParam) return 0 case _WM_MBUTTONDOWN: - areaMouseEvent(s, 2, false, 1, wParam, lParam) - return 0 - case _WM_MBUTTONDBLCLK: - areaMouseEvent(s, 2, false, 2, wParam, lParam) + areaMouseEvent(s, 2, false, wParam, lParam) return 0 case _WM_MBUTTONUP: - areaMouseEvent(s, 2, true, 0, wParam, lParam) + areaMouseEvent(s, 2, true, wParam, lParam) return 0 case _WM_RBUTTONDOWN: - areaMouseEvent(s, 3, false, 1, wParam, lParam) - return 0 - case _WM_RBUTTONDBLCLK: - areaMouseEvent(s, 3, false, 2, wParam, lParam) + areaMouseEvent(s, 3, false, wParam, lParam) return 0 case _WM_RBUTTONUP: - areaMouseEvent(s, 3, true, 0, wParam, lParam) + areaMouseEvent(s, 3, true, wParam, lParam) return 0 case _WM_XBUTTONDOWN: which := uint((wParam >> 16) & 0xFFFF) + 3 // values start at 1; we want them to start at 4 - areaMouseEvent(s, which, false, 1, wParam, lParam) + areaMouseEvent(s, which, false, wParam, lParam) return _LRESULT(_TRUE) // XBUTTON messages are different! - case _WM_XBUTTONDBLCLK: - which := uint((wParam >> 16) & 0xFFFF) + 3 - areaMouseEvent(s, which, false, 2, wParam, lParam) - return _LRESULT(_TRUE) case _WM_XBUTTONUP: which := uint((wParam >> 16) & 0xFFFF) + 3 - areaMouseEvent(s, which, true, 0, wParam, lParam) + areaMouseEvent(s, which, true, wParam, lParam) return _LRESULT(_TRUE) case _WM_KEYDOWN: areaKeyEvent(s, false, wParam, lParam) @@ -710,9 +718,6 @@ func registerAreaWndClass(s *sysData) (newClassName string, err error) { const ( _CS_HREDRAW = 0x0002 _CS_VREDRAW = 0x0001 - - // from winuser.h - _CS_DBLCLKS = 0x0008 // needed to be able to register double-clicks ) areaWndClassNumLock.Lock() @@ -721,7 +726,7 @@ func registerAreaWndClass(s *sysData) (newClassName string, err error) { areaWndClassNumLock.Unlock() wc := &_WNDCLASS{ - style: _CS_DBLCLKS | _CS_HREDRAW | _CS_VREDRAW, + style: _CS_HREDRAW | _CS_VREDRAW, // no CS_DBLCLKS because do that manually lpszClassName: uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(newClassName))), lpfnWndProc: syscall.NewCallback(areaWndProc(s)), hInstance: hInstance, diff --git a/events_notdarwin.go b/events_notdarwin.go index a96b835..7ccfcda 100644 --- a/events_notdarwin.go +++ b/events_notdarwin.go @@ -55,7 +55,7 @@ func (c *clickCounter) click(button uint, x int, y int, time uintptr, maxTime ui } // call this when losing focus, etc. -func (c *clickCounter reset() { +func (c *clickCounter) reset() { c.count = 0 } diff --git a/sysdata_windows.go b/sysdata_windows.go index 5bda9c0..1e02936 100644 --- a/sysdata_windows.go +++ b/sysdata_windows.go @@ -20,6 +20,7 @@ type sysData struct { // unlike with GTK+ and Mac OS X, we're responsible for sizing Area properly ourselves areawidth int areaheight int + clickCounter clickCounter } type classData struct {