mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
internal/glfw: bug fix: disabling cursor doesn't work well on remote desktop
This change applies the bug fix at glfw/glfw#1276 Updates #2961
This commit is contained in:
parent
86e0bcc264
commit
6df42f1a4b
@ -100,6 +100,7 @@ const (
|
|||||||
_MAPVK_VSC_TO_VK = 1
|
_MAPVK_VSC_TO_VK = 1
|
||||||
_MONITOR_DEFAULTTONEAREST = 0x00000002
|
_MONITOR_DEFAULTTONEAREST = 0x00000002
|
||||||
_MOUSE_MOVE_ABSOLUTE = 0x01
|
_MOUSE_MOVE_ABSOLUTE = 0x01
|
||||||
|
_MOUSE_VIRTUAL_DESKTOP = 0x02
|
||||||
_MSGFLT_ALLOW = 1
|
_MSGFLT_ALLOW = 1
|
||||||
_OCR_CROSS = 32515
|
_OCR_CROSS = 32515
|
||||||
_OCR_HAND = 32649
|
_OCR_HAND = 32649
|
||||||
@ -141,11 +142,18 @@ const (
|
|||||||
_SIZE_MAXIMIZED = 2
|
_SIZE_MAXIMIZED = 2
|
||||||
_SIZE_MINIMIZED = 1
|
_SIZE_MINIMIZED = 1
|
||||||
_SIZE_RESTORED = 0
|
_SIZE_RESTORED = 0
|
||||||
|
_SM_CXCURSOR = 13
|
||||||
_SM_CXICON = 11
|
_SM_CXICON = 11
|
||||||
_SM_CXSMICON = 49
|
_SM_CXSMICON = 49
|
||||||
_SM_CYCAPTION = 4
|
_SM_CYCAPTION = 4
|
||||||
|
_SM_CYCURSOR = 14
|
||||||
_SM_CYICON = 12
|
_SM_CYICON = 12
|
||||||
|
_SM_CXSCREEN = 0
|
||||||
|
_SM_CYSCREEN = 1
|
||||||
_SM_CYSMICON = 50
|
_SM_CYSMICON = 50
|
||||||
|
_SM_CXVIRTUALSCREEN = 78
|
||||||
|
_SM_CYVIRTUALSCREEN = 79
|
||||||
|
_SM_REMOTESESSION = 0x1000
|
||||||
_SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000
|
_SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000
|
||||||
_SPI_GETMOUSETRAILS = 94
|
_SPI_GETMOUSETRAILS = 94
|
||||||
_SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001
|
_SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001
|
||||||
@ -755,9 +763,11 @@ var (
|
|||||||
procChangeWindowMessageFilterEx = user32.NewProc("ChangeWindowMessageFilterEx")
|
procChangeWindowMessageFilterEx = user32.NewProc("ChangeWindowMessageFilterEx")
|
||||||
procClientToScreen = user32.NewProc("ClientToScreen")
|
procClientToScreen = user32.NewProc("ClientToScreen")
|
||||||
procClipCursor = user32.NewProc("ClipCursor")
|
procClipCursor = user32.NewProc("ClipCursor")
|
||||||
|
procCreateCursor = user32.NewProc("CreateCursor")
|
||||||
procCreateIconIndirect = user32.NewProc("CreateIconIndirect")
|
procCreateIconIndirect = user32.NewProc("CreateIconIndirect")
|
||||||
procCreateWindowExW = user32.NewProc("CreateWindowExW")
|
procCreateWindowExW = user32.NewProc("CreateWindowExW")
|
||||||
procDefWindowProcW = user32.NewProc("DefWindowProcW")
|
procDefWindowProcW = user32.NewProc("DefWindowProcW")
|
||||||
|
procDestroyCursor = user32.NewProc("DestroyCursor")
|
||||||
procDestroyIcon = user32.NewProc("DestroyIcon")
|
procDestroyIcon = user32.NewProc("DestroyIcon")
|
||||||
procDestroyWindow = user32.NewProc("DestroyWindow")
|
procDestroyWindow = user32.NewProc("DestroyWindow")
|
||||||
procDispatchMessageW = user32.NewProc("DispatchMessageW")
|
procDispatchMessageW = user32.NewProc("DispatchMessageW")
|
||||||
@ -915,6 +925,26 @@ func _ClipCursor(lpRect *_RECT) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _CreateCursor(hInst _HINSTANCE, xHotSpot int32, yHotSpot int32, nWidth int32, nHeight int32, pvANDPlane, pvXORPlane []byte) (_HCURSOR, error) {
|
||||||
|
var andPlane *byte
|
||||||
|
if len(pvANDPlane) > 0 {
|
||||||
|
andPlane = &pvANDPlane[0]
|
||||||
|
}
|
||||||
|
var xorPlane *byte
|
||||||
|
if len(pvXORPlane) > 0 {
|
||||||
|
xorPlane = &pvXORPlane[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _, e := procCreateCursor.Call(uintptr(hInst), uintptr(xHotSpot), uintptr(yHotSpot), uintptr(nWidth), uintptr(nHeight), uintptr(unsafe.Pointer(andPlane)), uintptr(unsafe.Pointer(xorPlane)))
|
||||||
|
runtime.KeepAlive(pvANDPlane)
|
||||||
|
runtime.KeepAlive(pvXORPlane)
|
||||||
|
|
||||||
|
if _HCURSOR(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||||
|
return 0, fmt.Errorf("glfw: CreateCursor failed: %w", e)
|
||||||
|
}
|
||||||
|
return _HCURSOR(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
func _CreateBitmap(nWidth int32, nHeight int32, nPlanes uint32, nBitCount uint32, lpBits unsafe.Pointer) (_HBITMAP, error) {
|
func _CreateBitmap(nWidth int32, nHeight int32, nPlanes uint32, nBitCount uint32, lpBits unsafe.Pointer) (_HBITMAP, error) {
|
||||||
r, _, e := procCreateBitmap.Call(uintptr(nWidth), uintptr(nHeight), uintptr(nPlanes), uintptr(nBitCount), uintptr(lpBits))
|
r, _, e := procCreateBitmap.Call(uintptr(nWidth), uintptr(nHeight), uintptr(nPlanes), uintptr(nBitCount), uintptr(lpBits))
|
||||||
if _HBITMAP(r) == 0 {
|
if _HBITMAP(r) == 0 {
|
||||||
@ -986,6 +1016,14 @@ func _DefWindowProcW(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPA
|
|||||||
return _LRESULT(r)
|
return _LRESULT(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _DestroyCursor(hCursor _HCURSOR) error {
|
||||||
|
r, _, e := procDestroyCursor.Call(uintptr(hCursor))
|
||||||
|
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||||
|
return fmt.Errorf("glfw: DestroyCursor failed: %w", e)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func _DestroyIcon(hIcon _HICON) error {
|
func _DestroyIcon(hIcon _HICON) error {
|
||||||
r, _, e := procDestroyIcon.Call(uintptr(hIcon))
|
r, _, e := procDestroyIcon.Call(uintptr(hIcon))
|
||||||
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||||
|
@ -239,6 +239,55 @@ func createHelperWindow() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createBlankCursor() error {
|
||||||
|
// HACK: Create a transparent cursor as using the NULL cursor breaks
|
||||||
|
// using SetCursorPos when connected over RDP
|
||||||
|
cursorWidth, err := _GetSystemMetrics(_SM_CXCURSOR)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cursorHeight, err := _GetSystemMetrics(_SM_CYCURSOR)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
andMask := make([]byte, cursorWidth*cursorHeight/8)
|
||||||
|
for i := range andMask {
|
||||||
|
andMask[i] = 0xff
|
||||||
|
}
|
||||||
|
xorMask := make([]byte, cursorWidth*cursorHeight/8)
|
||||||
|
|
||||||
|
// Cursor creation might fail, but that's fine as we get NULL in that case,
|
||||||
|
// which serves as an acceptable fallback blank cursor (other than on RDP)
|
||||||
|
c, _ := _CreateCursor(0, 0, 0, cursorWidth, cursorHeight, andMask, xorMask)
|
||||||
|
_glfw.platformWindow.blankCursor = c
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initRemoteSession() error {
|
||||||
|
if microsoftgdk.IsXbox() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the current progress was started with Remote Desktop.
|
||||||
|
r, err := _GetSystemMetrics(_SM_REMOTESESSION)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_glfw.platformWindow.isRemoteSession = r > 0
|
||||||
|
|
||||||
|
// With Remote desktop, we need to create a blank cursor because of the cursor is Set to nil
|
||||||
|
// if cannot be moved to center in capture mode. If not Remote Desktop platformWindow.blankCursor stays nil
|
||||||
|
// and will perform has before (normal).
|
||||||
|
if _glfw.platformWindow.isRemoteSession {
|
||||||
|
if err := createBlankCursor(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func platformInit() error {
|
func platformInit() error {
|
||||||
// Changing the foreground lock timeout was removed from the original code.
|
// Changing the foreground lock timeout was removed from the original code.
|
||||||
// See https://github.com/glfw/glfw/commit/58b48a3a00d9c2a5ca10cc23069a71d8773cc7a4
|
// See https://github.com/glfw/glfw/commit/58b48a3a00d9c2a5ca10cc23069a71d8773cc7a4
|
||||||
@ -293,6 +342,10 @@ func platformInit() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Some hacks are needed to support Remote Desktop...
|
||||||
|
if err := initRemoteSession(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := pollMonitorsWin32(); err != nil {
|
if err := pollMonitorsWin32(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -301,6 +354,12 @@ func platformInit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func platformTerminate() error {
|
func platformTerminate() error {
|
||||||
|
if _glfw.platformWindow.blankCursor != 0 {
|
||||||
|
if err := _DestroyCursor(_glfw.platformWindow.blankCursor); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if _glfw.platformWindow.deviceNotificationHandle != 0 {
|
if _glfw.platformWindow.deviceNotificationHandle != 0 {
|
||||||
if err := _UnregisterDeviceNotification(_glfw.platformWindow.deviceNotificationHandle); err != nil {
|
if err := _UnregisterDeviceNotification(_glfw.platformWindow.deviceNotificationHandle); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -66,14 +66,18 @@ type platformLibraryWindowState struct {
|
|||||||
scancodes [KeyLast + 1]int
|
scancodes [KeyLast + 1]int
|
||||||
keynames [KeyLast + 1]string
|
keynames [KeyLast + 1]string
|
||||||
|
|
||||||
// Where to place the cursor when re-enabled
|
// restoreCursorPosX and restoreCursorPosY indicates where to place the cursor when re-enabled
|
||||||
restoreCursorPosX float64
|
restoreCursorPosX float64
|
||||||
restoreCursorPosY float64
|
restoreCursorPosY float64
|
||||||
|
|
||||||
// The window whose disabled cursor mode is active
|
// disabledCursorWindow is the window whose disabled cursor mode is active
|
||||||
disabledCursorWindow *Window
|
disabledCursorWindow *Window
|
||||||
// The window the cursor is captured in
|
// capturedCursorWindow is the window the cursor is captured in
|
||||||
capturedCursorWindow *Window
|
capturedCursorWindow *Window
|
||||||
rawInput []byte
|
rawInput []byte
|
||||||
mouseTrailSize uint32
|
mouseTrailSize uint32
|
||||||
|
// isRemoteSession indicates if the process was started behind Remote Destop
|
||||||
|
isRemoteSession bool
|
||||||
|
// blankCursor is an invisible cursor, needed for special cases (see WM_INPUT handler)
|
||||||
|
blankCursor _HCURSOR
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,10 @@ func (w *Window) updateCursorImage() error {
|
|||||||
_SetCursor(cursor)
|
_SetCursor(cursor)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_SetCursor(0)
|
// Connected via Remote Desktop, nil cursor will present SetCursorPos the move the cursor.
|
||||||
|
// using a blank cursor fix that.
|
||||||
|
// When not via Remote Desktop, platformWindow.blankCursor should be nil.
|
||||||
|
_SetCursor(_glfw.platformWindow.blankCursor)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -907,8 +910,46 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
|
|||||||
var dx, dy int
|
var dx, dy int
|
||||||
data := (*_RAWINPUT)(unsafe.Pointer(&_glfw.platformWindow.rawInput[0]))
|
data := (*_RAWINPUT)(unsafe.Pointer(&_glfw.platformWindow.rawInput[0]))
|
||||||
if data.mouse.usFlags&_MOUSE_MOVE_ABSOLUTE != 0 {
|
if data.mouse.usFlags&_MOUSE_MOVE_ABSOLUTE != 0 {
|
||||||
dx = int(data.mouse.lLastX) - window.platform.lastCursorPosX
|
if _glfw.platformWindow.isRemoteSession {
|
||||||
dy = int(data.mouse.lLastY) - window.platform.lastCursorPosY
|
// Remote Desktop Mode
|
||||||
|
// As per https://github.com/Microsoft/DirectXTK/commit/ef56b63f3739381e451f7a5a5bd2c9779d2a7555
|
||||||
|
// MOUSE_MOVE_ABSOLUTE is a range from 0 through 65535, based on the screen size.
|
||||||
|
// Apparently, absolute mode only occurs over RDP though.
|
||||||
|
var smx int32 = _SM_CXSCREEN
|
||||||
|
var smy int32 = _SM_CYSCREEN
|
||||||
|
if data.mouse.usFlags&_MOUSE_VIRTUAL_DESKTOP != 0 {
|
||||||
|
smx = _SM_CXVIRTUALSCREEN
|
||||||
|
smy = _SM_CYVIRTUALSCREEN
|
||||||
|
}
|
||||||
|
|
||||||
|
width, err := _GetSystemMetrics(smx)
|
||||||
|
if err != nil {
|
||||||
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
height, err := _GetSystemMetrics(smy)
|
||||||
|
if err != nil {
|
||||||
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := _POINT{
|
||||||
|
x: int32(float64(data.mouse.lLastX) / 65535.0 * float64(width)),
|
||||||
|
y: int32(float64(data.mouse.lLastY) / 65535.0 * float64(height)),
|
||||||
|
}
|
||||||
|
if err := _ScreenToClient(window.platform.handle, &pos); err != nil {
|
||||||
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = int(pos.x) - window.platform.lastCursorPosX
|
||||||
|
dy = int(pos.y) - window.platform.lastCursorPosY
|
||||||
|
} else {
|
||||||
|
// Normal mode
|
||||||
|
// We should have the right absolute coords in data.mouse
|
||||||
|
dx = int(data.mouse.lLastX) - window.platform.lastCursorPosX
|
||||||
|
dy = int(data.mouse.lLastY) - window.platform.lastCursorPosY
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dx = int(data.mouse.lLastX)
|
dx = int(data.mouse.lLastX)
|
||||||
dy = int(data.mouse.lLastY)
|
dy = int(data.mouse.lLastY)
|
||||||
@ -2159,6 +2200,7 @@ func platformPollEvents() error {
|
|||||||
|
|
||||||
// NOTE: Re-center the cursor only if it has moved since the last call,
|
// NOTE: Re-center the cursor only if it has moved since the last call,
|
||||||
// to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
|
// to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
|
||||||
|
// The re-center is required in order to prevent the mouse cursor stopping at the edges of the screen.
|
||||||
if window.platform.lastCursorPosX != width/2 || window.platform.lastCursorPosY != height/2 {
|
if window.platform.lastCursorPosX != width/2 || window.platform.lastCursorPosY != height/2 {
|
||||||
if err := window.platformSetCursorPos(float64(width/2), float64(height/2)); err != nil {
|
if err := window.platformSetCursorPos(float64(width/2), float64(height/2)); err != nil {
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user