Posts in category linux

LDraw Parts Library 2024-01 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2024-01 parts library for Fedora 39 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202401-ec1.fc39.src.rpm

ldraw_parts-202401-ec1.fc39.noarch.rpm
ldraw_parts-creativecommons-202401-ec1.fc39.noarch.rpm
ldraw_parts-models-202401-ec1.fc39.noarch.rpm

See also LDrawPartsLibrary.

LDraw Parts Library 2023-07 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2023-07 parts library for Fedora 39 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202307-ec1.fc39.src.rpm

ldraw_parts-202307-ec1.fc39.noarch.rpm
ldraw_parts-creativecommons-202307-ec1.fc39.noarch.rpm
ldraw_parts-models-202307-ec1.fc39.noarch.rpm

See also LDrawPartsLibrary.

LDraw Parts Library 2023-06 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2023-06 parts library for Fedora 38 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202306-ec1.fc38.src.rpm

ldraw_parts-202306-ec1.fc38.noarch.rpm
ldraw_parts-creativecommons-202306-ec1.fc38.noarch.rpm
ldraw_parts-models-202306-ec1.fc38.noarch.rpm

See also LDrawPartsLibrary.

LDraw Parts Library 2023-03 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2023-03 parts library for Fedora 36 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202303-ec1.fc36.src.rpm

ldraw_parts-202303-ec1.fc36.noarch.rpm
ldraw_parts-creativecommons-202303-ec1.fc36.noarch.rpm
ldraw_parts-models-202303-ec1.fc36.noarch.rpm

See also LDrawPartsLibrary.

Grid-based Tiling Window Management, Mark III, aka QuickGridZones

With a laptop and a 4K monitor, I wind up with a large number of windows scattered across my screens. The general disarray of scattered and randomly offset windows drives me nuts.

I've done some work to address this problem before (here and here), which I had been referring to as "quicktile". But that's what KDE called its implementation that allowed snapping the window to either half of the screen, or to some quarter. On Windows, there's a Power Tool called "Fancy Zones" that also has a few similarities. In an effort to disambiguate what I've built, I've renamed my approach to "Quick Grid Zones".

Since the last post on this, I've done some cleanup of the logic and also ported it to work on Windows.

This isn't a cross-platform implementation, but rather three implementations with some structural similarities, implemented on top of platform-specific tools.

  • Linux KDE - KDE global shortcuts that call a Python script using xdotool, wmctrl, and xprop
  • Mac OS - a lua script for Hammerspoon
  • Windows - an AutoHotKey2 script

Simple demo of running this on KDE:

Grab the local tarball for this release, or check out the QuickGridZones project page.

LDraw Parts Library 2023-02 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2023-02 parts library for Fedora 36 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202302-ec1.fc36.src.rpm

ldraw_parts-202302-ec1.fc36.noarch.rpm
ldraw_parts-creativecommons-202302-ec1.fc36.noarch.rpm
ldraw_parts-models-202302-ec1.fc36.noarch.rpm

See also LDrawPartsLibrary.

LeoCAD 23.03 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged (as an rpm) the 23.03 release of LeoCAD for Fedora 36. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-23.03-ec1.fc36.x86_64.rpm

leocad-23.03-ec1.fc36.src.rpm

LDraw Parts Library 2022-06 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2022-06 parts library for Fedora 36 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202206-ec1.fc36.src.rpm

ldraw_parts-202206-ec1.fc36.noarch.rpm
ldraw_parts-creativecommons-202206-ec1.fc36.noarch.rpm
ldraw_parts-models-202206-ec1.fc36.noarch.rpm

LDraw Parts Library 2022-05 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2022-05 parts library for Fedora 34 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202205-ec1.fc34.src.rpm

ldraw_parts-202205-ec1.fc34.noarch.rpm
ldraw_parts-creativecommons-202205-ec1.fc34.noarch.rpm
ldraw_parts-models-202205-ec1.fc34.noarch.rpm

Grid-based Tiling Window Management, Mark II

A few years ago, I implemented a grid-based tiling window management tool for Linux/KDE that drastically improved my ability to utilize screen realestate on a 4K monitor.

The basic idea is that a 4K screen is divided into 16 cells in a 4x4 grid, and a Full HD screen is divided into 4 cells in a 2x2 grid. Windows can be snapped (Meta-Enter) to the nearest rectangle that aligns with that grid, whether that rectangle is 1 cell by 1 cell, or if it is 2 cells by 3 cells, etc. They can be moved around the grid with the keyboard (Meta-Up, Meta-Down, Meta-Left, Meta-Right). They can be grown by increments of the cell size in the four directions (Ctrl-Meta-Up, Ctrl-Meta-Down, Ctrl-Meta-Left, Ctrl-Meta-Right), and can be shrunk similarly (Shift-Meta-Up, Shift-Meta-Down, Shift-Meta-Left, Shift-Meta-Right).

While simple in concept, it dramatically improves the manageability of a large number of windows on multiple screens.

Since that first implementation, KDE or X11 introduced a change that broke some of the logic in the quicktile code for dealing with differences in behavior between different windows. All windows report location and size information for the part of the window inside the frame. When moving a window, some windows move the window inside the frame to the given coordinates (meaning that you set the window position to 100,100, and then query the location and it reports as 100,100). But other windows move the window _frame_ to the given coordinates (meaning that you set the window position to 100,100, and then query the location and it reports as 104,135). It used to be that we could differentiate those two types of windows because one type would show a client of N/A, and the other type would show a client of the hostname. But now, all windows show a client of the hostname, so I don't have a way to differentiate them.

Fortunately, all windows report their coordinates in the same way, so we can set the window's coordinates to the desired value, get the new coordinates, and if they aren't what were expected, adjust the coordinates we request by the error amount, and try again. That gets the window to the desired location reliably.

