Skip to content

Commit

Permalink
Create header, add installer and disallow multiple instances
Browse files Browse the repository at this point in the history
  • Loading branch information
alvesvaren committed Oct 6, 2024
1 parent f2cd7e0 commit b9774f9
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 67 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,7 @@ MigrationBackup/
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd

# Inno Setup Output folder
Output/
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,39 @@
Rewrite of https://github.com/IsacEkeroth/ahk-resize-windows in C++

## Installation:
1. Download the latest version from https://github.com/alvesvaren/resizer2/releases/
2. Move the program to somewhere other than your downloads
3. Start the .exe file, and allow it in smartscreen if it pops up
4. Follow the instructions under "Autostarting"

1. Download the latest version of the installer from https://github.com/alvesvaren/resizer2/releases/
2. Run the installer

> The program is also available as a portable .exe file, which can be ran without installation<br>
> However, autostarting is not automatically set up unless you use the installer
## Uninstalling:

You should be able to uninstall it using the built in uninstallation feature in windows. You will need to close the app before proceeding (in the system tray)

## How to use:

- Win + Left Mouse Button to move windows. If a window is fullscreened or maximized, it will snap between monitors
- Win + Right Mouse Button to resize windows from the closest corner
- Win + Scroll Up/Down to change window opacity
- Win + Middle mouse to minimize a window
- Win + Double click Left Mouse Button to maximize/restore a window

## Extra features:

- Changes the system cursors to reflect what's happening
- Can be closed from the system tray

## Quirks:

- When you normally press Win, the start menu appears, unless you pressed a keyboard shortcut using it.
So to keep it from appearing, it fakes the combination Win+F13, which usually doesn't do anything.
However, if you have any hotkeys using F13, you might need to change them or change the key used in this program.
- Some fullscreen apps really doesn't like being moved to another monitor, so be careful moving fullscreened windows.
- You can change opacity and move some system bars right now, for example move/resize taskbars on other screens.
If you accidentally did that, you can restart explorer.exe from task manager and it should fix it.
- Running multiple instances of the program at the same time is not supported and may break stuff.

## Autostarting:
1. Open the "Task Scheduler"
2. Click "Create Basic Task..."
3. Give the task a cool name and press next
4. Set trigger to "When I log on"
5. Keep action at "Start a program"
6. Select the exe file in "Program/script", preferably move the file out from your downloads first
7. Finish creating the task
8. Restart your computer to see if it works

When installing using the setup program, you can choose to enable autostarting
58 changes: 58 additions & 0 deletions installer.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppName "Resizer 2"
#define MyAppVersion "4"
#define MyAppPublisher "Alve Svarén"
#define MyAppURL "https://github.com/alvesvaren/resizer2"
#define MyAppExeName "resizer2.exe"

