mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
app: [Windows] add minimal support for devices with touch screens
The Windows Pointer API (https://learn.microsoft.com/en-us/windows/win32/api/_inputmsg/) was used to allow the detection of events when interacting with touch screens. This also opens the gates for supporting other types of input devices (e.g. pens and touchpads). Mouse events are now part of the pointer events (primary events trigger WM_POINTER<DOWN|UP>, whereas secondary ones vanilla WM_POINTERUPDATE, and cancellations WM_POINTERCAPTURECHANGED). A fourth and fifth button (usually found in modern mice) has also been added for completeness, though their integration in other OS-es shall be the objective of future patches. Signed-off-by: Marc <marc.leroy@samantree.com> Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+141
-39
@@ -108,6 +108,74 @@ type MonitorInfo struct {
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
type POINTER_INPUT_TYPE int32
|
||||
|
||||
const (
|
||||
PT_POINTER POINTER_INPUT_TYPE = 1
|
||||
PT_TOUCH POINTER_INPUT_TYPE = 2
|
||||
PT_PEN POINTER_INPUT_TYPE = 3
|
||||
PT_MOUSE POINTER_INPUT_TYPE = 4
|
||||
PT_TOUCHPAD POINTER_INPUT_TYPE = 5
|
||||
)
|
||||
|
||||
type POINTER_INFO_POINTER_FLAGS int32
|
||||
|
||||
const (
|
||||
POINTER_FLAG_NEW POINTER_INFO_POINTER_FLAGS = 0x00000001
|
||||
POINTER_FLAG_INRANGE POINTER_INFO_POINTER_FLAGS = 0x00000002
|
||||
POINTER_FLAG_INCONTACT POINTER_INFO_POINTER_FLAGS = 0x00000004
|
||||
POINTER_FLAG_FIRSTBUTTON POINTER_INFO_POINTER_FLAGS = 0x00000010
|
||||
POINTER_FLAG_SECONDBUTTON POINTER_INFO_POINTER_FLAGS = 0x00000020
|
||||
POINTER_FLAG_THIRDBUTTON POINTER_INFO_POINTER_FLAGS = 0x00000040
|
||||
POINTER_FLAG_FOURTHBUTTON POINTER_INFO_POINTER_FLAGS = 0x00000080
|
||||
POINTER_FLAG_FIFTHBUTTON POINTER_INFO_POINTER_FLAGS = 0x00000100
|
||||
POINTER_FLAG_PRIMARY POINTER_INFO_POINTER_FLAGS = 0x00002000
|
||||
POINTER_FLAG_CONFIDENCE POINTER_INFO_POINTER_FLAGS = 0x00004000
|
||||
POINTER_FLAG_CANCELED POINTER_INFO_POINTER_FLAGS = 0x00008000
|
||||
POINTER_FLAG_DOWN POINTER_INFO_POINTER_FLAGS = 0x00010000
|
||||
POINTER_FLAG_UPDATE POINTER_INFO_POINTER_FLAGS = 0x00020000
|
||||
POINTER_FLAG_UP POINTER_INFO_POINTER_FLAGS = 0x00040000
|
||||
POINTER_FLAG_WHEEL POINTER_INFO_POINTER_FLAGS = 0x00080000
|
||||
POINTER_FLAG_HWHEEL POINTER_INFO_POINTER_FLAGS = 0x00100000
|
||||
POINTER_FLAG_CAPTURECHANGED POINTER_INFO_POINTER_FLAGS = 0x00200000
|
||||
POINTER_FLAG_HASTRANSFORM POINTER_INFO_POINTER_FLAGS = 0x00400000
|
||||
)
|
||||
|
||||
type POINTER_BUTTON_CHANGE_TYPE int32
|
||||
|
||||
const (
|
||||
POINTER_CHANGE_NONE POINTER_BUTTON_CHANGE_TYPE = 0
|
||||
POINTER_CHANGE_FIRSTBUTTON_DOWN POINTER_BUTTON_CHANGE_TYPE = 1
|
||||
POINTER_CHANGE_FIRSTBUTTON_UP POINTER_BUTTON_CHANGE_TYPE = 2
|
||||
POINTER_CHANGE_SECONDBUTTON_DOWN POINTER_BUTTON_CHANGE_TYPE = 3
|
||||
POINTER_CHANGE_SECONDBUTTON_UP POINTER_BUTTON_CHANGE_TYPE = 4
|
||||
POINTER_CHANGE_THIRDBUTTON_DOWN POINTER_BUTTON_CHANGE_TYPE = 5
|
||||
POINTER_CHANGE_THIRDBUTTON_UP POINTER_BUTTON_CHANGE_TYPE = 6
|
||||
POINTER_CHANGE_FOURTHBUTTON_DOWN POINTER_BUTTON_CHANGE_TYPE = 7
|
||||
POINTER_CHANGE_FOURTHBUTTON_UP POINTER_BUTTON_CHANGE_TYPE = 8
|
||||
POINTER_CHANGE_FIFTHBUTTON_DOWN POINTER_BUTTON_CHANGE_TYPE = 9
|
||||
POINTER_CHANGE_FIFTHBUTTON_UP POINTER_BUTTON_CHANGE_TYPE = 10
|
||||
)
|
||||
|
||||
type PointerInfo struct {
|
||||
PointerType POINTER_INPUT_TYPE
|
||||
PointerId uint32
|
||||
FrameId uint32
|
||||
PointerFlags POINTER_INFO_POINTER_FLAGS
|
||||
SourceDevice syscall.Handle
|
||||
HwndTarget syscall.Handle
|
||||
PtPixelLocation Point
|
||||
PtHimetricLocation Point
|
||||
PtPixelLocationRaw Point
|
||||
PtHimetricLocationRaw Point
|
||||
DwTime uint32
|
||||
HistoryCount uint32
|
||||
InputData int32
|
||||
DwKeyStates uint32
|
||||
PerformanceCount uint64
|
||||
ButtonChangeType POINTER_BUTTON_CHANGE_TYPE
|
||||
}
|
||||
|
||||
const (
|
||||
TRUE = 1
|
||||
|
||||
@@ -244,45 +312,51 @@ const (
|
||||
|
||||
UNICODE_NOCHAR = 65535
|
||||
|
||||
WM_CANCELMODE = 0x001F
|
||||
WM_CHAR = 0x0102
|
||||
WM_CLOSE = 0x0010
|
||||
WM_CREATE = 0x0001
|
||||
WM_DPICHANGED = 0x02E0
|
||||
WM_DESTROY = 0x0002
|
||||
WM_ERASEBKGND = 0x0014
|
||||
WM_GETMINMAXINFO = 0x0024
|
||||
WM_IME_COMPOSITION = 0x010F
|
||||
WM_IME_ENDCOMPOSITION = 0x010E
|
||||
WM_IME_STARTCOMPOSITION = 0x010D
|
||||
WM_KEYDOWN = 0x0100
|
||||
WM_KEYUP = 0x0101
|
||||
WM_KILLFOCUS = 0x0008
|
||||
WM_LBUTTONDOWN = 0x0201
|
||||
WM_LBUTTONUP = 0x0202
|
||||
WM_MBUTTONDOWN = 0x0207
|
||||
WM_MBUTTONUP = 0x0208
|
||||
WM_MOUSEMOVE = 0x0200
|
||||
WM_MOUSEWHEEL = 0x020A
|
||||
WM_MOUSEHWHEEL = 0x020E
|
||||
WM_NCACTIVATE = 0x0086
|
||||
WM_NCHITTEST = 0x0084
|
||||
WM_NCCALCSIZE = 0x0083
|
||||
WM_PAINT = 0x000F
|
||||
WM_QUIT = 0x0012
|
||||
WM_SETCURSOR = 0x0020
|
||||
WM_SETFOCUS = 0x0007
|
||||
WM_SHOWWINDOW = 0x0018
|
||||
WM_SIZE = 0x0005
|
||||
WM_STYLECHANGED = 0x007D
|
||||
WM_SYSKEYDOWN = 0x0104
|
||||
WM_SYSKEYUP = 0x0105
|
||||
WM_RBUTTONDOWN = 0x0204
|
||||
WM_RBUTTONUP = 0x0205
|
||||
WM_TIMER = 0x0113
|
||||
WM_UNICHAR = 0x0109
|
||||
WM_USER = 0x0400
|
||||
WM_WINDOWPOSCHANGED = 0x0047
|
||||
WM_CANCELMODE = 0x001F
|
||||
WM_CHAR = 0x0102
|
||||
WM_CLOSE = 0x0010
|
||||
WM_CREATE = 0x0001
|
||||
WM_DPICHANGED = 0x02E0
|
||||
WM_DESTROY = 0x0002
|
||||
WM_ERASEBKGND = 0x0014
|
||||
WM_GETMINMAXINFO = 0x0024
|
||||
WM_IME_COMPOSITION = 0x010F
|
||||
WM_IME_ENDCOMPOSITION = 0x010E
|
||||
WM_IME_STARTCOMPOSITION = 0x010D
|
||||
WM_KEYDOWN = 0x0100
|
||||
WM_KEYUP = 0x0101
|
||||
WM_KILLFOCUS = 0x0008
|
||||
WM_LBUTTONDOWN = 0x0201
|
||||
WM_LBUTTONUP = 0x0202
|
||||
WM_MBUTTONDOWN = 0x0207
|
||||
WM_MBUTTONUP = 0x0208
|
||||
WM_MOUSEMOVE = 0x0200
|
||||
WM_MOUSEWHEEL = 0x020A
|
||||
WM_MOUSEHWHEEL = 0x020E
|
||||
WM_NCACTIVATE = 0x0086
|
||||
WM_NCHITTEST = 0x0084
|
||||
WM_NCCALCSIZE = 0x0083
|
||||
WM_PAINT = 0x000F
|
||||
WM_POINTERCAPTURECHANGED = 0x024C
|
||||
WM_POINTERDOWN = 0x0246
|
||||
WM_POINTERUP = 0x0247
|
||||
WM_POINTERUPDATE = 0x0245
|
||||
WM_POINTERWHEEL = 0x024E
|
||||
WM_POINTERHWHEEL = 0x024F
|
||||
WM_QUIT = 0x0012
|
||||
WM_RBUTTONDOWN = 0x0204
|
||||
WM_RBUTTONUP = 0x0205
|
||||
WM_SETCURSOR = 0x0020
|
||||
WM_SETFOCUS = 0x0007
|
||||
WM_SHOWWINDOW = 0x0018
|
||||
WM_SIZE = 0x0005
|
||||
WM_STYLECHANGED = 0x007D
|
||||
WM_SYSKEYDOWN = 0x0104
|
||||
WM_SYSKEYUP = 0x0105
|
||||
WM_TIMER = 0x0113
|
||||
WM_UNICHAR = 0x0109
|
||||
WM_USER = 0x0400
|
||||
WM_WINDOWPOSCHANGED = 0x0047
|
||||
|
||||
WS_CLIPCHILDREN = 0x02000000
|
||||
WS_CLIPSIBLINGS = 0x04000000
|
||||
@@ -346,6 +420,7 @@ var (
|
||||
_DestroyWindow = user32.NewProc("DestroyWindow")
|
||||
_DispatchMessage = user32.NewProc("DispatchMessageW")
|
||||
_EmptyClipboard = user32.NewProc("EmptyClipboard")
|
||||
_EnableMouseInPointer = user32.NewProc("EnableMouseInPointer")
|
||||
_GetWindowRect = user32.NewProc("GetWindowRect")
|
||||
_GetClientRect = user32.NewProc("GetClientRect")
|
||||
_GetClipboardData = user32.NewProc("GetClipboardData")
|
||||
@@ -355,6 +430,7 @@ var (
|
||||
_GetMessage = user32.NewProc("GetMessageW")
|
||||
_GetMessageTime = user32.NewProc("GetMessageTime")
|
||||
_GetMonitorInfo = user32.NewProc("GetMonitorInfoW")
|
||||
_GetPointerInfo = user32.NewProc("GetPointerInfo")
|
||||
_GetSystemMetrics = user32.NewProc("GetSystemMetrics")
|
||||
_GetWindowLong = user32.NewProc("GetWindowLongPtrW")
|
||||
_GetWindowLong32 = user32.NewProc("GetWindowLongW")
|
||||
@@ -372,6 +448,7 @@ var (
|
||||
_PostQuitMessage = user32.NewProc("PostQuitMessage")
|
||||
_ReleaseCapture = user32.NewProc("ReleaseCapture")
|
||||
_RegisterClassExW = user32.NewProc("RegisterClassExW")
|
||||
_RegisterTouchWindow = user32.NewProc("RegisterTouchWindow")
|
||||
_ReleaseDC = user32.NewProc("ReleaseDC")
|
||||
_ScreenToClient = user32.NewProc("ScreenToClient")
|
||||
_ShowWindow = user32.NewProc("ShowWindow")
|
||||
@@ -445,6 +522,31 @@ func CreateWindowEx(dwExStyle uint32, lpClassName uint16, lpWindowName string, d
|
||||
return syscall.Handle(hwnd), nil
|
||||
}
|
||||
|
||||
func GetPointerInfo(pointerId uint32) (PointerInfo, error) {
|
||||
var info PointerInfo
|
||||
r1, _, err := _GetPointerInfo.Call(uintptr(pointerId), uintptr(unsafe.Pointer(&info)))
|
||||
if r1 == 0 {
|
||||
return PointerInfo{}, fmt.Errorf("GetPointerInfo failed: %v", err)
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func RegisterTouchWindow(hwnd syscall.Handle, flags uint32) error {
|
||||
r1, _, err := _RegisterTouchWindow.Call(uintptr(hwnd), uintptr(flags))
|
||||
if r1 == 0 {
|
||||
return fmt.Errorf("RegisterTouchWindow failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func EnableMouseInPointer(enable uint) error {
|
||||
r1, _, err := _EnableMouseInPointer.Call(uintptr(enable))
|
||||
if r1 == 0 {
|
||||
return fmt.Errorf("EnableMouseInPointer failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func DefWindowProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr {
|
||||
r, _, _ := _DefWindowProc.Call(uintptr(hwnd), uintptr(msg), wparam, lparam)
|
||||
return r
|
||||
|
||||
+98
-48
@@ -36,10 +36,9 @@ type Win32ViewEvent struct {
|
||||
}
|
||||
|
||||
type window struct {
|
||||
hwnd syscall.Handle
|
||||
hdc syscall.Handle
|
||||
w *callbacks
|
||||
pointerBtns pointer.Buttons
|
||||
hwnd syscall.Handle
|
||||
hdc syscall.Handle
|
||||
w *callbacks
|
||||
|
||||
// cursorIn tracks whether the cursor was inside the window according
|
||||
// to the most recent WM_SETCURSOR.
|
||||
@@ -175,6 +174,12 @@ func (w *window) init() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := windows.RegisterTouchWindow(hwnd, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := windows.EnableMouseInPointer(1); err != nil {
|
||||
return err
|
||||
}
|
||||
w.hdc, err = windows.GetDC(hwnd)
|
||||
if err != nil {
|
||||
windows.DestroyWindow(hwnd)
|
||||
@@ -265,18 +270,32 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case windows.WM_LBUTTONDOWN:
|
||||
w.pointerButton(pointer.ButtonPrimary, true, lParam, getModifiers())
|
||||
case windows.WM_LBUTTONUP:
|
||||
w.pointerButton(pointer.ButtonPrimary, false, lParam, getModifiers())
|
||||
case windows.WM_RBUTTONDOWN:
|
||||
w.pointerButton(pointer.ButtonSecondary, true, lParam, getModifiers())
|
||||
case windows.WM_RBUTTONUP:
|
||||
w.pointerButton(pointer.ButtonSecondary, false, lParam, getModifiers())
|
||||
case windows.WM_MBUTTONDOWN:
|
||||
w.pointerButton(pointer.ButtonTertiary, true, lParam, getModifiers())
|
||||
case windows.WM_MBUTTONUP:
|
||||
w.pointerButton(pointer.ButtonTertiary, false, lParam, getModifiers())
|
||||
case windows.WM_POINTERDOWN, windows.WM_POINTERUP, windows.WM_POINTERUPDATE, windows.WM_POINTERCAPTURECHANGED:
|
||||
pid := getPointerIDwParam(wParam)
|
||||
pi, err := windows.GetPointerInfo(uint32(pid))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
switch msg {
|
||||
case windows.WM_POINTERDOWN:
|
||||
windows.SetCapture(w.hwnd)
|
||||
case windows.WM_POINTERUP:
|
||||
windows.ReleaseCapture()
|
||||
}
|
||||
|
||||
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)
|
||||
case windows.WM_CANCELMODE:
|
||||
w.ProcessEvent(pointer.Event{
|
||||
Kind: pointer.Cancel,
|
||||
@@ -296,20 +315,9 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
||||
np := windows.Point{X: int32(x), Y: int32(y)}
|
||||
windows.ScreenToClient(w.hwnd, &np)
|
||||
return w.hitTest(int(np.X), int(np.Y))
|
||||
case windows.WM_MOUSEMOVE:
|
||||
x, y := coordsFromlParam(lParam)
|
||||
p := f32.Point{X: float32(x), Y: float32(y)}
|
||||
w.ProcessEvent(pointer.Event{
|
||||
Kind: pointer.Move,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
Buttons: w.pointerBtns,
|
||||
Time: windows.GetMessageTime(),
|
||||
Modifiers: getModifiers(),
|
||||
})
|
||||
case windows.WM_MOUSEWHEEL:
|
||||
case windows.WM_POINTERWHEEL:
|
||||
w.scrollEvent(wParam, lParam, false, getModifiers())
|
||||
case windows.WM_MOUSEHWHEEL:
|
||||
case windows.WM_POINTERHWHEEL:
|
||||
w.scrollEvent(wParam, lParam, true, getModifiers())
|
||||
case windows.WM_DESTROY:
|
||||
w.ProcessEvent(Win32ViewEvent{})
|
||||
@@ -499,34 +507,28 @@ func (w *window) hitTest(x, y int) uintptr {
|
||||
return windows.HTCLIENT
|
||||
}
|
||||
|
||||
func (w *window) pointerButton(btn pointer.Buttons, press bool, lParam uintptr, kmods key.Modifiers) {
|
||||
func (w *window) pointerUpdate(pi windows.PointerInfo, pid pointer.ID, kind pointer.Kind, lParam uintptr) {
|
||||
if !w.config.Focused {
|
||||
windows.SetFocus(w.hwnd)
|
||||
}
|
||||
|
||||
var kind pointer.Kind
|
||||
if press {
|
||||
kind = pointer.Press
|
||||
if w.pointerBtns == 0 {
|
||||
windows.SetCapture(w.hwnd)
|
||||
}
|
||||
w.pointerBtns |= btn
|
||||
} else {
|
||||
kind = pointer.Release
|
||||
w.pointerBtns &^= btn
|
||||
if w.pointerBtns == 0 {
|
||||
windows.ReleaseCapture()
|
||||
}
|
||||
src := pointer.Touch
|
||||
if pi.PointerType == windows.PT_MOUSE {
|
||||
src = pointer.Mouse
|
||||
}
|
||||
|
||||
x, y := coordsFromlParam(lParam)
|
||||
p := f32.Point{X: float32(x), Y: float32(y)}
|
||||
np := windows.Point{X: int32(x), Y: int32(y)}
|
||||
windows.ScreenToClient(w.hwnd, &np)
|
||||
p := f32.Point{X: float32(np.X), Y: float32(np.Y)}
|
||||
w.ProcessEvent(pointer.Event{
|
||||
Kind: kind,
|
||||
Source: pointer.Mouse,
|
||||
Source: src,
|
||||
Position: p,
|
||||
Buttons: w.pointerBtns,
|
||||
PointerID: pid,
|
||||
Buttons: getPointerButtons(pi),
|
||||
Time: windows.GetMessageTime(),
|
||||
Modifiers: kmods,
|
||||
Modifiers: getModifiers(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -537,6 +539,12 @@ func coordsFromlParam(lParam uintptr) (int, int) {
|
||||
}
|
||||
|
||||
func (w *window) scrollEvent(wParam, lParam uintptr, horizontal bool, kmods key.Modifiers) {
|
||||
pid := getPointerIDwParam(wParam)
|
||||
pi, err := windows.GetPointerInfo(uint32(pid))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
x, y := coordsFromlParam(lParam)
|
||||
// The WM_MOUSEWHEEL coordinates are in screen coordinates, in contrast
|
||||
// to other mouse events.
|
||||
@@ -559,7 +567,7 @@ func (w *window) scrollEvent(wParam, lParam uintptr, horizontal bool, kmods key.
|
||||
Kind: pointer.Scroll,
|
||||
Source: pointer.Mouse,
|
||||
Position: p,
|
||||
Buttons: w.pointerBtns,
|
||||
Buttons: getPointerButtons(pi),
|
||||
Scroll: sp,
|
||||
Modifiers: kmods,
|
||||
Time: windows.GetMessageTime(),
|
||||
@@ -1005,3 +1013,45 @@ func (Win32ViewEvent) ImplementsEvent() {}
|
||||
func (w Win32ViewEvent) Valid() bool {
|
||||
return w != (Win32ViewEvent{})
|
||||
}
|
||||
|
||||
// LOWORD (minwindef.h)
|
||||
func loWord(val uint32) uint16 {
|
||||
return uint16(val & 0xFFFF)
|
||||
}
|
||||
|
||||
// GET_POINTERID_WPARAM (winuser.h)
|
||||
func getPointerIDwParam(wParam uintptr) pointer.ID {
|
||||
return pointer.ID(loWord(uint32(wParam)))
|
||||
}
|
||||
|
||||
func getPointerButtons(pi windows.PointerInfo) pointer.Buttons {
|
||||
var btns pointer.Buttons
|
||||
|
||||
if pi.PointerFlags&windows.POINTER_FLAG_FIRSTBUTTON != 0 {
|
||||
btns |= pointer.ButtonPrimary
|
||||
} else {
|
||||
btns &^= pointer.ButtonPrimary
|
||||
}
|
||||
if pi.PointerFlags&windows.POINTER_FLAG_SECONDBUTTON != 0 {
|
||||
btns |= pointer.ButtonSecondary
|
||||
} else {
|
||||
btns &^= pointer.ButtonSecondary
|
||||
}
|
||||
if pi.PointerFlags&windows.POINTER_FLAG_THIRDBUTTON != 0 {
|
||||
btns |= pointer.ButtonTertiary
|
||||
} else {
|
||||
btns &^= pointer.ButtonTertiary
|
||||
}
|
||||
if pi.PointerFlags&windows.POINTER_FLAG_FOURTHBUTTON != 0 {
|
||||
btns |= pointer.ButtonQuaternary
|
||||
} else {
|
||||
btns &^= pointer.ButtonQuaternary
|
||||
}
|
||||
if pi.PointerFlags&windows.POINTER_FLAG_FIFTHBUTTON != 0 {
|
||||
btns |= pointer.ButtonQuinary
|
||||
} else {
|
||||
btns &^= pointer.ButtonQuinary
|
||||
}
|
||||
|
||||
return btns
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user