The downside is that you do see the window move to the wrong place and then shift to the right place. Fixing that would require finding some characteristic that can differentiate between the two types of windows. It does seem to be consistent in terms of what program the window is for, and might be a GTK vs QT difference or something. Alternatively, tracking the error correction required for each window could improve behavior by making a proactive adjustment after the first move of a window. But that requires maintaining state from one call of quicktile to the next, which would entail saving information to disk (and then managing the life-cycle of that data), or keeping it in memory using a daemon (and managing said daemon). For the moment, I don't see the benefit being worth that level of effort.

Here is the updated quicktile script.

To use the tool, you need to set up global keyboard shortcuts for the various quicktile subcommands. To make that easier, I created an importable quicktile shortcuts config file for KDE.

Of late I have also noticed that some windows may get rearranged when my laptop has the external monitor connected or disconnected. When that happens, I frequently wind up with a large number of windows with odd shapes and in odd locations. Clicking on each window, hitting Meta-Enter to snap it to the grid, and then moving it out of the way of the next window gets old very quickly. To more easily get back to some sane starting point, I added a quicktile snap all subcommand which will snap all windows on the current desktop to the grid. The shortcuts config file provided above ties that action to Ctrl-Meta-Enter.

This version works on Fedora 34; I have not tested on other distributions.

LDraw Parts Library 2022-03 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2022-03 parts library for Fedora 34 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202203-ec1.fc34.src.rpm

ldraw_parts-202203-ec1.fc34.noarch.rpm
ldraw_parts-creativecommons-202203-ec1.fc34.noarch.rpm
ldraw_parts-models-202203-ec1.fc34.noarch.rpm

LDraw Parts Library 2022-01 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2022-01 parts library for Fedora 34 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202201-ec1.fc34.src.rpm

ldraw_parts-202201-ec1.fc34.noarch.rpm
ldraw_parts-creativecommons-202201-ec1.fc34.noarch.rpm
ldraw_parts-models-202201-ec1.fc34.noarch.rpm

LeoCAD 21.06 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged (as an rpm) the 21.06 release of LeoCAD for Fedora 34. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-21.06-1ec1.fc34.x86_64.rpm

leocad-21.06-1ec1.fc34.src.rpm

LDraw Parts Library 2020-03 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2020-03 parts library for Fedora 34 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202003-ec1.fc34.src.rpm

ldraw_parts-202003-ec1.fc34.noarch.rpm
ldraw_parts-creativecommons-202003-ec1.fc34.noarch.rpm
ldraw_parts-models-202003-ec1.fc34.noarch.rpm

More fun with the bash prompt

A few years ago, I posted some fun Bash prompt tools, part of which was adding emoticons to the prompt based on the previous command's exit code. I figured it was time to revisit that bit of fun with a couple of enhancements.

First, a bit of code cleanup so color choices are more obvious, and add faces for SIGILL and SIGKILL.

#!/bin/bash
# source this
function prompt_smile () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$green
        face=":)"
    elif [ $retval -eq 1 ]; then
        color=$red
        face=":("
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=":|"
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        face=":-&"
    elif [ $retval -eq 137 ]; then # KILL
        color=$red
        face="X_X"
    elif [ $retval -eq 139 ]; then # SEGV
        color=$red
        face=">_<"
    elif [ $retval -eq 143 ]; then # TERM
        color=$red
        face="x_x"
    else
        color=$red
        face="O_o"
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_smile) "

Download

When sourced into your shell with . promptsmile.sh, you get results like this:

bash-4.4$ . promptsmile.sh
bash-4.4$ :) false
bash-4.4$ :( true
bash-4.4$ :) sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 26699
[2] 26700
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ :| sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 26709
[2] 26710
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ :-& sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 26776
[2] 26777
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ X_X sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 26788
[2] 26789
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ >_< sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 26852
[2] 26853
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ x_x (exit 4)
bash-4.4$ O_o true
bash-4.4$ :) exit

One bit of feedback I received was that the use of :) vs x_x meant that command prompts would shift by a character, and it would be better to have all the emoticons be of the same width. So if you prefer your faces all the same width, promptsmile-3wide.sh gives you more consistent line lengths:

#!/bin/bash
# source this
function prompt_smile () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$green
        face=":-)"
    elif [ $retval -eq 1 ]; then
        color=$red
        face=":-("
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=":-|"
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        face=":-&"
    elif [ $retval -eq 137 ]; then # KILL
        color=$red
        face="X_X"
    elif [ $retval -eq 139 ]; then # SEGV
        color=$red
        face=">_<"
    elif [ $retval -eq 143 ]; then # TERM
        color=$red
        face="x_x"
    else
        color=$red
        face="O_o"
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_smile) "

Download

Which looks like this:

bash-4.4$ . promptsmile-3wide.sh
bash-4.4$ :-) false
bash-4.4$ :-( true
bash-4.4$ :-) sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 26914
[2] 26915
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ :-| sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 26925
[2] 26926
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ :-& sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 26991
[2] 26992
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ X_X sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 27001
[2] 27002
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ >_< sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 27065
[2] 27066
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ x_x (exit 4)
bash-4.4$ O_o true
bash-4.4$ :-) exit

For that old-school style, the text-based emoticons work well, but systems that support emojis are becoming rather common-place, so we can use UTF-8 to get little emotional faces in our prompts:

#!/bin/bash
# source this
function prompt_emoji () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$yellow
        face=$'\360\237\230\200' # :D
    elif [ $retval -eq 1 ]; then
        color=$yellow
        face=$'\360\237\230\246' # :(
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=$'\360\237\230\220' # :|
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        #face=$'\360\237\244\242' # nauseated # get a rectangle in Konsole
        face=$'\360\237\230\223' # cold sweat face
    elif [ $retval -eq 137 ]; then # KILL
        color=$yellow
        face=$'\360\237\230\265' # x_x
    elif [ $retval -eq 139 ]; then # SEGV
        #color=$yellow
        #face=$'\360\237\244\250' # Face with one eyebrow raised # get a rectangle in Konsole
        color=$red
        face=$'\360\237\230\240' # Angry face
    elif [ $retval -eq 143 ]; then # TERM
        color=$yellow
        face=$'\360\237\230\243' # >_<
    else
        color=$yellow
        face=$'\360\237\230\245' # ;(
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_emoji) "

