Unity3d user32.dll 拖动 window 并取回焦点
Unity3d user32.dll drag window and take focus back
我做了一个无边框的 windowed 应用程序和一个 "fake" 标题栏来拖动它。
我正在使用 user32.dll、
这将开始 window 拖动(由 unity IBeginDragHandler 触发):
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int WM_NCLBUTTONUP = 0x00A2;
public const int WM_LBUTTONUP = 0x0202;
[DllImport("User32.dll")]
public static extern bool ReleaseCapture();
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
IntPtr window = GetActiveWindow();
...
...
ReleaseCapture();
SendMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, 0);
然后停止拖动(这部分不确定):
ReleaseCapture();
SendMessage(window, WM_NCLBUTTONUP, HTCAPTION, 0);
SendMessage(window, WM_LBUTTONUP, HTCAPTION, 0);
它在编辑器和构建上运行良好,但在开发构建时产生错误:
An abnormal situation has occurred: the PlayerLoop internal function
has been called recursively. Please contact Customer Support with a
sample project so that we can reproduce the problem and troubleshoot
it. LauncherWindow:SendMessage(IntPtr, Int32, Int32, Int32)
LauncherWindow:StartWindowDrag() (at E:\Unity Projects\Crime Club
Launcher\Assets\Scripts\Lib\LauncherWindow.cs:115)
WindowDragZone:UnityEngine.EventSystems.IBeginDragHandler.OnBeginDrag(PointerEventData)
(at E:\Unity Projects\Crime Club Launcher\Assets\WindowDragZone.cs:9)
UnityEngine.EventSystems.ExecuteEvents:Execute(IBeginDragHandler,
BaseEventData) (at
C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:64)
UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject,
BaseEventData, EventFunction`1) (at
C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:261)
UnityEngine.EventSystems.PointerInputModule:ProcessDrag(PointerEventData)
(at
C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\PointerInputModule.cs:261)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent(Int32)
(at
C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:434)
UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent() (at
C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:412)
UnityEngine.EventSystems.StandaloneInputModule:Process() (at
C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:186)
UnityEngine.EventSystems.EventSystem:Update() (at
C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\EventSystem.cs:283)
你怎么看这个?
编辑:
好的,所以我终于通过替换
摆脱了那个错误
SendMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, 0);
来自:
private const int WM_SYSCOMMAND = 0x112;
private const int MOUSE_MOVE = 0xF012;
SendMessage(window, WM_SYSCOMMAND, MOUSE_MOVE, 0);
现在我有最后一个小问题:
windows 在鼠标释放时被拖放,但我看起来 window 正在失去对类似内容的关注:
第一次点击总是错过,我必须点击两次才能再次拖动或简单地与 unity 应用程序交互。
我在 OnEndDrag 中尝试了 User32 的函数:
ShowWindow、SetActiveWindow、SetFocus 等...
我发现的所有内容都与该问题有关,但它们都没有明显效果,我仍然必须单击两次。
最终通过将 SendMessage() 替换为 :
摆脱了这个错误
SendMessageCallback(window, WM_SYSCOMMAND, MOUSE_MOVE, 0, WindowDropCallback, 0);
我做了一个无边框的 windowed 应用程序和一个 "fake" 标题栏来拖动它。
我正在使用 user32.dll、
这将开始 window 拖动(由 unity IBeginDragHandler 触发):
public const int WM_NCLBUTTONDOWN = 0xA1;
public const int WM_NCLBUTTONUP = 0x00A2;
public const int WM_LBUTTONUP = 0x0202;
[DllImport("User32.dll")]
public static extern bool ReleaseCapture();
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
IntPtr window = GetActiveWindow();
...
...
ReleaseCapture();
SendMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, 0);
然后停止拖动(这部分不确定):
ReleaseCapture();
SendMessage(window, WM_NCLBUTTONUP, HTCAPTION, 0);
SendMessage(window, WM_LBUTTONUP, HTCAPTION, 0);
它在编辑器和构建上运行良好,但在开发构建时产生错误:
An abnormal situation has occurred: the PlayerLoop internal function has been called recursively. Please contact Customer Support with a sample project so that we can reproduce the problem and troubleshoot it. LauncherWindow:SendMessage(IntPtr, Int32, Int32, Int32) LauncherWindow:StartWindowDrag() (at E:\Unity Projects\Crime Club Launcher\Assets\Scripts\Lib\LauncherWindow.cs:115) WindowDragZone:UnityEngine.EventSystems.IBeginDragHandler.OnBeginDrag(PointerEventData) (at E:\Unity Projects\Crime Club Launcher\Assets\WindowDragZone.cs:9) UnityEngine.EventSystems.ExecuteEvents:Execute(IBeginDragHandler, BaseEventData) (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:64) UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1) (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\ExecuteEvents.cs:261) UnityEngine.EventSystems.PointerInputModule:ProcessDrag(PointerEventData) (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\PointerInputModule.cs:261) UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent(Int32) (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:434) UnityEngine.EventSystems.StandaloneInputModule:ProcessMouseEvent() (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:412) UnityEngine.EventSystems.StandaloneInputModule:Process() (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\InputModules\StandaloneInputModule.cs:186) UnityEngine.EventSystems.EventSystem:Update() (at C:\buildslave\unity\build\Extensions\guisystem\UnityEngine.UI\EventSystem\EventSystem.cs:283)
你怎么看这个?
编辑: 好的,所以我终于通过替换
摆脱了那个错误SendMessage(window, WM_NCLBUTTONDOWN, HTCAPTION, 0);
来自:
private const int WM_SYSCOMMAND = 0x112;
private const int MOUSE_MOVE = 0xF012;
SendMessage(window, WM_SYSCOMMAND, MOUSE_MOVE, 0);
现在我有最后一个小问题: windows 在鼠标释放时被拖放,但我看起来 window 正在失去对类似内容的关注: 第一次点击总是错过,我必须点击两次才能再次拖动或简单地与 unity 应用程序交互。
我在 OnEndDrag 中尝试了 User32 的函数: ShowWindow、SetActiveWindow、SetFocus 等... 我发现的所有内容都与该问题有关,但它们都没有明显效果,我仍然必须单击两次。
最终通过将 SendMessage() 替换为 :
摆脱了这个错误SendMessageCallback(window, WM_SYSCOMMAND, MOUSE_MOVE, 0, WindowDropCallback, 0);