Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ jobs:
if: steps.src_changes.outputs.has_src_changes == 'true'
uses: actions/upload-artifact@v4
with:
name: be-there-dev-${{ github.sha }}
name: harken-dev-${{ github.sha }}
path: |
dist\be-there-source-dev.zip
dist\be-there-dev-win64.zip
dist\be-there.exe
dist\harken-source-dev.zip
dist\harken.exe
5 changes: 2 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,5 @@ jobs:
tag_name: ${{ env.VERSION }}
prerelease: ${{ env.PRERELEASE }}
files: |
dist/be-there-source-${{ env.VERSION }}.zip
dist/be-there-${{ env.VERSION }}-win64.zip
dist/be-there.exe
dist/harken-source-${{ env.VERSION }}.zip
dist/harken.exe
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
PLAN.md
config/config.json
config/harken.toml
dist/
ahk/
*_PLAN.md
52 changes: 39 additions & 13 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ No Cursor rules found in `.cursor/rules/` or `.cursorrules`.
No Copilot instructions found in `.github/copilot-instructions.md`.

## Quick Context
- Entry point: `be-there.ahk`.
- Entry point: `harken.ahk`.
- Source modules: `src/` (hotkeys, window management, UI helpers, config loader).
- Tools: `tools/` (build script, inspector utilities).
- Config example: `config/config.example.json` (user config lives outside the repo).
- Config example: `config/config.example.toml` (user config lives outside the repo).

## Build / Lint / Test
This repo does not currently use a formal test or lint framework.
Expand All @@ -25,13 +25,18 @@ Dev build (CI):
- GitHub Actions runs `tools/build_release.ps1 -Version dev` on `main`/`dev` when `src/` changes.