Download

Which will give something maybe like this. The way the faces are rendered will depend on your terminal. For Konsole, these are simple line art; for Gnome-terminal some match Konsole, others have a more blob-like shape; and here they're rendered by your browser.

bash-4.4$ . promptemoji.sh
bash-4.4$ 😀 false
bash-4.4$ 😦 true
bash-4.4$ 😀 sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 27143
[2] 27144
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ 😐 sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 27154
[2] 27155
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ 😓 sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 27220
[2] 27221
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ 😵 sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 27232
[2] 27233
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ 😠 sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 27295
[2] 27296
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ 😣 (exit 4)
bash-4.4$ 😥 true
bash-4.4$ 😀 exit

Beyond that, you'll find that your terminal may render a different subset of emojis than what mine does. I found a useful site for finding emojis with octal UTF-8 which makes it easy to update promptemoji.sh with something that suits your particular set of software.

And for ANSI colors, you may find this reference handy.

Go then, and liven up your own bash prompts, even more!

LDraw Parts Library 2019-02 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2019-02 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201902-ec1.fc29.src.rpm

ldraw_parts-201902-ec1.fc29.noarch.rpm
ldraw_parts-creativecommons-201902-ec1.fc29.noarch.rpm
ldraw_parts-models-201902-ec1.fc29.noarch.rpm

LeoCAD 19.07.1 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged (as an rpm) the 19.07.1 release of LeoCAD for Fedora 29. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-19.07.1-1ec1.fc29.x86_64.rpm

leocad-19.07.1-1ec1.fc29.src.rpm

Grid-based Tiling Window Management

Many years ago, a coworker of mine showed me Window's "quick tiling" feature, where you would press Window-LeftArrow or Window-RightArrow to snap the current window to the left or right half of the screen. I then found that KDE on Linux had that same feature and the ability to snap to the upper-left, lower-left, upper-right, or lower-right quarter of the screen. I assigned those actions to the Meta-Home, Meta-End, Meta-PgUp, and Meta-PgDn shortcuts. (I'm going to use "Meta" as a generic term to mean the modifier key that on Windows machines has a Windows logo, on Linux machines has a Ubuntu or Tux logo, and Macs call "command".) Being able to arrange windows on screen quickly and neatly with keyboard shortcuts worked extremely well and quickly became a capability central to how I work.

Then I bought a 4K monitor.

With a 4K monitor, I could still arrange windows in the same way, but now I had 4 times the number of pixels. There was room on the screen to have a lot more windows that I could see at the same time and remain readable. I wanted a 4x4 grid on the screen, with the ability to move windows around on that grid, but also to resize windows to use multiple cells within that grid.

Further complicating matters is the fact that I use that 4K monitor along with the laptop's !FullHD screen which is 1920x1080. Dividing that screen into a 4x4 grid would be awkward; I wanted to retain a 2x2 grid for that screen, and keep a consistent mechanism for moving windows around on that screen and across screens.

KDE (Linux)

Unfortunately, KDE does not have features to support such a setup. So I went looking for a programatic way to control window size and placement on KDE/X11. I found three commandline tools that among them offered primitives I could build upon: xdotool, wmctrl, and xprop.

My solution was to write a Python program which took two arguments: a command and a direction.

The commands were 'move', 'grow', and 'shrink', and the directions 'left', 'right', 'up', and 'down'. And one additional command 'snap' with the location 'here' to snap the window to the nearest matching grid cells. The program would identify the currently active window, determine which grid cell was a best match for the action, and execute the appropriate xdotool commands. Then I associated keyboard shortcuts with those commands. Meta-Arrow keys for moving, Meta-Ctrl-Arrow keys to grow the window by a cell in the given direction, Meta-Shift-Arrow to shrink the window by a cell from the given direction, and Meta-Enter to snap to the closest cell.

system-settings-config.png

Conceptually, that's not all that complicated to implement, but in practice:

Window geometry has to be adjusted for window decorations. But there appears to be a bug with setting the position of a window. The window coordinates used by the underlying tools for setting and getting the geometries do not include the frame, except for setting the position of the window, on windows that have a 'client' of the machine name instead of N/A. Getting the position, getting the size, and setting the size, all use the non-frame values. Windows with a client of N/A use the non-frame values for everything. A border width by title bar height offset error for only some of the windows proved to be a vexing bug to track down.

The space on a secondary monitor where the taskbar would be is also special, even if there is no task bar on that monitor; attempting to move a window into that space causes the window to shift up out of that space, so there remains an unused border on the bottom of the screen. Annoying, but I have found no alternative.

Move operations are not instantaneous, so setting a location and immediately querying it will yield the old coordinates for a short period.

A window which is maximized does not respond to the resize and move commands (and attempting it will cause xdotool to hang for 15 seconds), so that has to be detected and unmaximized.

A window which has been "Quick Tiled" using KDE's native quick-tiling feature acts like a maximized window, but does not set the maximized vert or maximized horz state flags, so cannot be detected with xprop, and to get it out of the KDE quick tiled state, it must be maximized and then unmaximized. So attempting to move a KDE quick tiled window leads to a 15 second pause, then the window maximizing briefly, and then resizing to the desired size. In practice, this is not much of an issue since my tool has completely replaced my use of KDE's quick-tiling.

OS X

I recently whined to a friend about not having the same window management setup on OS X; and he pointed me in the direction of a rather intriguing open source tool called Hammerspoon which lets you write Lua code to automate tasks in OS X and can assign keyboard shortcuts to those actions. That has a grid module that offers the necessary primitives to accomplish the same goal.

After installing Hammerspoon, launching it, and enabling Accessibility for Hammerspoon (so that the OS will let it control application windows), use init.lua as your ~/.hammerspoon/init.lua and reload the Hammerspoon config. This will set up the same set of keyboard shortcuts for moving application windows around as described in the KDE (Linux) section. For those who use OS X as their primary system, that set of shortcuts are going to conflict with (and therefore override) many of the standard keyboard shortcuts. Changing the keyboard shortcuts to add the Option key as part of the set of modifiers for all of the shortcuts should avoid those collisions at the cost of either needing another finger in the chord or putting a finger between the Option and Command keys to hit them together with one finger.

