capture user move window action instantly with precision without using delay timer

This commit is contained in:
Kang Yu 2020-02-29 18:18:00 -08:00
parent 29f24db354
commit aa8b478eda

View file

@ -22,9 +22,6 @@ namespace Ninjacrab.PersistentWindows.Common
private const int MaxRestoreTimesRemote = 6; // for remote session private const int MaxRestoreTimesRemote = 6; // for remote session
private const int CaptureLatency = 3000; // milliseconds to wait for window position capture, should be bigger than RestoreLatency private const int CaptureLatency = 3000; // milliseconds to wait for window position capture, should be bigger than RestoreLatency
private const int MaxCaptureLatency = 15000; // max latency to capture OS moves, needed for slow RDP session
private const int MaxUserMovePerSecond = 4; // maximum speed of window move/resize by human
private const int MinOsMoveWindows = 5; // minimum number of moving windows to measure in order to recognize OS initiated move
// window position database // window position database
private Dictionary<string, Dictionary<string, ApplicationDisplayMetrics>> monitorApplications = null; private Dictionary<string, Dictionary<string, ApplicationDisplayMetrics>> monitorApplications = null;
@ -37,14 +34,8 @@ namespace Ninjacrab.PersistentWindows.Common
private Object controlLock = new Object(); private Object controlLock = new Object();
private string validDisplayKeyForCapture = null; private string validDisplayKeyForCapture = null;
// capture control: window move/resize activity
private int userMoves = 0; // user initiated window move/resize events
private DateTime firstEventTime;
private HashSet<IntPtr> pendingCaptureWindows = new HashSet<IntPtr>();
// restore control // restore control
private bool restoringWindowPos = false; // about to restore private bool restoringWindowPos = false; // about to restore
private bool osMove = false; // window move/resize is initiated by OS
private int restoreTimes = 0; private int restoreTimes = 0;
private int restoreNestLevel = 0; // nested call level private int restoreNestLevel = 0; // nested call level
@ -71,7 +62,6 @@ namespace Ninjacrab.PersistentWindows.Common
BeginCaptureApplicationsOnCurrentDisplays(); BeginCaptureApplicationsOnCurrentDisplays();
}); });
firstEventTime = DateTime.Now;
validDisplayKeyForCapture = GetDisplayKey(); validDisplayKeyForCapture = GetDisplayKey();
StartCaptureTimer(); //initial capture StartCaptureTimer(); //initial capture
@ -85,7 +75,6 @@ namespace Ninjacrab.PersistentWindows.Common
{ {
Log.Trace("Restore Finished"); Log.Trace("Restore Finished");
restoringWindowPos = false; restoringWindowPos = false;
osMove = false;
ResetState(); ResetState();
}); });
@ -244,25 +233,6 @@ namespace Ninjacrab.PersistentWindows.Common
Log.Trace(log); Log.Trace(log);
#endif #endif
DateTime now = DateTime.Now;
if (pendingCaptureWindows.Count() == 0)
{
firstEventTime = now;
}
pendingCaptureWindows.Add(hwnd);
// figure out if all pending capture moves are OS initiated
double elapsedMs = (now - firstEventTime).TotalMilliseconds;
if (userMoves == 0
&& pendingCaptureWindows.Count >= MinOsMoveWindows
&& elapsedMs * MaxUserMovePerSecond / 1000 < pendingCaptureWindows.Count)
{
osMove = true;
Log.Trace("os move detected. user moves :{0}, total moved windows : {1}, elapsed milliseconds {2}",
userMoves, pendingCaptureWindows.Count, elapsedMs);
}
if (restoringWindowPos) if (restoringWindowPos)
{ {
switch (eventType) switch (eventType)
@ -271,6 +241,7 @@ namespace Ninjacrab.PersistentWindows.Common
// if user opened new window, don't abort restore, as new window is not affected by restore anyway // if user opened new window, don't abort restore, as new window is not affected by restore anyway
return; return;
case User32Events.EVENT_OBJECT_LOCATIONCHANGE: case User32Events.EVENT_OBJECT_LOCATIONCHANGE:
// let it trigger next restore
break; break;
case User32Events.EVENT_SYSTEM_MINIMIZESTART: case User32Events.EVENT_SYSTEM_MINIMIZESTART:
case User32Events.EVENT_SYSTEM_MINIMIZEEND: case User32Events.EVENT_SYSTEM_MINIMIZEEND:
@ -283,7 +254,8 @@ namespace Ninjacrab.PersistentWindows.Common
{ {
lock (databaseLock) lock (databaseLock)
{ {
StartCaptureApplicationsOnCurrentDisplays(); string displayKey = GetDisplayKey();
CaptureWindow(window, eventType, DateTime.Now, displayKey);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -307,6 +279,34 @@ namespace Ninjacrab.PersistentWindows.Common
} }
else else
{ {
switch (eventType)
{
case User32Events.EVENT_OBJECT_LOCATIONCHANGE:
break;
case User32Events.EVENT_SYSTEM_FOREGROUND:
case User32Events.EVENT_SYSTEM_MINIMIZESTART:
case User32Events.EVENT_SYSTEM_MINIMIZEEND:
case User32Events.EVENT_SYSTEM_MOVESIZEEND:
var thread = new Thread(() =>
{
try
{
lock (databaseLock)
{
string displayKey = GetDisplayKey();
CaptureWindow(window, eventType, DateTime.Now, displayKey);
}
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
});
thread.Start();
break;
}
/*
if (eventType != User32Events.EVENT_OBJECT_LOCATIONCHANGE) if (eventType != User32Events.EVENT_OBJECT_LOCATIONCHANGE)
{ {
userMoves++; userMoves++;
@ -316,6 +316,7 @@ namespace Ninjacrab.PersistentWindows.Common
{ {
StartCaptureTimer(); StartCaptureTimer();
} }
*/
} }
} }
catch (Exception ex) catch (Exception ex)
@ -424,22 +425,6 @@ namespace Ninjacrab.PersistentWindows.Common
return; return;
} }
if (restoringWindowPos && userMoves == 0 && pendingCaptureWindows.Count == 0)
{
return;
}
if (osMove)
{
// postpone capture to wait for restore
osMove = false;
if (!restoringWindowPos)
{
StartCaptureTimer(MaxCaptureLatency);
}
return;
}
lock (databaseLock) lock (databaseLock)
{ {
StartCaptureApplicationsOnCurrentDisplays(); StartCaptureApplicationsOnCurrentDisplays();
@ -467,15 +452,12 @@ namespace Ninjacrab.PersistentWindows.Common
// reset capture statistics for next capture period // reset capture statistics for next capture period
CancelCaptureTimer(); CancelCaptureTimer();
pendingCaptureWindows.Clear();
userMoves = 0;
} }
} }
private void StartCaptureApplicationsOnCurrentDisplays() private void StartCaptureApplicationsOnCurrentDisplays()
{ {
restoringWindowPos = false; restoringWindowPos = false;
osMove = false;
ResetState(); ResetState();
CaptureApplicationsOnCurrentDisplays(); CaptureApplicationsOnCurrentDisplays();
} }