Hackathons were originally events for working on personal hardware and software projects in an environment with food, few distractions, and people happy to help. More recently, they’ve become timed programming competitions. Until this weekend, I’d only tried the latter.
Previously, I’ve won several 24-hour competitions with Unity games. This time, with a non-competitive event (organized by Ilan, food provided by VRAC), I decided to try a project more focused on learning for those 6 hours on Sunday afternoon.
I wrote a C++ program for Ubuntu (run on a Raspberry Pi, but that doesn’t actually matter) that lets the user “paint” on the screen with the mouse without using a graphical environment. That’s probably more impressive than it sounds, so lemme try to explain some background.
The Linux kernel (a low-abstraction piece of the operating system that interfaces with hardware) keeps track of input devices and makes them available to programs that the user wants to run. There’s a “file” for each input device that describes what it’s doing. It’s a stream of information, really, that describes anything coming from the device. For example, pressing a key on the keyboard makes the keyboard tell the kernel that it was pressed, when it was pressed, and what key was pressed. All that info is dumped in the keyboard event stream for anything else to read. Similarly, the mouse reports a little blob of information whenever anything happens to it. That structured piece of data (called a data structure, or just struct) describes what just happened (horizontal movement, vertical movement, button press, button release), when it happened, and in the case of movement, how much. So really what this boils down to is that I need to read that stream of data and do something whenever some info comes in. How does that usually work? Does every program that uses a mouse need to do that?
In a typical graphical environment, there’s a program that runs in the background that watches the mouse. Since the mouse only directly reports relative motion, this program keeps track of an absolute position by adding the relative movements as they come in. This also means keeping track of the borders of the screen so the pointer is always visible. If a different program wants to know something about the mouse, it asks this background program where pointer is, which buttons are pressed, etc. What I wanted to do in this project is ignore all that and write my own input handler that isn’t bundled with a desktop environment. That’s an unusual thing to do, since nearly every use for a mouse requires a desktop and thus already has the mouse handler available.
The first problem that I needed to solve came up because if the program is waiting for mouse data to come in, that means it isn’t doing anything else. The whole program is frozen except when you move your mouse. What if you could tell part of the computer to watch that stream and another to use the data that the first part finds? That’s called threading. (Yes, there are other ways I could’ve done this, but I wanted to learn C++ threading, anyway.)
I’ve made threads in C# (and Python, too, I think) for watching information come in through the internet. It’s a similar situation where you have an asynchronous task that shouldn’t hold up everything else. The way that C# and C++ do threads are somewhat similar, but I didn’t have a new enough version of the C++ tools installed for the modern method to work properly (or at least that was my theory when I gave up after a few minutes). I instead learned C-style threading and made my program keep track of the mouse events that way. The thread waits for an even to come in, changes the position and state of a variable that represents the mouse, then goes back to waiting. Elsewhere in that program, I can read that variable and see the most up-to-date info about the mouse.
After getting the reading down, I had to actually do something with that data. In this case, I used it to move a cursor around the screen. I could’ve also used it to do something more complicated like rotate a 3D model or something like that, but I decided to keep it simple for now and focus on one challenge at a time. The end product lets you move a cursor with the mouse, left click to type “#” under the cursor, and right click to type a bunch of spaces in a square (which “erases” that part of the screen). That means you draw with a left click and erase with a right click, making for a simple paint program in a text-only environment!