I was pleasantly surprised with how easily I could implement this approach using Hammerspoon.

Demo

Simple demo of running this on KDE:

(And that beautiful background is a high resolution photo by a friend and colleague, Sai Rupanagudi.)

LDraw Parts Library 2019-01 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2019-01 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201901-ec1.fc29.src.rpm

ldraw_parts-201901-ec1.fc29.noarch.rpm
ldraw_parts-creativecommons-201901-ec1.fc29.noarch.rpm
ldraw_parts-models-201901-ec1.fc29.noarch.rpm

LeoCAD 18.02 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged the 18.02 release of LeoCAD for Fedora 29. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-18.02-1ec1.fc29.x86_64.rpm

leocad-18.02-1ec1.fc29.src.rpm

LDraw Parts Library 201802 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 201802 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201802-ec1.fc29.src.rpm

ldraw_parts-201802-ec1.fc29.noarch.rpm
ldraw_parts-creativecommons-201802-ec1.fc29.noarch.rpm
ldraw_parts-models-201802-ec1.fc29.noarch.rpm

LeoCAD 17.02 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged the 17.02 release of LeoCAD for Fedora 25. This package requires the LDraw parts library packaged earlier.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-17.02-1ec1.fc25.x86_64.rpm

leocad-17.02-1ec1.fc25.src.rpm

LDraw Parts Library 2016-01 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2016-01 parts library for Fedora 25 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201601-ec1.fc25.src.rpm

ldraw_parts-201601-ec1.fc25.noarch.rpm
ldraw_parts-creativecommons-201601-ec1.fc25.noarch.rpm
ldraw_parts-models-201601-ec1.fc25.noarch.rpm

Having fun with the bash prompt

Run Time

I frequently want to know how long a command took, but only after I realize that it's taking longer than I expected. So I modified my bash prompt to time every single command I run. So each prompt looks like

[eli@hostname blog]$ [13]

When a command takes a long time, I may want to go work on something else for a couple of minutes, but still want to know when it completes. So I made the command prompt include a bell character and an exclamation point if the command exceeded 5 seconds.

[eli@hostname blog]$ [13!]

It would also be nice to have my eye drawn to the prompt if it took a long time, but I don't want to be distracted by all the [0]'s getting displayed. So I made the color vary based on the length of time. If it is 0 seconds, it's displayed in black, and as it takes longer, it transitions to white, and then to increasingly brighter shades of red, maxing out at bright red on a 5 minute run time.

[eli@hostname blog]$ [0s] sleep 5
[eli@hostname blog]$ [5s!] sleep 60
[eli@hostname blog]$ [60s!] sleep 252
[eli@hostname blog]$ [252s!] 
[eli@hostname blog]$ [0s] sleep 1
[eli@hostname blog]$ [1s] 
[eli@hostname blog]$ [0s] 

So all that code went into a dotscript I called promptautobell:

#!/bin/bash
function prompt_autobell_start {
    prompt_autobell_timer=${prompt_autobell_timer:-$SECONDS}
}
function prompt_autobell_stop {
    local retval=$?
    prompt_autobell_elapsed=$(($SECONDS-$prompt_autobell_timer))
    unset prompt_autobell_timer

    local color
    local bell
    if [ $prompt_autobell_elapsed -ge 5 ]; then
        bell="\001\a\002!"
    else
        bell=""
    fi
    
    color="$(tput bold)$(tput setaf $((prompt_autobell_elapsed > 300 ? 196 \
: prompt_autobell_elapsed > 22 ? 16+(1+(prompt_autobell_elapsed-1)/60)*36: \
233+prompt_autobell_elapsed)))"

    prompt_autobell_show="$(echo -e "\001${color}\002[\
${prompt_autobell_elapsed}s$bell]\001$(tput sgr0)\002")"

    return $retval
}
trap 'prompt_autobell_start' DEBUG
PROMPT_COMMAND="prompt_autobell_stop"
PS1="$PS1\${prompt_autobell_show} "

So that's nice, we get to know how long our commands take, and automatically get nudged when a long-running command finally completes.

Return Codes

But that doesn't tell us if the command passed or failed. And in the *NIX tradition, commands are generally silent on success. So what if we make the prompt display an appropriate emoticon based on the exit code? Like, a green smiley on success, and a red frown on failure. And maybe a few other expressions as well.

[eli@hostname blog]$ source ~/bin/promptsmile
[eli@hostname blog]$ :) 
[eli@hostname blog]$ :) false
[eli@hostname blog]$ :( sleep 60
^C
[eli@hostname blog]$ :| sleep 60
Terminated
[eli@hostname blog]$ x_x sleep 60
Segmentation fault (core dumped)
[eli@hostname blog]$ >_< true
[eli@hostname blog]$ :) 

So into a dotscript called promptsmile goes:

#!/bin/bash
# source this
function prompt_smile () {
local retval=$?
if [ $retval -eq 0 ]; then
    color=46
    face=":)"
elif [ $retval -eq 1 ]; then
    color=196
    face=":("
elif [ $retval -eq 130 ]; then # INT
    color=226
    face=":|"
elif [ $retval -eq 139 ]; then # SEGV
    color=196
    face=">_<"
elif [ $retval -eq 143 ]; then # TERM
    color=196
    face="x_x"
else
    color=196
    face=";("
fi
echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_smile) "

Note that the emoticon logic is readily extensible. Do you frequently deal with a program that has a couple of special exit codes? Make those stand out with a bit of straight-forward customization of the prompt_smile function.

Combined

And of course, I want an easy way to get both of these behaviors at the same time, so I created a dotscript called promptfancy:

source ~/bin/promptautobell
source ~/bin/promptsmile

And to make it easy to apply to a shell, I added to ~/.bashrc:

alias fancyprompt="source ~/bin/promptfancy"

