Skip to Content

Split Loaf Update

An Update On The Progress Of Split Loaf
4 December 2025 by
Split Loaf Update
All Things Toasty Software Ltd, Austin Welsh-Graham
| No comments yet

The development for the Split Loaf keyboard rerouter has been going surprisingly well with the pre-release of version 0.6.3 (The 63rd build attempt). The program can now be installed as an exe for windows machines creating a system tray icon to let the user know its active. By hovering over the icon should tell you the state of the program.

Split Loaf - Idle (Nothing Happening)
Split Loaf - [Window Name] (A window has been targeted)
Split Loaf - [WINDOW NAME] (The window has been locked on)

However these have not yet been implemented into the program. Additionally when right clicking it in the system tray it gives two options. Settings and Exit. 


Settings will open up a window which would allow the user to change the keybinds for the program to change how they target, lock, and unlock windows as well as enable the program to run on startup if the user would like to always have it available without needing to manually start it however these functions have not been finished yet.

The exit option does just that, it exits the app.


For the actual workings of the app, it is surprisingly good, at least good enough that I've been using it since it started working. by using the default keybinds:

F8 - Target Window
F6 - Lock Keyboard
F7 - Unlock Keyboard

I've been able to easily target and lock onto my IDE (CLion) and then move my mouse to my second display where I have about 20 different tabs on the Windows API and no matter what I'm doing, every time I use the keyboard it goes straight to the IDE, perfect for my one handed style of typing. Its also been updated to successfully manage modifier keys like Shift or Control by changing the way it handles key presses.


The initial method was:

void SendVirtualKeyToTarget(DWORD vkCode) {
​INPUT in[2] = {0};

​// Key down
​in[0].type = INPUT_KEYBOARD;
​in[0].ki.wVk = vkCode;
​in[0].ki.dwFlags = 0;

​// Key up
​in[1].type = INPUT_KEYBOARD;
​in[1].ki.wVk = vkCode;
​in[1].ki.dwFlags = KEYEVENTF_KEYUP;

​SendInput(2, in, sizeof(INPUT));}

However what this does is when ever a key is pressed down, both the down and up signal is sent, the issue with this is when you hold down a key. Normally when you hold a key down windows will periodically send a key down signal to the app, so when you hold down a, it will repeatedly send a (down) resulting in aaaaaaa, however this code will repeatedly send a (down) a (up) which still results in aaaaaaa, but is less efficient, this is key when it comes to modifier keys like Shift. When you hold down the Shift key windows detects this and activates it as a modifier and will only deactivate it when it detects shift has been pressed up, however since this code sends both, it's impossible to handle it, and so instead its been replaced with:

void WinBackend::sendVirtualKey(uint32_t vk) {
INPUT in = {0};

in.type = INPUT_KEYBOARD;
in.ki.wVk = vk;


SendInput(1, &in, sizeof(INPUT));
}

What this does instead is sends the default input method of KEY DOWN as alongside the detection function:

if (locked && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)) {
if (targetWindow) {
HWND fg = GetForegroundWindow();

if (fg != targetWindow) {

SetForegroundWindow(targetWindow);
Sleep(1);
targetHasFocus = 1;
}

WinBackend::sendVirtualKey (kbd->vkCode);

return 1;
}
}

What will happen is, whenever a key is pressed down, the program will intercept it and send the key down signal, and so if a key is held down, each time the keyboard tries to handle that and repeatedly send a down signal, it will be intercepted, and when you hold down a modifier key like Shift, it will only be set down so the OS can handle it, and then whenever a key is pressed up, the hook ignores it and just lets it run naturally so windows will send the KEYUP signal for us to deactivate the key or modifier. 

This could be handled in the program by replicating the detection code and modifying it for KEYUP and then either adding a flag to the sendVirtualKey function or creating a new function to set the key state to up however I don't think there is ever a need where we need to intercept a key being pressed up as I don't think anything ever actually cares about the key being pressed up and so although by letting Windows handle it and it might activate outside of the target window if your somehow super quick and manage to hold the key, move to a different window, and release before it repeats its signal and redirects to the target window again, I doubt this will cause any major effect


A bit more work has been done into looking into how this can be developed for Linux systems with a somewhat working test being found which uses the uInput library to create a virtual keyboard and then process signals through that, however currently that only does it based on programmed in presses like:

emit(fd, EV_KEY, KEY_SPACE, 1);
emit(fd, EV_SYN, SYN_REPORT, 0);
emit(fd, EV_KEY, KEY_SPACE, 0);
emit(fd, EV_SYN, SYN_REPORT, 0);

And it doesn't yet handle being able to target, lock, or redirect the keyboard to different windows, however when tested on Hyprland using Wayland on Arch Linux it seemed to work as by running the program and moving to a different app by adding a Sleep() function to give me the time to move, it send a space to chrome showing it might be possible.

Although whether this will work on different distributions and display servers I'm not sure, its shown to be compile able on ubuntu-latest from GitHub and its been build able and executable on Crosinti Linux from Chromebooks however it doesn't send the space so alternate methods will likely be needed for different types of Linux.


For now, the Windows development has been going somewhat smoothly other than the many hours spent trying to understand the different features for Windows App Development with win32 API, so I will be focusing on pushing that to the final release with working settings and indicators for use.

Split Loaf Update
All Things Toasty Software Ltd, Austin Welsh-Graham 4 December 2025
Share this post
Archive
Sign in to leave a comment