From 7cf8a152fc51300580670bf73aada55a37c6047f Mon Sep 17 00:00:00 2001 From: Kang Yu Date: Fri, 6 Mar 2020 13:20:49 -0800 Subject: [PATCH] experiment to move taskbar --- .../Models/ApplicationDisplayMetrics.cs | 4 + .../PersistentWindowProcessor.cs | 92 ++++++++++++++++++- .../WinApiBridge/User32.cs | 71 ++++++++++++++ 3 files changed, 163 insertions(+), 4 deletions(-) diff --git a/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/Models/ApplicationDisplayMetrics.cs b/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/Models/ApplicationDisplayMetrics.cs index 1a8a7e1..eb6ba10 100644 --- a/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/Models/ApplicationDisplayMetrics.cs +++ b/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/Models/ApplicationDisplayMetrics.cs @@ -10,6 +10,10 @@ namespace Ninjacrab.PersistentWindows.Common.Models public uint ProcessId { get; set; } public string ClassName { get; set; } public string ApplicationName { get; set; } + + public bool IsTaskbar { get; set; } + public Shell32.APP_BAR_DATA TaskBarPos { get; set; } + public RECT ScreenPosition { get; set; } public WindowPlacement WindowPlacement { get; set; } public bool NeedUpdateWindowPlacement { get; set; } //non-persistent data used for tmp argument passing only diff --git a/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/PersistentWindowProcessor.cs b/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/PersistentWindowProcessor.cs index 222c207..c347afd 100644 --- a/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/PersistentWindowProcessor.cs +++ b/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/PersistentWindowProcessor.cs @@ -64,6 +64,20 @@ namespace Ninjacrab.PersistentWindows.Common #endif public void Start() { + /* + RECT screenPosition = new RECT(); + //IntPtr hTaskMan = User32.FindWindowA(null, "Untitled - Notepad"); + IntPtr hTaskMan = User32.FindWindowA(null, "Task Manager"); + User32.GetWindowRect(hTaskMan, ref screenPosition); + User32.SetCursorPos(screenPosition.Left + 200, screenPosition.Top + 20); + User32.SetForegroundWindow(hTaskMan); + User32.SetActiveWindow(hTaskMan); + User32.mouse_event(MouseAction.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, UIntPtr.Zero); + Thread.Sleep(1000); // wait to be activated + User32.SetCursorPos(screenPosition.Left + 200, screenPosition.Top - 100); + User32.mouse_event(MouseAction.MOUSEEVENTF_LEFTUP, 0, 0, 0, UIntPtr.Zero); + */ + monitorApplications = new Dictionary>(); databaseLock = new object(); validDisplayKeyForCapture = GetDisplayKey(); @@ -406,6 +420,10 @@ namespace Ninjacrab.PersistentWindows.Common { monitorApplications[displayKey].Add(curDisplayMetrics.Key, curDisplayMetrics); } + else if (curDisplayMetrics.IsTaskbar) + { + monitorApplications[displayKey][curDisplayMetrics.Key].TaskBarPos = curDisplayMetrics.TaskBarPos; + } else { monitorApplications[displayKey][curDisplayMetrics.Key].WindowPlacement = curDisplayMetrics.WindowPlacement; @@ -540,14 +558,16 @@ namespace Ninjacrab.PersistentWindows.Common private IEnumerable CaptureWindowsOfInterest() { return SystemWindow.AllToplevelWindows - .Where(row => row.Parent.HWnd.ToInt64() == 0 + .Where(row => + { + return row.Parent.HWnd.ToInt64() == 0 //&& !string.IsNullOrEmpty(row.Title) //&& !row.Title.Equals("Program Manager") //&& !row.Title.Contains("Task Manager") //&& row.Position.Height != 0 //&& row.Position.Width != 0 - && row.Visible - ); + && row.Visible; + }); } private bool IsWindowMoved(string displayKey, SystemWindow window, User32Events eventType, DateTime now, out ApplicationDisplayMetrics curDisplayMetrics) @@ -559,10 +579,15 @@ namespace Ninjacrab.PersistentWindows.Common return false; } + bool isTaskBar = false; + Shell32.APP_BAR_DATA abd = new Shell32.APP_BAR_DATA(); if (window.ClassName.Contains("Shell_TrayWnd")) { // capture task bar - int i = 0; + isTaskBar = true; + abd.cbSize = (uint)Marshal.SizeOf(abd); + abd.hWnd = window.HWnd; + Shell32.SHAppBarMessage(Shell32.ABM_GETTASKBARPOS, ref abd); } else if (string.IsNullOrEmpty(window.Title)) { @@ -597,11 +622,31 @@ namespace Ninjacrab.PersistentWindows.Common ClassName = window.ClassName, ProcessId = processId, + IsTaskbar = isTaskBar, + TaskBarPos = abd, + WindowPlacement = windowPlacement, NeedUpdateWindowPlacement = false, ScreenPosition = screenPosition }; + if (isTaskBar) + { + IntPtr hReBar = User32.FindWindowEx(hwnd, IntPtr.Zero, "ReBarWindow32", null); + User32.GetWindowRect(hReBar, ref screenPosition); + //User32.SetCursorPos(screenPosition.Left + 50, screenPosition.Top + 1650); + User32.SetCursorPos(screenPosition.Left + 3, screenPosition.Top + 3); + User32.SetForegroundWindow(hReBar); + User32.SetActiveWindow(hReBar); + User32.mouse_event(MouseAction.MOUSEEVENTF_LEFTDOWN, + 0, 0, 0, UIntPtr.Zero); + Thread.Sleep(2000); // wait to be activated + User32.SetCursorPos(screenPosition.Left + 200, - (screenPosition.Top + 3)); + User32.mouse_event(MouseAction.MOUSEEVENTF_LEFTUP, + 0, 0, 0, UIntPtr.Zero); + + int i = 0; + } bool moved = false; if (!monitorApplications[displayKey].ContainsKey(curDisplayMetrics.Key)) { @@ -622,6 +667,10 @@ namespace Ninjacrab.PersistentWindows.Common // when close/reopen session, OS/user may activate existing window (possibly with different position) // just ignore it } + else if (isTaskBar) + { + return !prevDisplayMetrics.TaskBarPos.Equals(curDisplayMetrics.TaskBarPos); + } else if (!prevDisplayMetrics.EqualPlacement(curDisplayMetrics)) { /* @@ -767,6 +816,7 @@ namespace Ninjacrab.PersistentWindows.Common { sWindows = CaptureWindowsOfInterest(); } + foreach (var window in sWindows) { if (!window.IsValid() || string.IsNullOrEmpty(window.ClassName)) @@ -798,6 +848,40 @@ namespace Ninjacrab.PersistentWindows.Common } bool success = true; + if (curDisplayMetrics.IsTaskbar) + { + // simulate mouse drag, assuming taskbar is unlocked + /* + ControlGetPos x, y, w, h, MSTaskListWClass1, ahk_class Shell_TrayWnd + MouseMove x+1, y+1 + MouseClickDrag Left, x+1, y+1, targetX, targetY, 10 + */ + IntPtr hTaskBar = User32.FindWindowEx(hwnd, IntPtr.Zero, "MSTaskListWClass1", "Running applications"); + + /* + Shell32.APP_BAR_DATA abd = prevDisplayMetrics.TaskBarPos; + abd.cbSize = (uint)Marshal.SizeOf(abd); + //abd.hWnd = window.HWnd; + //abd.uEdge = Shell32.ABE_TOP; + UIntPtr result = Shell32.SHAppBarMessage(Shell32.ABM_SETPOS, ref abd); + Log.Info("Set TaskBar pos ({0} [{1}x{2}]-[{3}x{4}]) - {5}", + window.Process.ProcessName, + abd.rc.Left, + abd.rc.Top, + abd.rc.Width, + abd.rc.Height, + result); + + User32.SetWindowPos(hwnd, IntPtr.Zero, abd.rc.Left, abd.rc.Top, abd.rc.Width, abd.rc.Height, + //SWP_NOSENDCHANGING); + SetWindowPosFlags.DoNotSendChangingEvent); + + User32.ShowWindow(hwnd, 5); //SW_SHOW + User32.UpdateWindow(hwnd); + */ + continue; + } + if (restoreTimes >= MinRestoreTimes || curDisplayMetrics.NeedUpdateWindowPlacement) { // recover NormalPosition (the workspace position prior to snap) diff --git a/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/WinApiBridge/User32.cs b/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/WinApiBridge/User32.cs index 3a6f70a..a2f981f 100644 --- a/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/WinApiBridge/User32.cs +++ b/Ninjacrab.PersistentWindows.Solution/Ninjacrab.PersistentWindows.Common/WinApiBridge/User32.cs @@ -49,6 +49,18 @@ namespace Ninjacrab.PersistentWindows.Common.WinApiBridge WINEVENT_INCONTEXT = 0x0004 } + public enum MouseAction : uint + { + MOUSEEVENTF_ABSOLUTE = 0x8000, + + MOUSEEVENTF_LEFTDOWN = 0x0002, + MOUSEEVENTF_LEFTUP = 0x0004, + MOUSEEVENTF_RIGHTDOWN = 0x0008, + MOUSEEVENTF_RIGHTUP = 0x0010, + + MOUSEEVENTF_MOVE = 0x0001, + } + public class User32 { #region EnumDisplayMonitors @@ -96,10 +108,37 @@ namespace Ninjacrab.PersistentWindows.Common.WinApiBridge [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsWindow(IntPtr hWnd); + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShowWindow(IntPtr hWnd, int cmd); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UpdateWindow(IntPtr hWnd); + [DllImport("user32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool IsTopLevelWindow(IntPtr hWnd); + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr FindWindowA(string lpClassName, string lpWindowName); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle); + + [DllImport("user32.dll")] + public static extern void mouse_event(MouseAction dwFlags, int dx, int dy, uint dwData, UIntPtr dwExtraInfo); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetCursorPos(int x, int y); + + [DllImport("user32.dll")] + public static extern bool SetForegroundWindow (IntPtr hWnd); + + [DllImport("user32.dll", SetLastError=true)] + public static extern IntPtr SetActiveWindow(IntPtr hWnd); + #region Hooks [DllImport("user32.dll")] public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam); @@ -130,4 +169,36 @@ namespace Ninjacrab.PersistentWindows.Common.WinApiBridge #endregion } + + public class Shell32 + { + [DllImport("Shell32.dll", CharSet = CharSet.Auto)] + public static extern UIntPtr SHAppBarMessage(int dwMessage, ref APP_BAR_DATA abd); + + public const int ABM_NEW = 0x00; + public const int ABM_REMOVE = 0x01; + public const int ABM_QUERYPOS = 0x02; + public const int ABM_SETPOS = 0x03; + public const int ABM_GETTASKBARPOS = 0x05; + public const int ABM_SETAUTOHIDEBAR = 0x08; + public const int ABM_SETSTATE = 0x0000000a; + public const int ABE_LEFT = 0; + public const int ABE_TOP = 1; + public const int ABE_RIGHT = 2; + public const int ABE_BOTTOM = 3; + public const int ABS_AUTOHIDE = 0x01; + public const int ABS_ALWAYSONTOP = 0x02; + + [StructLayout(LayoutKind.Sequential)] + public struct APP_BAR_DATA + { + public uint cbSize; + public IntPtr hWnd; + public int uCallbackMessage; + public int uEdge; + public RECT rc; + public IntPtr lParam; + } + + } }