And now,

[eli@hostname blog]$ fancyprompt 
[eli@hostname blog]$ [0s] :) 
[eli@hostname blog]$ [0s] :) sleep 60
^C
[eli@hostname blog]$ [1s] :| sleep 60
Terminated
[eli@hostname blog]$ [12s!] x_x sleep 60
Segmentation fault (core dumped)
[eli@hostname blog]$ [12s!] >_< false
[eli@hostname blog]$ [0s] :( sleep 6
[eli@hostname blog]$ [6s!] :) 
[eli@hostname blog]$ [0s] :) 
[eli@hostname blog]$ [0s] :) 

Go then, and liven up your own bash prompts!

Driving Corsair Gaming keyboards on Linux with Python, IV

Here is a new release of my Corsair keyboard software.

The 0.4 release of rgbkbd includes:

  • Union Jack animation and still image
  • Templates and tools for easier customization
  • Re-introduced brightness control

New Flag

For our friends across the pond, here's a Union Jack.

I started with this public domain image (from Wikipedia)

I scaled it down to 53px wide, cropped it to 18px tall, and saved that as uka.png in the flags/k95 directory. I then cropped it to 46px wide and saved that as flags/k70/uka.png. Then I ran make.

Here is what it looks like on the K95:

Union Jack animation

Tools

To make it easier to draw images for the keyboard, I created templates for the supported keyboards that are suitable for use with simple graphics programs.

K95 template

K70 template

Each key has an outline in not-quite-black, so you can flood fill each key. Once that image is saved, ./tools/template2pattern modified-template-k95.png images/k95/mine.png will convert that template to something the animated GIF mode can use. A single image will obviously give you a static image on the keyboard.

But you can also use this with ImageMagick's convert to create an animation without too much trouble.

For example, if you used template-k70.png to create 25 individual frames of an animation called template-k70-fun-1.png through template-k70-run-25.png, you could create an animated GIF with these commands (in bash):

for frame in {1..25}; do
    ./tools/template2pattern template-k70-fun-$frame.png /tmp/k70-fun-$frame.png
done
convert /tmp/k70-fun-{1..25}.png images/k70/fun.gif
rm -f /tmp/k70-fun-{1..25}.png

Brightness control

This version re-introduces the brightness level control so the "light" key toggles through four brightness levels.

Grab the source code, or the pre-built binary tarball.

Previous release

Driving Corsair Gaming keyboards on Linux with Python, III

Here is a new release of my Corsair keyboard software.

The 0.3 release of rgbkbd includes:

  • Add flying flag animations
  • Add Knight Rider inspired animation
  • Support images with filenames that have extensions
  • Cleanup of the Pac-Man inspired animation code

Here is what the flying Texas flag looks like: Animated Texas flag

And the Knight Rider inspired animation: Knight Rider inspired animation

Grab the source code, or the pre-built binary tarball.

Previous release

Update: Driving Corsair Gaming keyboards on Linux with Python, IV

Driving Corsair Gaming keyboards on Linux with Python, II

Since I wrote about Driving the Corsair Gaming K70 RGB keyboard on Linux with Python, the ckb project has released v0.2. With that came changes to the protocol used to communicate with ckb-daemon which broke my rgbkbd tool.

So I had to do some work on the code. But that wasn't the only thing I tackled.

The 0.2 release of rgbkbd includes:

  • Updates the code to work with ckb-daemon v0.2
  • Adds support for the K95-RGB, in addition to the existing support for the K70-RGB.
  • Adds a key-stroke driven "ripple" effect.
  • Adds a "falling-letter" animation, inspired by a screen saver which was inspired by The Matrix.
  • Adds support for displaying images on the keyboard, with a couple of example images.
  • Adds support for displaying animated GIFs on the keyboard, with an example animated GIF.

That's right; you can play animated GIFs on these keyboards. The keyboards have a very low resolution, obviously, but internally, I represent them as an image sized based on a standard key being 2x2 pixels. That allows for half-key offsets in the mapping of pixels to keys which gets a reasonable approximation. Keys are colored based on averaging the color of the pixels for that key. Larger keys are backed by more pixels. If the image dimensions don't match the dimensions of the keyboard's image buffer (46x14 for K70, 53x14 for K95), it will slowly scroll around the image. Since the ideal image size depends on the keyboard model, the image files are segregated by model name.

Here is what that looks like:

(Also available on YouTube)

Grab the source code and have fun.

Previous release

Update: Driving Corsair Gaming keyboards on Linux with Python, III

The Floppy-Disk Archiving Machine, Mark III

"I'm not building a Mark III."

Famous last words.

I made the mistake of asking my parents if they had any 3.5" floppy disks at their place.

They did.

And a couple hundred of them were even mine.

Faced with the prospect of processing another 500-odd disks, I realized the Mark III was worth doing. So I made a few enhancements for the Floppy Machine Mark III:

  • Changed the gearing of the track motor assembly to increase torque and added plates to keep its structure from spreading apart. The latter had been causing the push rod mechanism to bind up and block the motor, even at 100% power.
  • Removed the 1x4 technic bricks from the end of the tractor tread, and lengthened the tread by several links and added to the top of the structure under those links. This reduced the frequency that something got caught on the structure and caused a problem.
  • Extended the drive's shell's lower half by replacing the 1x6 technic bricks with 1x10 technic bricks; and a 1x4 plate on the underside flush with the end. This made the machine more resilient to the drive getting dropped too quickly.
  • Added 1x2 bricks to lock the axles into place for the drive shell's pivot point, since they seemed to be working their way out very slowly.
  • Added 1x16 technic bricks to the bottom of all the legs, and panels to accommodate that, increasing the machine's height by 5" and making it easier to pull disks out of the GOOD and BAD bins.
  • Added doors at the bottom of the trays in the front to keep disks from bouncing out
  • Added back wall at bottom of the trays in the back to keep disks from bouncing out.
  • Moved the ultrasonic sensor lower in an attempt to reduce the false empty magazine scenario. This particular issue was sporadic enough that the effectiveness of the change is hard to determine. I only had one false-empty magazine event after this change.
  • Added a touch sensor to detect when the push rod has been fully retracted in order to protect the motor. Before this, the machine identified the position of the push rod by driving the push rod to the extreme right until the motor blocked. This seems to have had a negative effect upon the motor in question. Turning the rotor of that poor, abused motor in one direction has a very rough feel. This also used the last sensor port on the NXT. (One ultrasonic sensor and three touch sensors.)
  • Replaced the cable to the push rod motor with a longer one from HiTechnic.
  • Significantly modified the controlling software to calibrate locations of the motors in ways that did not require driving a motor to a blocked state.
  • Enhanced the controlling software to allow choosing what events warranted marking a disk as bad and which didn't.
  • Enhanced the data recovery software to allow bailing on the first error detected. This helps when you want to do an initial pass through the disks to get all the good disks archived first. Then you can run the disks through a second time, spending more time recovering the data off the disks.
  • Enhanced the controlling software to detect common physical complications and take action to correct it, such as making additional attempts to eject a disk.

