Skip to content

Commit

Permalink
v1.9 - Current Focused Window support
Browse files Browse the repository at this point in the history
- Instead of choosing a specific application, you can now choose to manipulate the current focused window. This allows you to "snap"/"resize" the current focused app to various areas on the screen.
  • Loading branch information
BarRaider committed Sep 24, 2019
1 parent 335db83 commit a45390c
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 95 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Allows you to control the position and size of application windows on your Windo

**Author's website and contact information:** [https://barraider.github.io](https://barraider.github.io)

## New in v1.8.1
- `Only Make Topmost` feature allows moving an application to top, without moving or resizing it. Useful along with SuperMacro to send key-presses in a Multi-Action.
## New in v1.9
- Instead of choosing a specific application, you can now choose to manipulate the current focused window. This allows you to "snap"/"resize" the current focused app to various areas on the screen.

## Features
- Multi-Screen support, move applications across multiple screens
Expand All @@ -18,6 +18,7 @@ Allows you to control the position and size of application windows on your Windo
- `Make Topmost `feature will attempt to make the window pop up to the front of the screen
- `Location Filter` allows to filter processes to a specific directory
- `Title Filter` allows to filter out processes that don't have certain words in the window title. **Note:** Chrome/Firefox act weird and the titles change based on the current open tab (your mileage may vary)
- `Only Make Topmost` feature allows moving an application to top, without moving or resizing it. Useful along with [SuperMacro](https://github.com/BarRaider/streamdeck-supermacro) to send key-presses in a Multi-Action.

### Download

Expand Down
12 changes: 12 additions & 0 deletions streamdeck-windowsmover/PropertyInspector/WindowsMover.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ function checkResize(payload) {
setHeightWidthWrapper("none");
setLocationFilterWrapper("none");
setTitleFilterWrapper("none");
setApplicationChooser("none");

if (payload['resizeWindow']) {
setHeightWidthWrapper("");
}
Expand All @@ -34,7 +36,10 @@ function checkResize(payload) {

if (payload['filterTitle']) {
setTitleFilterWrapper("");
}

if (payload['appSpecific']) {
setApplicationChooser("");
}
}

Expand All @@ -55,6 +60,13 @@ function setTitleFilterWrapper(displayValue) {
dvTitle.style.display = displayValue;
}

function setApplicationChooser(displayValue) {
var dvAppSpecific = document.getElementById('dvAppSpecific');
var dvAppFilters = document.getElementById('dvAppFilters');
dvAppSpecific.style.display = displayValue;
dvAppFilters.style.display = displayValue;
}

function getWindowDetails() {
var payload = {};
payload.property_inspector = 'getWindowDetails';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,34 @@
<body>
<div class="sdpi-wrapper">
<details class="message">
<summary>For feedback/suggestions contact me at <span class="linkspan" onclick="openWebsite()">https://BarRaider.github.io</span></summary>
<summary>For feedback/suggestions contact me at <span class="linkspan" onclick="openWebsite()">https://BarRaider.com</span></summary>
</details>
<div class="sdpi-item" id="dvApplications">
<div class="sdpi-item-label">Application</div>
<select class="sdpi-item-value select sdProperty sdList" id="applications" oninput="setSettings()" sdListTextProperty="name" sdListValueProperty="name" sdValueField="applicationName"></select>
</div>
<details class="message">
<summary>Note: Only applications that are currently running are shown in the list above.</summary>
<summary>Note: "Current Focused" will pick the window that is focused when the button is pressed</summary>
</details>
<div type="radio" class="sdpi-item" id="rdWindowResize">
<div class="sdpi-item-label">Application</div>
<div class="sdpi-item-value ">

<div class="sdpi-item-child">
<input id="appCurrent" class="sdProperty sdCheckbox" type="radio" name="rdApplication" checked oninput="setSettings()">
<label for="appCurrent" class="sdpi-item-label"><span></span>Current Focused Window</label>
</div>
<div class="sdpi-item-child">
<input id="appSpecific" class="sdProperty sdCheckbox" type="radio" name="rdApplication" oninput="setSettings()">
<label for="appSpecific" class="sdpi-item-label"><span></span>Specific Application</label>
</div>
</div>
</div>
<div id="dvAppSpecific">
<div class="sdpi-item" id="dvApplications">
<div class="sdpi-item-label">App Name</div>
<select class="sdpi-item-value select sdProperty sdList" id="applications" oninput="setSettings()" sdListTextProperty="name" sdListValueProperty="name" sdValueField="applicationName"></select>
</div>
<details class="message">
<summary>Note: Only applications that are currently running are shown in the list above.</summary>
</details>
</div>
<div class="sdpi-item" id="dvScreens">
<div class="sdpi-item-label">Screen</div>
<select class="sdpi-item-value select sdProperty sdList" id="screens" oninput="setSettings()" sdListTextProperty="name" sdListValueProperty="device" sdValueField="screen"></select>
Expand Down Expand Up @@ -85,27 +104,29 @@
<label for="topmostWindow" class="sdpi-item-label"><span></span>Make window topmost</label>
</div>
</div>
<div type="checkbox" class="sdpi-item">
<div class="sdpi-item-label">Location Filter</div>
<div class="sdpi-item-value">
<input id="filterLocation" type="checkbox" value="" class="sdProperty sdCheckbox" oninput="setSettings()">
<label for="filterLocation" class="sdpi-item-label"><span></span>Only exe in a specific folder</label>
<div id="dvAppFilters">
<div type="checkbox" class="sdpi-item">
<div class="sdpi-item-label">Location Filter</div>
<div class="sdpi-item-value">
<input id="filterLocation" type="checkbox" value="" class="sdProperty sdCheckbox" oninput="setSettings()">
<label for="filterLocation" class="sdpi-item-label"><span></span>Only exe in a specific folder</label>
</div>
</div>
</div>
<div class="sdpi-item" id="dvLocationFilter">
<div class="sdpi-item-label">Location Filter</div>
<input class="sdpi-item-value sdProperty" placeholder="c:\program files\firefox" value="" id="locationFilter" oninput="setSettings()">
</div>
<div type="checkbox" class="sdpi-item">
<div class="sdpi-item-label">Title Filter</div>
<div class="sdpi-item-value">
<input id="filterTitle" type="checkbox" value="" class="sdProperty sdCheckbox" oninput="setSettings()">
<label for="filterTitle" class="sdpi-item-label"><span></span>Filter title with specifc text</label>
<div class="sdpi-item" id="dvLocationFilter">
<div class="sdpi-item-label">Location Filter</div>
<input class="sdpi-item-value sdProperty" placeholder="c:\program files\firefox" value="" id="locationFilter" oninput="setSettings()">
</div>
<div type="checkbox" class="sdpi-item">
<div class="sdpi-item-label">Title Filter</div>
<div class="sdpi-item-value">
<input id="filterTitle" type="checkbox" value="" class="sdProperty sdCheckbox" oninput="setSettings()">
<label for="filterTitle" class="sdpi-item-label"><span></span>Filter title with specifc text</label>
</div>
</div>
<div class="sdpi-item" id="dvTitleFilter">
<div class="sdpi-item-label">Title Filter</div>
<input class="sdpi-item-value sdProperty" placeholder="Google" value="" id="titleFilter" oninput="setSettings()">
</div>
</div>
<div class="sdpi-item" id="dvTitleFilter">
<div class="sdpi-item-label">Title Filter</div>
<input class="sdpi-item-value sdProperty" placeholder="Google" value="" id="titleFilter" oninput="setSettings()">
</div>
<div class="sdpi-item">
<div class="sdpi-item-label">Retry Attempts</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ function openWebsite() {
const json = {
'event': 'openUrl',
'payload': {
'url': 'https://BarRaider.github.io'
'url': 'https://BarRaider.com'
}
};
websocket.send(JSON.stringify(json));
Expand Down
131 changes: 72 additions & 59 deletions streamdeck-windowsmover/WindowPosition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ private struct RECT
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

public static int MoveProcess(MoveProcessSettings settings)
{
if (settings == null)
Expand All @@ -171,78 +174,91 @@ public static int MoveProcess(MoveProcessSettings settings)
}

Logger.Instance.LogMessage(TracingLevel.INFO, $"Changing window position for: {settings.ToString()}");
int totalProcesses = 0;
int movedProcesses = 0;
foreach (var process in System.Diagnostics.Process.GetProcessesByName(settings.Name))
if (!settings.AppSpecific)
{
try
ManipulateWindow(GetForegroundWindow(), settings, width, height, flags);
return 1;
}
else
{
int totalProcesses = 0;
int movedProcesses = 0;
foreach (var process in System.Diagnostics.Process.GetProcessesByName(settings.Name))
{
totalProcesses++;
IntPtr h1 = process.MainWindowHandle;
if (h1.ToInt32() == 0)
try
{
continue;
}
Logger.Instance.LogMessage(TracingLevel.INFO, $"Found {settings.Name} with handle {h1}");
totalProcesses++;
IntPtr h1 = process.MainWindowHandle;
if (h1.ToInt32() == 0)
{
continue;
}
Logger.Instance.LogMessage(TracingLevel.INFO, $"Found {settings.Name} with handle {h1}");

if (!String.IsNullOrEmpty(settings.LocationFilter) && !process.MainModule.FileName.ToLowerInvariant().Contains(settings.LocationFilter.ToLowerInvariant()))
{
Logger.Instance.LogMessage(TracingLevel.INFO, $"Skipped {settings.Name} with handle {h1} as the file location was different from \"{settings.LocationFilter}\": {process.MainModule.FileName}");
continue;
}
if (!String.IsNullOrEmpty(settings.LocationFilter) && !process.MainModule.FileName.ToLowerInvariant().Contains(settings.LocationFilter.ToLowerInvariant()))
{
Logger.Instance.LogMessage(TracingLevel.INFO, $"Skipped {settings.Name} with handle {h1} as the file location was different from \"{settings.LocationFilter}\": {process.MainModule.FileName}");
continue;
}

if (!String.IsNullOrEmpty(settings.TitleFilter) && !process.MainWindowTitle.Contains(settings.TitleFilter))
{
Logger.Instance.LogMessage(TracingLevel.INFO, $"Skipped {settings.Name} with handle {h1} as the window title was different from \"{settings.TitleFilter}\": {process.MainWindowTitle}");
continue;
}
if (!String.IsNullOrEmpty(settings.TitleFilter) && !process.MainWindowTitle.Contains(settings.TitleFilter))
{
Logger.Instance.LogMessage(TracingLevel.INFO, $"Skipped {settings.Name} with handle {h1} as the window title was different from \"{settings.TitleFilter}\": {process.MainWindowTitle}");
continue;
}
movedProcesses++;

movedProcesses++;
// Needed to support multi-maximize clicks
if (settings.WindowResize != WindowResize.Minimize)
{
ShowWindow(h1, ShowWindowEnum.SHOWNORMAL);
ManipulateWindow(h1, settings, width, height, flags);
}

// Do not change window position or location in the "OnlyTopmost" setting is set
if (settings.WindowResize != WindowResize.OnlyTopmost)
catch (Exception ex)
{
// Resize and move window
SetWindowPos(h1, new IntPtr(0), settings.DestinationScreen.WorkingArea.X + settings.Position.X, settings.DestinationScreen.WorkingArea.Y + settings.Position.Y, width, height, flags);
Logger.Instance.LogMessage(TracingLevel.ERROR, $"Error setting window for process {settings.Name} {ex}");
}
}
Logger.Instance.LogMessage(TracingLevel.INFO, $"Iterated through {totalProcesses} processes, moved {movedProcesses}");

if (settings.WindowResize == WindowResize.Maximize)
{
// Maximize the window.
ShowWindow(h1, ShowWindowEnum.SHOWMAXIMIZED);
}
else if (settings.WindowResize == WindowResize.Minimize)
{
// Minimize the window.
ShowWindow(h1, ShowWindowEnum.MINIMIZE);
}
SetForegroundWindow(h1);
return movedProcesses;
}
}

if (settings.MakeTopmost)
{
try
{
TryForceForegroundWindow(h1);
}
catch (Exception ex)
{
Logger.Instance.LogMessage(TracingLevel.WARN, $"Failed to make topmost {settings.Name} {ex}");
}
}
private static void ManipulateWindow(IntPtr windowHandle, MoveProcessSettings settings, int width, int height, SetWindowPosFlags flags)
{
// Needed to support multi-maximize clicks
if (settings.WindowResize != WindowResize.Minimize)
{
ShowWindow(windowHandle, ShowWindowEnum.SHOWNORMAL);
}

// Do not change window position or location in the "OnlyTopmost" setting is set
if (settings.WindowResize != WindowResize.OnlyTopmost)
{
// Resize and move window
SetWindowPos(windowHandle, new IntPtr(0), settings.DestinationScreen.WorkingArea.X + settings.Position.X, settings.DestinationScreen.WorkingArea.Y + settings.Position.Y, width, height, flags);
}

if (settings.WindowResize == WindowResize.Maximize)
{
// Maximize the window.
ShowWindow(windowHandle, ShowWindowEnum.SHOWMAXIMIZED);
}
else if (settings.WindowResize == WindowResize.Minimize)
{
// Minimize the window.
ShowWindow(windowHandle, ShowWindowEnum.MINIMIZE);
}
SetForegroundWindow(windowHandle);

if (settings.MakeTopmost)
{
try
{
TryForceForegroundWindow(windowHandle);
}
catch (Exception ex)
{
Logger.Instance.LogMessage(TracingLevel.ERROR, $"Error setting window for process {settings.Name} {ex}");
Logger.Instance.LogMessage(TracingLevel.WARN, $"Failed to make topmost {settings.Name} {ex}");
}
}
Logger.Instance.LogMessage(TracingLevel.INFO, $"Iterated through {totalProcesses} processes, moved {movedProcesses}");

return movedProcesses;
}

public static Rectangle GetWindowPostion(string processName)
Expand Down Expand Up @@ -282,9 +298,6 @@ public static Rectangle GetWindowPostion(string processName)
[DllImport("user32.dll")]
static extern bool AllowSetForegroundWindow(int dwProcessId);

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

Expand Down
2 changes: 1 addition & 1 deletion streamdeck-windowsmover/WindowsMover.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.6.6\lib\net45\NLog.dll</HintPath>
<HintPath>..\..\..\DotNet\StreamDeck\packages\NLog.4.6.7\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="streamdeck-client-csharp, Version=4.1.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\streamdeck-client-csharp.4.1.1\lib\netstandard2.0\streamdeck-client-csharp.dll</HintPath>
Expand Down
Loading

0 comments on commit a45390c

Please sign in to comment.