[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{3C32B837-6368-48A2-A026-F0EB8B1E6311}
AppName={#MyAppName}
AppVerName={#MyAppName} v{#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf}\Resizer2
; "ArchitecturesAllowed=x64compatible" specifies that Setup cannot run
; on anything but x64 and Windows 11 on Arm.
ArchitecturesAllowed=x64compatible
; "ArchitecturesInstallIn64BitMode=x64compatible" requests that the
; install be done in "64-bit mode" on x64 or Windows 11 on Arm,
; meaning it should use the native 64-bit Program Files directory and
; the 64-bit view of the registry.
ArchitecturesInstallIn64BitMode=x64compatible
DefaultGroupName={#MyAppName}
AppMutex=Resizer2Mutex
AllowNoIcons=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
;PrivilegesRequired=lowest
OutputBaseFilename=resizer2-setup
Compression=lzma
SolidCompression=yes
WizardStyle=modern

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

[Tasks]
Name: "autostart"; Description: "Start Resizer 2 (as administrator) automatically with Windows"; GroupDescription: "Other Tasks";

[Files]
Source: "C:\Users\alve\source\repos\resizer2\x64\Release\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"

[Run]
Filename: "schtasks"; Parameters: "/Delete /TN ""Resizer2"" /F"; Flags: runhidden;
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent runascurrentuser
Filename: "schtasks"; Parameters: "/Create /TN ""Resizer2"" /TR ""\""{app}\{#MyAppExeName}""\"" /SC ONLOGON /RL HIGHEST"; Flags: runhidden; Tasks: autostart

[UninstallRun]
Filename: "schtasks"; Parameters: "/Delete /TN ""Resizer2"" /F"; Flags: runhidden; RunOnceId: "autostart-task-remove"

61 changes: 8 additions & 53 deletions resizer2/resizer2.cpp
Original file line number Diff line number Diff line change
@@ -1,46 +1,5 @@
#define OEMRESOURCE
#include <windows.h>
#include <iostream>
#include <chrono>

#pragma comment(lib, "user32.lib")

#define TRAY_ICON_UID 1001
#define WM_TRAYICON (WM_USER + 1)


// Config
const int DOUBLE_CLICK_THRESHOLD = 300; // ms
const BYTE MIN_OPACITY = 64;
const BYTE MAX_OPACITY = 255;
const BYTE OPACITY_STEP = 26; // Around 10% of 255
const int DUMMY_KEY = VK_F13; // Any key that doesn't do anything when pressed together with the Windows key

enum ContextType {
MOVE,
RESIZE
};

struct Context {
bool inProgress = false;
HANDLE hEvent = NULL;
POINT startMousePos;
RECT startWindowRect;
HWND targetWindow = NULL;
ContextType operationType;
};

struct MonitorSearchData {
int x, y;
HMONITOR hMonitor;
};

enum ResizerCursor {
SIZEALL,
SIZENWSE,
SIZENESW,
UNSET,
};
#include "resizer2.h"

const int systemCursors[] = {
OCR_NORMAL,
Expand All @@ -67,17 +26,6 @@ bool shouldMinimize = false;
std::chrono::steady_clock::time_point lastClickTime;
NOTIFYICONDATA nid;

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
DWORD WINAPI WindowOperationThreadProc(LPVOID lpParam);

void adjustWindowOpacity(int change);

void minimizeWindow();
template <ContextType type>
void startWindowOperation();
void stopWindowOperation();

static HWND getTopLevelParent(HWND hwnd) {
HWND parent = hwnd;
HWND tmp;
Expand Down Expand Up @@ -208,6 +156,13 @@ static HMONITOR SysGetMonitorContainingPoint(int x, int y) {
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
const wchar_t CLASS_NAME[] = L"TrayIconWindowClass";

// Both for the uninstaller, and to prevent multiple instances
HANDLE hMutexHandle = CreateMutex(NULL, FALSE, L"Resizer2Mutex");
if (GetLastError() == ERROR_ALREADY_EXISTS) {
MessageBox(NULL, L"Resizer is already running!", L"Resizer", MB_ICONINFORMATION | MB_OK);
return 0;
}

WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
Expand Down
74 changes: 74 additions & 0 deletions resizer2/resizer2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once

#include <windows.h>
#include <iostream>
#include <chrono>

#pragma comment(lib, "user32.lib")

#define TRAY_ICON_UID 1001
#define WM_TRAYICON (WM_USER + 1)

// Config
const int DOUBLE_CLICK_THRESHOLD = 300; // ms
const BYTE MIN_OPACITY = 64;
const BYTE MAX_OPACITY = 255;
const BYTE OPACITY_STEP = 26; // Around 10% of 255
const int DUMMY_KEY = VK_F13; // Any key that doesn't do anything when pressed together with the Windows key

enum ContextType {
MOVE,
RESIZE
};

struct Context {
bool inProgress = false;
HANDLE hEvent = NULL;
POINT startMousePos{};
RECT startWindowRect{};
HWND targetWindow = NULL;
ContextType operationType;
};

struct MonitorSearchData {
int x, y;
HMONITOR hMonitor;
};

enum ResizerCursor {
SIZEALL,
SIZENWSE,
SIZENESW,
UNSET,
};

// Declarations
extern const int systemCursors[];

extern Context ctx;
extern HHOOK hKeyboardHook;
extern HHOOK hMouseHook;
extern bool modKeyPressed;
extern bool didUseWindowsKey;
extern bool shouldMinimize;
extern std::chrono::steady_clock::time_point lastClickTime;
extern NOTIFYICONDATA nid;

LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
DWORD WINAPI WindowOperationThreadProc(LPVOID lpParam);

void adjustWindowOpacity(int change);
void minimizeWindow();
template <ContextType type>
void startWindowOperation();
void stopWindowOperation();
HWND getTopLevelParent(HWND hwnd);
void snapToMonitor(HWND window, HMONITOR screen);
template <ResizerCursor cursor>
void SetGlobalCursor();
void AddTrayIcon(HWND hWnd);
void RemoveTrayIcon();
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
HMONITOR SysGetMonitorContainingPoint(int x, int y);
3 changes: 3 additions & 0 deletions resizer2/resizer2.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@
<ItemGroup>
<ClCompile Include="resizer2.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="resizer2.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
Expand Down
5 changes: 5 additions & 0 deletions resizer2/resizer2.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,9 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resizer2.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

0 comments on commit b9774f9

Please sign in to comment.