With those changes, the Mark III wound up much more rainbow-warrior than the Mark II:

floppy machine mark iii

And naturally, I updated the model with the changes:

floppy machine mark iii model

The general theme for the Mark II was to rebuild the machine with a cleaner construction, reasonable colors, and reduced part count. The general theme for the Mark III was to improve the reliability of the machine so it could process more disks with less baby-sitting.

All told, I had 1196 floppy disks. If you stack them carefully, they'll fit in a pair of bankers boxes.

boxes of disks

And with that, I'm done. No Mark IV. For real, this time. I hope.

Previously: the Mark II

The Floppy-Disk Archiving Machine, Mark II

Four and a half years ago, I built a machine to archive 3.5" floppy disks. By the time I finished doing the archiving of the 443 floppies, I realized that it fell short of what I wanted. There were a couple of problems:

  • many 3.5" floppy disk labels wrap around to the back of the disk
  • disks were dumped into a single bin
  • the machine was sensitive to any shifts to the platform, which consisted of two cardboard boxes
  • the structure of the frame was cobbled together and did not use parts efficiently
  • lighting was ad-hoc and significantly affected by the room's ambient light
  • the index of the disks was cumbersome

I recently had an opportunity to dust off the old machine (quite literally), and do a complete rebuild of it. That allowed me to address the above issues. Thus, I present:

The Floppy-Disk Archiving Machine, Mark II

The Mark II addresses the shortcomings of the first machine.

Under the photography stage, an angled mirror provides the camera (an Android Dev Phone 1) a view of the label on the back of the disk. That image needs perspective correction, and has to be mirrored and cropped to extract a useful image of the rear label. OpenCV serves this purpose well enough, and is straight forward to use with the Python bindings.

The addition of lights and tracing-paper diffusers improved the quality of the photos and reduced the glare. It also made the machine usable whether the room lights were on or off.

The baffle under disk drive allows the machine to divert the ejected disks into either of two bins. I labeled those bins "BAD" and "GOOD". I wrote the control software (also Python) to accept a number of options to allow sorting the disks by different criteria. For instance, sometimes OpenCV's object matching selects a portion of a disk or its label instead of the photography stage's arrows. When that happens, the extraction of the label will fail. That can happen for either the front or back disk labels. The machine can treat such a disk as 'BAD'. When a disk is processed, and bad bytes are found, the machine can treat the disk as bad. The data extraction tool supports different levels of effort for extracting data from around bad bytes on a disk.

This allows for a multiple-pass approach to processing a large number of disks.

In the first pass, if there is a problem with either picture, or if there are bad bytes detected, sort the disk as bad. That first pass can configure the data extraction to not try very hard to get the data, and thus not spend much time per disk. At the end of the first pass, all the 'GOOD' disks have been successfully read with no bad bytes, and labels successfully extracted. The 'BAD' disks however, may have failed for a mix of different reasons.

The second pass can then expend more effort extracting data from disks with read errors. Disks which encounter problems with the label pictures would still be sorted as 'BAD', but disks with bad bytes would be sorted as 'GOOD' since we've extracted all the data we can from them, and we have good pictures of them.

That leaves us with disks that have failed label extraction at least once, and probably twice. At this point, it makes sense to run the disks through the machine and treat them as 'GOOD' unconditionally. Then the label extraction tool can be manually tweaked to extract the labels from this small stack of disks.

Once the disks have been successfully photographed and all available data extracted, an html-based index can be created. That process creates one page containing thumbnails of the front of the disks.

index of floppies screenshot

Each thumbnail links to a page for a disk giving ready access to:

  • a full-resolution picture of the extracted front label
  • a full-resolution picture of the extracted back label
  • a zip file containing the files from the disk
  • a browsable file tree of the files from the disk
  • an image of the data on the disk
  • a log of the data extracted from the disk
  • the un-processed picture of the front of the disk
  • the un-processed picture of the back of the disk

single disk screenshot

