diff --git a/app/internal/windows/windows.go b/app/internal/windows/windows.go index 3fd2805d..30023052 100644 --- a/app/internal/windows/windows.go +++ b/app/internal/windows/windows.go @@ -384,9 +384,13 @@ const ( WM_NCACTIVATE = 0x0086 WM_NCHITTEST = 0x0084 WM_NCCALCSIZE = 0x0083 + WM_NCPOINTERUPDATE = 0x0241 + WM_NCPOINTERDOWN = 0x0242 + WM_NCPOINTERUP = 0x0243 WM_PAINT = 0x000F WM_POINTERCAPTURECHANGED = 0x024C WM_POINTERDOWN = 0x0246 + WM_POINTERLEAVE = 0x024A WM_POINTERUP = 0x0247 WM_POINTERUPDATE = 0x0245 WM_POINTERWHEEL = 0x024E diff --git a/app/os_windows.go b/app/os_windows.go index db684400..7daa449b 100644 --- a/app/os_windows.go +++ b/app/os_windows.go @@ -313,26 +313,16 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr return 0 } } - case windows.WM_POINTERDOWN, windows.WM_POINTERUP, windows.WM_POINTERUPDATE, windows.WM_POINTERCAPTURECHANGED: + case windows.WM_POINTERDOWN, windows.WM_POINTERUP, windows.WM_POINTERUPDATE, + windows.WM_POINTERLEAVE, windows.WM_POINTERCAPTURECHANGED, + windows.WM_NCPOINTERUPDATE, windows.WM_NCPOINTERDOWN, windows.WM_NCPOINTERUP: pid := getPointerIDwParam(wParam) pi, err := windows.GetPointerInfo(uint32(pid)) if err != nil { panic(err) } - kind := pointer.Move - switch pi.ButtonChangeType { - case windows.POINTER_CHANGE_FIRSTBUTTON_DOWN, windows.POINTER_CHANGE_SECONDBUTTON_DOWN, windows.POINTER_CHANGE_THIRDBUTTON_DOWN, windows.POINTER_CHANGE_FOURTHBUTTON_DOWN, windows.POINTER_CHANGE_FIFTHBUTTON_DOWN: - kind = pointer.Press - case windows.POINTER_CHANGE_FIRSTBUTTON_UP, windows.POINTER_CHANGE_SECONDBUTTON_UP, windows.POINTER_CHANGE_THIRDBUTTON_UP, windows.POINTER_CHANGE_FOURTHBUTTON_UP, windows.POINTER_CHANGE_FIFTHBUTTON_UP: - kind = pointer.Release - } - - if (pi.PointerFlags&windows.POINTER_FLAG_CANCELED != 0) || (msg == windows.WM_POINTERCAPTURECHANGED) { - kind = pointer.Cancel - } - - w.pointerUpdate(pi, pid, kind, lParam) + w.pointerUpdate(pi, pid, pointerKind(msg, pi), lParam) case windows.WM_CANCELMODE: w.ProcessEvent(pointer.Event{ Kind: pointer.Cancel, @@ -648,8 +638,31 @@ func (w *window) hitTest(x, y int) uintptr { return windows.HTCLIENT } +func pointerKind(msg uint32, pi windows.PointerInfo) pointer.Kind { + if pi.PointerFlags&windows.POINTER_FLAG_CANCELED != 0 || msg == windows.WM_POINTERCAPTURECHANGED { + return pointer.Cancel + } + switch msg { + case windows.WM_POINTERLEAVE, windows.WM_NCPOINTERUPDATE, windows.WM_NCPOINTERDOWN, windows.WM_NCPOINTERUP: + // Treat non-client input as leaving the client area. + return pointer.Leave + } + switch pi.ButtonChangeType { + case windows.POINTER_CHANGE_FIRSTBUTTON_DOWN, windows.POINTER_CHANGE_SECONDBUTTON_DOWN, + windows.POINTER_CHANGE_THIRDBUTTON_DOWN, windows.POINTER_CHANGE_FOURTHBUTTON_DOWN, + windows.POINTER_CHANGE_FIFTHBUTTON_DOWN: + return pointer.Press + case windows.POINTER_CHANGE_FIRSTBUTTON_UP, windows.POINTER_CHANGE_SECONDBUTTON_UP, + windows.POINTER_CHANGE_THIRDBUTTON_UP, windows.POINTER_CHANGE_FOURTHBUTTON_UP, + windows.POINTER_CHANGE_FIFTHBUTTON_UP: + return pointer.Release + default: + return pointer.Move + } +} + func (w *window) pointerUpdate(pi windows.PointerInfo, pid pointer.ID, kind pointer.Kind, lParam uintptr) { - if !w.config.Focused { + if !w.config.Focused && kind != pointer.Leave { windows.SetFocus(w.hwnd) } diff --git a/app/os_x11.go b/app/os_x11.go index 94102449..13f8262b 100644 --- a/app/os_x11.go +++ b/app/os_x11.go @@ -708,6 +708,11 @@ func (h *x11EventHandler) handleEvents() bool { default: continue } + if ev.Kind == pointer.Scroll && _type == C.ButtonRelease { + // The X server sends a press and a release for every wheel + // notch; only the press scrolls, or each notch counts twice. + continue + } switch _type { case C.ButtonPress: w.pointerBtns |= btn @@ -734,6 +739,11 @@ func (h *x11EventHandler) handleEvents() bool { Time: time.Duration(mevt.time) * time.Millisecond, Modifiers: w.xkb.Modifiers(), }) + case C.LeaveNotify: + cevt := (*C.XCrossingEvent)(unsafe.Pointer(xev)) + if w.pointerBtns == 0 && cevt.detail != C.NotifyInferior { + w.ProcessEvent(pointer.Event{Kind: pointer.Cancel}) + } case C.Expose: // update // redraw only on the last expose event redraw = (*C.XExposeEvent)(unsafe.Pointer(xev)).count == 0 @@ -917,6 +927,7 @@ func newX11Window(gioWin *callbacks, options []Option) error { C.KeyPressMask | C.KeyReleaseMask | // keyboard C.ButtonPressMask | C.ButtonReleaseMask | // mouse clicks C.PointerMotionMask | // mouse movement + C.LeaveWindowMask | // pointer leaving the window C.StructureNotifyMask, // resize background_pixmap: C.None, override_redirect: C.False,