Keyboard Tiler

Window Tiling Script

Keyboard Tiler is a simple script which given 2 keys on your keyboard, maps a window to the screen using the keyboard grid as referent.

On a keyboard, the keys from 1 down to Z over to /, and up to 0 form a 4x10 grid. Given the 40 tiles on your keyboard, keyboard tiler maps the visual space of your screen to the grid of your keyboard.

1 2 3 4 5 6 7 8 9 0
Q W E R T Y U I O P
A S D F G H J K L ;
Z X C V B N M < > /

So in the above example, hitting 1 and B would place and resize a window to occupy the entire left half your screen because that's the left half of your keyboard. This works for any two keys. My intention was to create an obvious and intuitive mental model for keyboard-driven window management.

I scripted around xdotool so I could focus on the logic of processing the two points and positioning the window on the screen rather than building out a full window manager. The entire script works to calculate the variables used, ultimatly pushing to xdotool as:

%x[xdotool getactivewindow windowmove --sync #{startX} #{decorationsHeight + startY}]
%x[xdotool getactivewindow windowsize --sync #{newWidth} #{newHeight - (decorationsHeight * 2)}]

Providing keybindings is another task separate from the logic of my key processing script. For the keybindings my first thought was to use xchainkeys. This way I could have emacs style key chording for pressing two keys in positioning. To generate the keybindings for xchainkeys, I created the logic to generate all permutations for any two keys on the grid being pressed:

$tiles = [
    [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' ],
    [ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p' ],
    [ 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';' ],
    [ 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/' ]
]

def crawl(s)
    $tiles.each_with_index do |row, column|
        row.each_with_index do |cell, count|    
            # This is 1 Permutation! 
            # This will be hit 1560 times!
        end
    end
end

$tiles.each_with_index do |row, column|
    row.each_with_index do |cell, count|
        crawl(cell)
    end
end

You can also use this script with Dmenu if your handy with pipes and the only disadvantage over xbindkeys is you have to hit enter after your two keys. An example of how to setup Dmenu can be found in the project's README.