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
|
||||
_MONITOR_DEFAULTTONEAREST = 0x00000002
|
||||
_MOUSE_MOVE_ABSOLUTE = 0x01
|
||||
_MOUSE_VIRTUAL_DESKTOP = 0x02
|
||||
_MSGFLT_ALLOW = 1
|
||||
_OCR_CROSS = 32515
|
||||
_OCR_HAND = 32649
|
||||
@ -141,11 +142,18 @@ const (
|
||||
_SIZE_MAXIMIZED = 2
|
||||
_SIZE_MINIMIZED = 1
|
||||
_SIZE_RESTORED = 0
|
||||
_SM_CXCURSOR = 13
|
||||
_SM_CXICON = 11
|
||||
_SM_CXSMICON = 49
|
||||
_SM_CYCAPTION = 4
|
||||
_SM_CYCURSOR = 14
|
||||
_SM_CYICON = 12
|
||||
_SM_CXSCREEN = 0
|
||||
_SM_CYSCREEN = 1
|
||||
_SM_CYSMICON = 50
|
||||
_SM_CXVIRTUALSCREEN = 78
|
||||
_SM_CYVIRTUALSCREEN = 79
|
||||
_SM_REMOTESESSION = 0x1000
|
||||
_SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000
|
||||
_SPI_GETMOUSETRAILS = 94
|
||||
_SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001
|
||||
@ -755,9 +763,11 @@ var (
|
||||
procChangeWindowMessageFilterEx = user32.NewProc("ChangeWindowMessageFilterEx")
|
||||
procClientToScreen = user32.NewProc("ClientToScreen")
|
||||
procClipCursor = user32.NewProc("ClipCursor")
|
||||
procCreateCursor = user32.NewProc("CreateCursor")
|
||||
procCreateIconIndirect = user32.NewProc("CreateIconIndirect")
|
||||
procCreateWindowExW = user32.NewProc("CreateWindowExW")
|
||||
procDefWindowProcW = user32.NewProc("DefWindowProcW")
|
||||
procDestroyCursor = user32.NewProc("DestroyCursor")
|
||||
procDestroyIcon = user32.NewProc("DestroyIcon")
|
||||
procDestroyWindow = user32.NewProc("DestroyWindow")
|
||||
procDispatchMessageW = user32.NewProc("DispatchMessageW")
|
||||
@ -915,6 +925,26 @@ func _ClipCursor(lpRect *_RECT) error {
|
||||
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) {
|
||||
r, _, e := procCreateBitmap.Call(uintptr(nWidth), uintptr(nHeight), uintptr(nPlanes), uintptr(nBitCount), uintptr(lpBits))
|
||||
if _HBITMAP(r) == 0 {
|
||||
@ -986,6 +1016,14 @@ func _DefWindowProcW(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPA
|
||||
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 {
|
||||
r, _, e := procDestroyIcon.Call(uintptr(hIcon))
|
||||
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||
|
@ -239,6 +239,55 @@ func createHelperWindow() error {
|
||||
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 {
|
||||
// Changing the foreground lock timeout was removed from the original code.
|
||||
// See https://github.com/glfw/glfw/commit/58b48a3a00d9c2a5ca10cc23069a71d8773cc7a4
|
||||
@ -293,6 +342,10 @@ func platformInit() error {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Some hacks are needed to support Remote Desktop...
|
||||
if err := initRemoteSession(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := pollMonitorsWin32(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -301,6 +354,12 @@ func platformInit() 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 err := _UnregisterDeviceNotification(_glfw.platformWindow.deviceNotificationHandle); err != nil {
|
||||
return err
|
||||
|
@ -66,14 +66,18 @@ type platformLibraryWindowState struct {
|
||||
scancodes [KeyLast + 1]int
|
||||
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
|
||||
restoreCursorPosY float64
|
||||
|
||||
// The window whose disabled cursor mode is active
|
||||
// disabledCursorWindow is the window whose disabled cursor mode is active
|
||||
disabledCursorWindow *Window
|
||||
// The window the cursor is captured in
|
||||
// capturedCursorWindow is the window the cursor is captured in
|
||||
capturedCursorWindow *Window
|
||||
rawInput []byte
|
||||
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)
|
||||
}
|
||||
} 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
|
||||
}
|
||||
@ -907,8 +910,46 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
|
||||
var dx, dy int
|
||||
data := (*_RAWINPUT)(unsafe.Pointer(&_glfw.platformWindow.rawInput[0]))
|
||||
if data.mouse.usFlags&_MOUSE_MOVE_ABSOLUTE != 0 {
|
||||
if _glfw.platformWindow.isRemoteSession {
|
||||
// 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 {
|
||||
dx = int(data.mouse.lLastX)
|
||||
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,
|
||||
// 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 err := window.platformSetCursorPos(float64(width/2), float64(height/2)); err != nil {
|
||||
return err
|
||||
|
Loading…
Reference in New Issue
Block a user