shiny/driver/internal/win32: use relative coordinates for mouse wheel events

Windows mouse wheel events report the cursor position in
absolute screen coordinates, while other mouse event's positions
are relative to the window.
This adds ScreenToClient to syscall_windows.go and converts the
event's position for mouse wheel events.

Fixes golang/go#18695

Change-Id: Ic086033e435cf4699c7ff0aad90e1a1ce233bb02
Reviewed-on: https://go-review.googlesource.com/35412
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
diff --git a/shiny/driver/internal/win32/syscall_windows.go b/shiny/driver/internal/win32/syscall_windows.go
index 6c55058..53857c4 100644
--- a/shiny/driver/internal/win32/syscall_windows.go
+++ b/shiny/driver/internal/win32/syscall_windows.go
@@ -178,5 +178,6 @@
 //sys   _PostQuitMessage(exitCode int32) = user32.PostQuitMessage
 //sys	_RegisterClass(wc *_WNDCLASS) (atom uint16, err error) = user32.RegisterClassW
 //sys	_ShowWindow(hwnd syscall.Handle, cmdshow int32) (wasvisible bool) = user32.ShowWindow
+//sys	_ScreenToClient(hwnd syscall.Handle, lpPoint *_POINT) (ok bool) = user32.ScreenToClient
 //sys   _ToUnicodeEx(wVirtKey uint32, wScanCode uint32, lpKeyState *byte, pwszBuff *uint16, cchBuff int32, wFlags uint32, dwhkl syscall.Handle) (ret int32) = user32.ToUnicodeEx
 //sys	_TranslateMessage(msg *_MSG) (done bool) = user32.TranslateMessage
diff --git a/shiny/driver/internal/win32/win32.go b/shiny/driver/internal/win32/win32.go
index 6b70162..78895bd 100644
--- a/shiny/driver/internal/win32/win32.go
+++ b/shiny/driver/internal/win32/win32.go
@@ -183,6 +183,15 @@
 		// distinct beginning and end. Should the intermediate events be
 		// DirNone?
 		e.Direction = mouse.DirStep
+
+		// Convert from screen to window coordinates.
+		p := _POINT{
+			int32(e.X),
+			int32(e.Y),
+		}
+		_ScreenToClient(hwnd, &p)
+		e.X = float32(p.X)
+		e.Y = float32(p.Y)
 	default:
 		panic("sendMouseEvent() called on non-mouse message")
 	}
diff --git a/shiny/driver/internal/win32/zsyscall_windows.go b/shiny/driver/internal/win32/zsyscall_windows.go
index 3ff0582..07430ac 100644
--- a/shiny/driver/internal/win32/zsyscall_windows.go
+++ b/shiny/driver/internal/win32/zsyscall_windows.go
@@ -11,6 +11,31 @@
 
 var _ unsafe.Pointer
 
+// Do the interface allocations only once for common
+// Errno values.
+const (
+	errnoERROR_IO_PENDING = 997
+)
+
+var (
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+	switch e {
+	case 0:
+		return nil
+	case errnoERROR_IO_PENDING:
+		return errERROR_IO_PENDING
+	}
+	// TODO: add more here, after collecting data on the common
+	// error values see on Windows. (perhaps when running
+	// all.bat?)
+	return e
+}
+
 var (
 	moduser32 = windows.NewLazySystemDLL("user32.dll")
 
@@ -32,6 +57,7 @@
 	procPostQuitMessage   = moduser32.NewProc("PostQuitMessage")
 	procRegisterClassW    = moduser32.NewProc("RegisterClassW")
 	procShowWindow        = moduser32.NewProc("ShowWindow")
+	procScreenToClient    = moduser32.NewProc("ScreenToClient")
 	procToUnicodeEx       = moduser32.NewProc("ToUnicodeEx")
 	procTranslateMessage  = moduser32.NewProc("TranslateMessage")
 )
@@ -41,7 +67,7 @@
 	dc = syscall.Handle(r0)
 	if dc == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -53,7 +79,7 @@
 	r1, _, e1 := syscall.Syscall(procReleaseDC.Addr(), 2, uintptr(hwnd), uintptr(dc), 0)
 	if r1 == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -72,7 +98,7 @@
 	hwnd = syscall.Handle(r0)
 	if hwnd == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -90,7 +116,7 @@
 	r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0)
 	if r1 == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -108,7 +134,7 @@
 	r1, _, e1 := syscall.Syscall(procGetClientRect.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(rect)), 0)
 	if r1 == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -126,7 +152,7 @@
 	r1, _, e1 := syscall.Syscall(procGetKeyboardState.Addr(), 1, uintptr(unsafe.Pointer(lpKeyState)), 0, 0)
 	if r1 == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -145,7 +171,7 @@
 	ret = int32(r0)
 	if ret == -1 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -158,7 +184,7 @@
 	cursor = syscall.Handle(r0)
 	if cursor == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -171,7 +197,7 @@
 	icon = syscall.Handle(r0)
 	if icon == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -195,7 +221,7 @@
 	atom = uint16(r0)
 	if atom == 0 {
 		if e1 != 0 {
-			err = error(e1)
+			err = errnoErr(e1)
 		} else {
 			err = syscall.EINVAL
 		}
@@ -209,6 +235,12 @@
 	return
 }
 
+func _ScreenToClient(hwnd syscall.Handle, lpPoint *_POINT) (ok bool) {
+	r0, _, _ := syscall.Syscall(procScreenToClient.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(lpPoint)), 0)
+	ok = r0 != 0
+	return
+}
+
 func _ToUnicodeEx(wVirtKey uint32, wScanCode uint32, lpKeyState *byte, pwszBuff *uint16, cchBuff int32, wFlags uint32, dwhkl syscall.Handle) (ret int32) {
 	r0, _, _ := syscall.Syscall9(procToUnicodeEx.Addr(), 7, uintptr(wVirtKey), uintptr(wScanCode), uintptr(unsafe.Pointer(lpKeyState)), uintptr(unsafe.Pointer(pwszBuff)), uintptr(cchBuff), uintptr(wFlags), uintptr(dwhkl), 0, 0)
 	ret = int32(r0)