Single test / focused run:
- No unit test runner exists. Use manual verification steps (launch `be-there.ahk`, validate
- No unit test runner exists. Use manual verification steps (launch `harken.ahk`, validate
hotkeys, reload flow, and Command Overlay) or run targeted helper tools in `tools/`.
- Focused validation (pick relevant items):
- Launch `harken.ahk` with a clean config and verify: super hotkeys, window cycling, overlay.
- If virtual desktops touched: test `super+alt+h/l`, mapped desktop hotkeys, and tray indicator.

## Code Style Guidelines
### AutoHotkey version and file headers
- Use AutoHotkey v2 syntax and conventions.
- Keep `#Requires AutoHotkey v2.0` in entry points and new top-level scripts.
- Virtual desktop integration requires AutoHotkey v2.1 alpha (VD.ahk dependency).
- Keep `#Requires AutoHotkey v2.0` in entry points and new top-level scripts unless a file
specifically requires v2.1 alpha features.
- Keep `#Include` statements at the top and ordered by dependency.

### Formatting
Expand All @@ -55,32 +60,40 @@ Single test / focused run:
### Imports and module structure
- Keep modules focused by domain (hotkeys, window management, utilities).
- Avoid circular dependencies; shared helpers should live in `src/lib/`.
- `be-there.ahk` should remain the only top-level orchestrator.
- `harken.ahk` should remain the only top-level orchestrator.

### Error handling
- Use `try`/`catch` for file IO and JSON parsing; return structured errors where possible.
- Use clear, user-facing error messages for missing dependencies or invalid config.
- For config validation, return error arrays and handle them in the entry point.
- Avoid throwing for normal control flow.
- Guard `WinGetID("A")` calls when no active window is possible (use `try`/`catch`).

### Config handling
- Keep user configuration separate from core behavior.
- Do not edit or delete user config without backup.
- Validate config with schema before registering hotkeys.
- When adding config keys, update:
- `DefaultConfig()` in `be-there.ahk`
- `DefaultConfig()` in `harken.ahk`
- Schema in `src/lib/config_loader.ahk`
- `config/config.example.json`
- `config/config.example.toml`
- `README.md`
- If adding virtual desktop hotkeys:
- Normalize new config formats in `NormalizeVirtualDesktopConfig`.
- Update debug logs and config validation for duplicate hotkeys.

### Hotkeys and window behavior
- Keep hotkey registration centralized under `src/hotkeys/`.
- Avoid direct global state unless required; prefer explicit `global` declarations when needed.
- For window manipulation, consider edge cases with elevated windows and multiple monitors.
- Be careful with modifier ordering: use `HotIf` guards and wildcard hotkeys when needed.

### UI helpers
- GUI helpers (overlays, inspectors) should remain non-blocking and lightweight.
- Prefer explicit refresh actions instead of continuous loops when possible.
- Command overlay behavior:
- Normal mode: `super + /` shows temporary overlay; any key hides it.
- Command/move modes: overlay stays visible and is centered on screen.

### Third-party code
- Keep third-party code in `src/lib/` and document licensing in `LICENSES/`.
Expand All @@ -94,24 +107,37 @@ Single test / focused run:
- Keep `README.md` and `AGENTS.md` aligned with current behavior.

## Suggested Manual Checks
- Launch `be-there.ahk` with a clean `config.json` and verify hotkeys.
- Launch `harken.ahk` with a clean `harken.toml` and verify hotkeys.
- Validate reload flow (normal hotkey and command mode).
- Confirm Command Overlay and helper tools still open and update.
- If touching config schema, ensure errors log correctly in `~/.config/be-there/config.errors.log`.
- If touching config schema, ensure errors log correctly in `%APPDATA%\harken\config.errors.log`.
- If touching tray indicator: confirm tray icon updates on desktop change.
- If touching cycling: verify `super+c` (all desktops) and `super+shift+c` (current desktop).

## Paths and Layout Notes
- Main script: `be-there.ahk`.
- Main script: `harken.ahk`.
- Config loader: `src/lib/config_loader.ahk` (schema + validation).
- JSON parsing: `src/lib/JXON.ahk`.
- Window manager: `src/lib/window_manager.ahk`.
- Hotkeys: `src/hotkeys/*.ahk`.
- Virtual desktop helpers: `src/lib/virtual_desktop.ahk` + `src/lib/VD.ahk`.

## Build Artifacts
- `dist/be-there.exe`
- `dist/be-there-source-<version>.zip`
- `dist/be-there-<version>-win64.zip`
- `dist/harken.exe`
- `dist/harken-source-<version>.zip`
- `dist/harken-<version>-win64.zip`

## When In Doubt
- Keep behavior consistent with existing hotkeys and overlays.
- Document any new public functions or configuration keys.
- Favor explicitness over cleverness.

## Recent Project-Specific Notes
- Debug logs:
- `virtual_desktop.debug_cycle` writes `%APPDATA%\harken\cycle.debug.log`.
- `virtual_desktop.debug_hotkeys` writes `%APPDATA%\harken\vd.hotkeys.log` and `vd.actions.log`.
- Logs reset on startup when debug flags are enabled.
- Tray indicator:
- `virtual_desktop.tray_indicator` draws `{current}/{total}` on the existing tray icon.
- Tooltip uses `virtual_desktop.tray_format`.
- Window cycling across desktops uses a cache to include off-desktop windows.
21 changes: 21 additions & 0 deletions LICENSES/VD.ahk-LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2021 [Fu Pei Jiang](https://github.com/FuPeiJiang)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
135 changes: 104 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# be-there
# Harken
A window manager written in AutoHotkey v2.

The aim is a low-friction workflow: a single super modifier, mnemonic app keys, and fast window actions. Alt+Tab and Win+Tab still work, but you will hardly use them.
Harken allows a keyboard-centered workflow on Windows: a single super modifier, mnemonic app keys, and fast window actions. Alt+Tab and Win+Tab still work, but you will hardly use them.

## Contents
- [Overview](#overview)
Expand All @@ -24,6 +24,20 @@ The aim is a low-friction workflow: a single super modifier, mnemonic app keys,

### Features

- Launch-or-focus your most common programs with the hotkeys you assign in your config file.
- Focused tile includes border highlight that can be customized, including per app, window class, or window title.
- Snap tiles to grid and cycle through various positions with subsequent key presses.
- Freely move tiles with your keyboard.
- Resize tiles and their edges with your keyboard.
- Directional focus changes with vim-like motions.
- Cycle stacked tiles with `super + [` and `super + ]`.
- Cycle focus between tiles of the same program with `super + c`.
- Show a hotkey menu with `super + /`.
- Virtual desktops (native)
- Navigate between desktops with better hotkeys
- Assign custom hotkeys for the index-based virtual desktops.



Launch-or-focus a program with `super + [letter]`, or directionally change window focus with `alt + h/l/j/k` (left, right, down, up) and `alt + [` / `alt + ]` for back/forward in a stack.
![Alt text](docs/assets/focus.gif)
Expand Down Expand Up @@ -52,10 +66,15 @@ Use the "window switcher" (like powertoys window walker) with `super + w`.
Other
- `super + alt` sends `ctrl + tab` (configurable via `global_hotkeys`)
- `super + c` cycle through windows of the same app
- `super + shift + c` cycle through windows of the same app on the current desktop
- `super + alt + h/l` switch to previous/next virtual desktop
- `super + alt + shift + h/l` move the active window to previous/next desktop (follow)
- `super + w` open Window Selector (fuzzy find open windows)
- `alt + h/l` move window focus left/right
- `alt + j/k` move window focus down/up (non-stacked)
- `alt + [` / `alt + ]` move window focus forward/back through stacked windows
- `super + alt + h/l` to move between desktops
- `super + shift + alt + h/l` send current tile to adjacent desktop

Enter Command Mode with `super + ;`.
- `r` to reload program/config
Expand All @@ -64,62 +83,116 @@ Enter Command Mode with `super + ;`.
- `n` toggles the command overlay on or off
- `i` opens the [Helper Utility](#helper-utility)

## TODO

- Clarify and work on areas of state
- saving layouts
- per app configs determining where things go (virtual desktop destination is supported now)
- Possibly rework the config schema. It's hectic.


## Configuration

### Quick start

- Start the program and enter command mode with `super + ;`. The binary is not currently signed and you will be warned by Windows. Clone and use `main.ahk` directly as an alternative.
- Press `e` to open the config file. You can also find it manually in `~/.config/be-there/config.json`.
- If not using the binary, make sure to install AutoHotKey 2.1-alpha18 or newer.
- Start the program and enter command mode with `super + ;`. The binary is not currently signed and you will be warned by Windows. Clone and use `harken.ahk` directly as an alternative.
- The program might fail on first run? Probably something to do with the config. For now you can create the config first to _maybe_ avoid the initial-crash scenario.
- Press `e` to open the config file. You can also find it manually in `~/.config/harken/harken.toml` as it will be created on first run.
- After making changes to your config you can reload the config (the entire program, actually) with `r` while in command mode.

### Default Config Keys
- `super_key`: key or modifier chord used as the super modifier (e.g., `CapsLock`, `Ctrl+Shift+Alt`).
- `apps`: list of app bindings with `hotkey`, `win_title`, and `run` command.
- `apps[].run_paths`: optional list of directories to search for the executable.
- `global_hotkeys`: array of scoped hotkey bindings (set `target_exes` empty for global use).
- `window`: resize/move steps and hotkeys (including move mode).
- `window_selector`: Window Selector settings (hotkey, match fields, display limits).
- `window_manager`: grid size, margins, gaps, and ignored window classes.
- `directional_focus`: directional focus settings (stacked threshold, stack tolerance, topmost preference, last-stacked preference, frontmost guard, perpendicular overlap min, cross-monitor, debug).
- `focus_border`: overlay appearance and update interval.
- `helper`: command overlay settings.
- `reload`: hotkey and file watch settings for config reload.

### Window Matching
- `apps[].win_title` accepts standard AutoHotkey window selectors.
- Common forms: plain title text, `ahk_exe <exe>`, `ahk_class <class>`, `ahk_pid <pid>`.
- Use `ahk_exe` for stable matching when window titles change (e.g., tabs/documents).
- Plain title text supports AutoHotkey's standard title matching and wildcards (e.g., `* - Notepad`).
- `ahk_exe`, `ahk_class`, and `ahk_pid` are exact matches; wildcards/regex are not supported today but could be added later.

### Path Expansion
- `apps[].run_paths` supports environment variables like `%APPDATA%` and `%LOCALAPPDATA%`.
- `~\` expands to your user profile (e.g., `~\AppData\Roaming`).
### All default keybindings

#### Window management (Super)

| Shortcut | Action |
| --- | --- |
| `super + /` | Show command overlay (temporary) |
| `super + w` | Window selector (window walker) |
| `super + c` | Cycle app windows on current desktop |
| `super + shift + c` | Cycle app windows across desktops (not working) |
| `super + space` | Center width cycle |
| `super + m` | Maximize/un-maximize |
| `super + q` | Close window |
| `super + Left/Right/Up/Down` | Resize window and snap to grids |
| `super + shift + h/j/k/l` | Resize centered |
| `super + ctrl + h/j/k/l` | Move window |
| `super` (double tap) | Toggle move mode |

#### Window management (Move mode)

| Shortcut | Action |
| --- | --- |
| `h/j/k/l` | Move window |
| `Esc` or `super` | Exit move mode |

#### Focus navigation (Alt)

| Shortcut | Action |
| --- | --- |
| `alt + h/l` | Focus left/right |
| `alt + j/k` | Focus down/up |
| `alt + [` / `alt + ]` | Cycle stacked (prev/next) |

#### Virtual desktops

| Shortcut | Action |
| --- | --- |
| `super + alt + h/l` | Previous/next desktop |
| `super + alt + shift + h/l` | Move window to previous/next desktop (follow) |
| `super + alt + <key>` | Go to mapped desktop (`[[virtual_desktop.<N>]]`) |
| `super + alt + shift + <key>` | Move window to mapped desktop (follow) |

#### Apps (defaults)

These are examples for the launch-or-focus keybindings.

| Shortcut | Action |
| --- | --- |
| `super + e` | Files (`explorer.exe`) |
| `super + v` | Editor (`Code.exe`) |
| `super + s` | Terminal (`WindowsTerminal.exe`) |
| `super + n` | Notes (`notepad++.exe`) |

#### Command mode

| Shortcut | Action |
| --- | --- |
| `super + ;` | Enter command mode |
| `r` | Reload program/config |
| `e` | Open config file |
| `w` | Open a new window for the active app |
| `n` | Toggle command overlay |
| `i` | Open window inspector |
| `Esc` | Exit command mode |


### Helper Utility
- `tools/window_inspector.ahk` lists active window titles, exe names, classes, and PIDs.
- Use it to identify values for `apps[].win_title` in your config.
- In Command Mode, press `i` to launch the window inspector.
- Use Refresh to update the list; Copy Selected/All or Export to save results.

## Known Limitations
## Limitations
- This has not been tested with multi-monitor setups or much outside of ultra-wide monitors.
- Virtual desktop integration requires AutoHotkey v2.1-alpha-18 or later.
- Some apps (e.g., Discord) launch via `Update.exe` and keep versioned subfolders, which makes auto-resolution unreliable for launching or focusing more challenging.
- For some apps that minimize or close to the system tray, it's recommended you disable that in the program. Otherwise you can try to set `apps[].run` to a stable full path (or use `run_paths`) in your config.
- Windows with elevated permissions may ignore be-there hotkeys unless be-there is run as Administrator.
- Windows with elevated permissions may ignore Harken hotkeys unless Harken is run as Administrator.

## Third-Party
- JXON (AHK v2 JSON serializer) from https://github.com/TheArkive/JXON_ahk2
- License: `LICENSES/JXON_ahk2-LICENSE.md`
- VD.ahk from https://github.com/FuPeiJiang/VD.ahk
- License: `LICENSES/VD.ahk-LICENSE.md`

## Similar tools and inspirations

For this project I was primarily inspired by what I was able to accomplish with [Raycast](https://www.raycast.com/) on macOS. Between [Karabiner](https://karabiner-elements.pqrs.org/), Raycast, and [HammerSpoon](https://www.hammerspoon.org/) one could achieve all of `be-there` and more on macOS. I needed to move back to Windows for work, and I wanted a way to use the same flow on Windows that I had become accustomed to on macOS.
For this project I was primarily inspired by what I was able to accomplish with [Raycast](https://www.raycast.com/) on macOS. Between [Karabiner](https://karabiner-elements.pqrs.org/), Raycast, and [HammerSpoon](https://www.hammerspoon.org/) one could achieve all of Harken and more on macOS. I needed to move back to windows for work, and I wanted a way to use the same flow on Windows that I had become accustomed to on macOS.

Other macOS tools that I tried for more than five minutes were [AeroSpace](https://github.com/nikitabobko/AeroSpace) and [Loop](https://github.com/MrKai77/Loop).

The foundation of be-there was built upon [this reddit post](https://old.reddit.com/r/AutoHotkey/comments/17qv594/window_management_tool/), shared by u/CrashKZ -- Thanks to [/u/plankoe](https://old.reddit.com/user/plankoe) for the pieces they shared, too.
The foundation of Harken was built upon [this reddit post](https://old.reddit.com/r/AutoHotkey/comments/17qv594/window_management_tool/), shared by u/CrashKZ -- Thanks to [/u/plankoe](https://old.reddit.com/user/plankoe) for their initial contributions, too.

### [FancyZones](https://learn.microsoft.com/en-us/windows/powertoys/fancyzones)

Expand Down
Loading