The data image of the disk can be mounted for access to the original filesystem, or forensic analysis tools can be used on it to extract deleted files or do deeper analysis of data affected by read errors. The log of the data extracted includes information describing which bytes were read successfully, which had errors, and which were not directly attempted. The latter may occur due to time limits placed on the data extraction process. Since a single bad byte may take ~4 seconds to return from the read operation, and there may be 1474560 bytes on a disk, if every byte were bad you could spend 10 weeks on a single disk, and recover nothing. The data recovery software (also written in Python) therefore prioritizes the sections of the disk that are most likely to contain the most good data. This means that in practice everything that can be read off the disk will be read off in less than 20 minutes. For a thorough run, I will generally configure the data extraction software to give up if it has not successfully read any data in the past 30 minutes (it's only machine time, after all). At that point, the odds of any more bytes being readable are quite low.

So what does the machine look like in action?

(Also posted to YouTube.)

Part of the reason I didn't disassemble the machine while it collected dust for 4.5 years was that I knew I would not be able to reproduce it should I have need of it again in the future. Doing a full rebuild of the machine allowed me to simplify the build dramatically. That made it feasible to create an Ldraw model of it using LeoCAD.

rendering of digital model

Rebuilding the frame with an eye to modeling it in the computer yielded a significantly simpler support mechanism, and one that proved to be more rigid as well. To address the variations of different platforms and tables, I screwed a pair of 1x2 boards together with some 5" sections of 1x4 using a pocket hole jig. The nice thing about the 5" gap between the 1x2 boards is that the Lego bricks are 5/16" wide, so 16 studs fit neatly within that gap. The vertical legs actually extend slightly below the top of the 1x2's, and the bottom horizontal frame rests on top of the boards. This keeps the machine from sliding around on the wooden frame, and makes for a consistent, sturdy platform which improves the machine's reliability.

The increase in stability and decrease in parts required also allowed me to increase the height of the machine itself to accommodate the inclusion of the disk baffle and egress bins.

What about a Mark III?

Uhm, no.

I have processed all 590 disks in my possession (where did the additional 150 come from?), and will be having these disks shredded. That said, the Mark II is not a flawlessly perfect machine. Were I to build a third machine, increasing the height a bit further to make the disk bins more easily accessible would be a worthwhile improvement. Likewise, the disk magazine feeding the machine is a little awkward to load with the cables crossing over it, and could use some improvement so that the weight of a tall stack of disks does not impede the proper function of the pushrod.

So, no, I'm not building a Mark III. Unless you or someone you know happen to have a thousand 3.5" floppy disks you need archived, and are willing to pay me well to do it. But who still has important 3.5" floppy disks lying around these days? I sure don't. (Well, not anymore, anyway.)

Previously: the Mark I

Update: the Mark III

Driving the Corsair Gaming K70 RGB keyboard on Linux with Python

I recently purchased a fun toy for my computer, a Corsair Gaming K70 RGB keyboard. It is a mechanical keyboard with each key individually backlit with an RGB LED. So you can pick the color of each key independently.

Lots of blinken-lights!

I realize there may not be many practical applications for such things, but it looked like fun. And it is.

There were a few hurdles to overcome. For one, I run Linux, which is not officially supported. Thankfully, someone had already done the hard work of reverse engineering the keyboard's USB protocol and written a Linux-compatible daemon and user utility called `ckb` for driving it. The design of ckb allows for any process to communicate with the ckb-daemon, so you can replace the ckb GUI with something else. I chose to create a Python program to replace ckb so I could play with this fun keyboard in a language I enjoy using. I also thought it would be a fun challenge to make the lighting of the keyboard controllable without having a GUI on the screen. Afterall, the keyboard has a way to give feedback: all those many, many RGB LEDs.

So I created rgbkbd. This supports doing some simple non-reactive animations of color on the keyboard, such as fading, pulsing, or jumping through a series of colors of the background. Or having those colors sweep across the keyboard in any of 6 different directions. And you can setup the set of colors you want to use by hitting the backlight and Windows lock keys to get into a command mode and select all the variations you want to apply.

But I found there were a couple of things I could do with this keyboard that have some practical value beyond just looking cool.

One is "typing mode". This is a mostly static lighting scheme with each logical group of keys lit in a different color. But it has one bit of reactive animation. It measures your current, your peak, and your sustained typing speed, and displays that on the number row of the keyboard. This way you can see how well you are typing. You can see how well you are sustaining a typing speed, and how "bursty" your typing is. (And yes, it docks your typing speed when you hit delete or the backspace key.)

Another interesting mode I created was a way to take notes without displaying what you are typing. Essentially, you switch to command mode, hit the 'Scroll Lock' key, and the keyboard lights random keys in green, but what you type is saved to a file in your home directory named .secret-<unixepochtime>. (A new file is created each time you switch into this keyboard mode.) But none of your keypresses are sent to the programs that would normally receive keystrokes. The trick here is that the keyboard allows you to "unbind" a key so that it does not generate a keystroke when you hit it. In this secrete note taking mode, all keys are unbound so none generate keystrokes for the OS. However, ckb-daemon still sees the events and passes them on to rgbkbd which can then interpret them. In this mode, it translates those keystrokes to text and writes them out to the current .secret file.

Oh, and for a fun patriotic look: press and hold the play button, tap the number pad 1, then tap blue, white, red, white, red, white, red, white; and release the play button.

Browse the source code or download the tarball.

(Also available on YouTube)

Here is the documentation for rgbkbd.

RGB KBD

rgbkbd is a Linux compatible utility for driving the Corsair Gaming K70 RGB keyboard using the ckb-daemon from ckb.

Rather than being built around a GUI like ckb is, rgbkbd is a Python program that allows for rapid prototyping and experimentation with what the K70 RGB keyboard can do.

Installation

Run rgbkbd_controller.py from this directory, or package it as an RPM, install it, and run /usr/bin/rgbkbd

Usage

Make sure that 'ckb-daemon' is running, and that 'ckb' is NOT running. rgbkbd replaces 'ckb's role in driving the keyboard animations, so they will interfere with each other if run concurrently. Like ckb, rgbkbd contains the logic behind the operations occuring on the keyboard.

rgbkbd will initialize the keyboard to a static all-white backlight.

Pressing the light button will toggle the backlight off and on.

Pressing the light button and the Windows lock button together (as a chord), will switch to the keyboard command mode. Pressing the light button and the Windows lock button again will return you to the previous keyboard mode.

The command mode allows you to select a number of different modes and effects. Most of the selections involve chording keys. When a new mode is selected, the keyboard exits command mode and initiates the new keyboard mode. When in command mode, your key presses are not passed on to currently running programs.

Static color lighting

The number keys are illuminated in a variety of colors. Pressing and releasing one of these keys will switch to a monochome color for the keyboard. Note that the ~/\ key to the left of 1` is for black.

Random pattern lighting

The Home key toggles through a random selection of colors. Hitting that key in command mode will select a random pair of colors, and a changing random set of keys will toggle between those colors.

You can select the colors for the random key animation. To do so, press and hold the Home key, then press the color selection key on the number row, and release the keys. Random keys will light with the chosen color on a black background. To select the background color as well, press and hold the Home key, then tap the color you want for the foreground, then tap the color you want for the background, and release the Home key.

Color pattern lighting

You can configure the keyboard to cycle through a pattern of colors with a configurable transition. The media keys show a light pattern in command mode. The stop button shows alternating colors. The back button shows a pulse that fades out. The play and forward buttons show fading colors at different rates. Press and hold one of those buttons, then tap a sequence of the color keys, then release the media key. The entire keyboard will cycle through the select colors using the selected transition.

Color motion lighting

You can put the color patterns described above into motion across the keyboard. To do so, choose your transition type and colors in the same way you would for the color pattern lighting, but before you release the transition selection key, tap a direction key on the number pad. You can select any of 6 different directions. Then release the transition key. The color pattern will now sweep across the keyboard in the direction you chose.

Touch-typing mode

The PrtScn button selects a touch-typing mode. Keys are statically backlit in logical groups. Plus the number row indicates your typing speed in increments of 10WPM (words per minute). The indicator includes the - and the = keys to indicate 110WPM and 120WPM, respectively.

As you type, the keys, starting with 1 will light up in white, creating a growing bar of white. This indicates your current typing speed. Your peak typing speed from the past is indicated with a yellow backlit key. If your peak typing speed exceeds 130WPM, the peak indicator will change to red. The average typing speed you have maintained over the past minute is indicated by a green backlit key. If this exceeds 130WPM, the indicator will change to blue.

Secret notes mode

The Scroll Lock key selects a secret note taking mode. The lighting will change to a random green-on-black animation, but what you type will be written to a file in your home directory named .secret-<timestamp> instead of going to your programs. This allows you to write a note to yourself for later without displaying what you are typing on the screen. This can be useful if you have someone sitting near you and you remembered something important but private you wanted to make sure you didn't forget.

Update: Driving Corsair Gaming keyboards on Linux with Python, II

LPub4 for Linux, 4th iteration

LPub4 is a program by Kevin Clague for creating high-quality instructions for Lego models. It runs on OS X and Windows. I ported it to Linux a while ago.

I have updated the patches for current versions of LPub4 and packaged it for Fedora 19.

LPub4 needs to know where to find the LDraw parts library and the ldview executable. Its configuration file is ~/.config/LPub/LDraw Building Instruction Tool.conf which (assuming you are using my package of the LDraw parts library and my package of LDView) you can edit to contain:

[General]
LDrawDir=/usr/share/ldraw
LDView=/usr/bin/ldview
PreferredRenderer=LDView
PliControl=/usr/share/lpub/pli.mpd

The .spec file shows how it was created, the *.patch files are the modifications I made, the .x86_64.rpm file (other than debuginfo) is the one to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

lpub4.spec

lpub4-1-dev-doc-fixes.patch
lpub4-2-setmeta-args-fix.patch
lpub4-3-pro-case.patch
lpub4-4-main-case.patch
lpub4-5-openfiledialog.patch
lpub4-6-preferencesdialog.patch

lpub4-4.0.0.14-20140514.ec3.src.rpm

lpub4-4.0.0.14-20140514.ec3.x86_64.rpm

lpub4-debuginfo-4.0.0.14-20140514.ec3.x86_64.rpm

LDView - Packaged for Linux

LDView renders digital Lego models, both interactively and batch. I made a couple of small patches to it and packaged it for Fedora 19.

There are two executables in these packages. LDView is the interactive GUI. If you use the LDraw Parts Library I packaged, you will need to configure it to point to /usr/share/ldraw for the LDrawDir config option. You can do that by editing ~/.config/LDView/LDView.conf to include this content:

[LDView]
LDrawDir=/usr/local/ldraw/

The other executable is ldview, which provides batch rendering operations for use by other programs such as LPub. It also needs to know where the LDraw model files are, so edit ~/.ldviewrc to contain this:

[General]
LDrawDir=/usr/local/ldraw

The .spec file shows how it was created, the *.patch files are the modifications I made, the *.x86_64.rpm files (other than debuginfo) are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldview.spec

ldview-1-no-force-zoomtofit.patch
ldview-2-typo.patch
ldview-3-64-bit-fix.patch

ldview-4.2b1.20140530-ec1.src.rpm

ldview-4.2b1.20140530-ec1.x86_64.rpm
ldview-gnome-4.2b1.20140530-ec1.x86_64.rpm
ldview-osmesa-4.2b1.20140530-ec1.x86_64.rpm

ldview-debuginfo-4.2b1.20140530-ec1.x86_64.rpm

LDraw Parts Library - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LDView and LPub rely.

I packaged the library for Fedora 19 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The .spec file shows how it was created, the *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts.spec

ldraw_parts-201302-ec4.src.rpm

ldraw_parts-201302-ec4.noarch.rpm
ldraw_parts-creativecommons-201302-ec4.noarch.rpm
ldraw_parts-models-201302-ec4.noarch.rpm

3.5" Floppy-disk Archiving Machine

August 31st of last year, at the age of 89, my Grandfather passed away. I'm a computer geek, as was he, though his machines filled rooms, and mine, merely pockets. His software flew fighter aircraft. He worked on the Apollo missions. He wrote the first software by which to operate a nuclear reactor. That is a hard act to follow.

But as a computer geek, he had accumulated a large stack of 3.5" floppy disks: 443, of them in fact. And when he passed away, it became my responsibility to deal with those. I was not looking forward to the days of mindless repetition inherent in that task. So, I did what any self-respecting software engineer would do: I automated it.

Start with Lego Mindstorms, add a laptop running Fedora Linux, an Android Dev Phone 1, a good bit of Python code, and about the same number of hours of work, and you get this:

picture of floppy archiving machine

Watch it in action on YouTube

There are a number of interesting details in this build which I plan to write about in the coming weeks, so stay tuned.

Follow up articles: NXT control software, The Floppy-Disk Archiving Machine, Mark II