Now that we've laid down a good foundation in working with the Win32 API, it's time to pay a bit of attention to the frontend. There are a lot of options here. You could just run a generic TCP server and have clients send you keystrokes you'd like to press on the server machine, but this would require a custom client. This just makes things more complicated, for something so simple it's much easier to simply do a web interface. It might not be the "coolest" thing under the sun, but it's easy to do and it means you can access this interface from any machine with a web browser.
And Ruby being Ruby, there are many many ways to make a web application as well. There's Rails of course, but that's beyond overkill for this purpose. Rails is huge, Rails is complicated, we don't need it so let's not use it here. And while there are several smaller frameworks, the most common and probably easiest to use is Sinatra. It's the best tool I've ever used for quickly making a web application. It's also good because there's hardly anything to remember. If you don't make small web applications often, you may find you've forgotten everything you knew about Sinatra in the interim. But that's OK, Sinatra is so easy to learn you can be refreshed in just a minute or two.
Installing and Hello World
Sinatra is a straight up Ruby gem, there are no surprises when installing it. There is one extra step we'll take and install a gem that gives us access to sinatra/reloader, a library that automatically reloads the web application when the source file changes. This makes developing Sinatra applications much, much easier.
gem install sinatra sinatra-contrib
Let's code up a quick Hello World web application with Sinatra. It's so easy, this is the entire web application.
require 'sinatra' get "/" do 'Hello world!' end
You can just run this script file as is for now, we'll deal with Rack later. When you run it, it'll tell you what port it's running on (Sinatra's default port is 4000), so open up http://localhost:4567/ in a browser and see our (thus far) meager handiwork. But before we go any further, let's get the reloader working.
Reloading your application every single time you make a change to the code is a real pain. It doesn't sound like much, but trust me, it really is a pain to have to hunt for your terminal window, ctrl-c and relaunch it again. Thankfully, Sinatra can reload itself with a handy library provided with the sinatra-contrib gem. To use it, simply change the require statements a bit at the top of your program.
require 'sinatra' require 'sinatra/reloader' get "/" do 'Hello world!' end
Now run the program and visit http://localhost:4567/. Now make a change so it returns something other than "Hello world" and hit refresh. The text updates without having to restart the server. This is a big time saver when working with Sinatra.
Pages and Requests
Now we're ready to start serving some pages and respond to requests. But let's take a moment and talk about Haml. Haml is an alternative markup to HTML. It generates HTML, but it's much easier to type and work with than the endless angle brackets and ending tags with HTML. It's not necessary, you can use Erb just like you use in Rails, but Haml is pretty standard in the Ruby world and a very good tool to work with. So let's install the Haml gem first.
gem install haml
Sinatra already knows about Haml and if you have it installed it will automatically require it and allow you to use it via the haml method. Another great thing about Sinatra is the ability to store your layouts and views in the same file as your application. While this would be a nightmare for larger projects, it's great for tiny projects like this. So we'll whip up a quick page layout to use here to get us started. We'll then add some markup to the root view (which we'll keep as hello world for now, but we'll give it some markup and take the actual string out of the controller).
require 'sinatra' require 'sinatra/reloader' get "/" do haml :root end __END__ @@ layout %html %head %title Sinatra HAML Test %body =yield @@ root %h1 Sinatra HTML Test %p Hello world!
In this way, we can serve views and respond to requests using our quick "controller" type code for each type of request.