Search this site


Page 1 of 3  [next]

Metadata

Articles

Projects

Presentations

Suxus font change - Zero no longer looks like capital O

So yeah, the subject rather explains it - i got tired of always thinking "Is that a zero or a letter?" When reading text with suxus, so I changed it to have a small slash in the zero.

http://www.semicomplete.com/misc/suxus.pcf.gz

Necessary screenshot -

Update: The real suxus release has this now.

Firefox 'url editor' implemented with xdotool

You'll need xdotool and these 3 scripts for this example: Then just run 'ffue' and it'll open up vi with the current url split so you can edit it. Save+quit and it'll unsplit it and use ffup to go to the modified url.

xdo - do (keyboard or mouse) things in X

Update: xdotool is now a full project, see this page. It supports much more than just mouse and keyboard things.

Yesterday, I talked about macros. I spent some time coding today and I now have a tool that will let you execute raw keyboard and mouse input into X using the XTEST extension.

The primary example I used was focusing firefox's URL bar without the mouse. The sequence was this: Switch to Desktop 2 (I press Alt+2), focus firefox's URL bar (using control+l) and clear it.

The result is a simple tool I'm tentatively calling 'xdo'. You can download the source here. Compile instructions are at the top of the file.

The top of xdo.c details the implemented commands, so let's cut to an example:

% echo 'key alt+2; sleep 1; key ctrl+l; key BackSpace' | ./xdo
It does exactly what you think. The 'sleep' command has values in milliseconds, and is only necessary to slow down so that events can propgate fast enough (window focus changes, etc).

Another reasonable example would be to say "firefox, open a new tab and load the URL in my clipboard":

# My clipboard contains a valid url, say, "http://www.google.com/"
(echo "key alt+2; sleep 1; key ctrl+l; key BackSpace;"
 echo "move 55 55; sleep 1; click 2; key Return") | ./xdo
Seems complex, but look at what's really happening: Go to desktop 2, focus urlbar, hit backspace (clearing it), move the mouse cursor to 55,55 (a point inside the urlbar for me), hit middle mouse button to paste.

Change "ctrl+l" to ctrl+k (unix firefox) to focus the "Search" box instead, and change the 'move' command to cursor over the search box to paste instead, and suddenly you can bind a simple keystroke to search for whatever is in your X clipboard. Useful.

One of the neater features is that you can 'type' text:

% echo 'type echo hello there; key Return' | ./xdo
echo hello there
% echo hello there
hello there

Key macro navigation

Today was a learning day. A few months ago, I released keynav, a tool to make large-area mouse navigation very quick. However, I found myself using keynav to do the same things over and over again. Select certain windows, clicking on certain UI widgets, etc; things that are annoying to do repeatedly.

What if we had a way to describe input actions? What if you could say "Focus the firefox URL bar" with a simple keystroke, without having firefox focused? This premise is fairly simple - Focus firefox, then "click" on a certain part of the window. The URL bar's location is pretty reliable (a few pixels from the top).

If you're like me, firefox is on another virtual desktop. What if firefox isn't shown right now because you're on "Desktop 1" and firefox lives on "Desktop 2"? Well we can find out if it's hidden, then send the keystrokes (via XTEST) to switch to "Desktop 2" and then do whatever we would normally do to focus on Firefox's URL bar. The basic pseudocode of the script would look like:

if firefox is not shown:
  go to desktop 2 ("fake send alt+2")

focus firefox (via fake click?)
fake send "Control+L" (Firefox's shortcut for focusing the urlbar)
Seems pretty simple. "Fake" above refers to events sent using the XTest, an extension to X11 (Xorg/XFree86) that lets you send keystrokes and mouse events as if they had been typed.

So, tonight I started work on a project that would let you script actions. Generally, I'm aiming at scripting UI interaction to make common tasks such as "take me to firefox" simpler.

I revisited some man pages for Xlib I hadn't seen in many months, and now I can traverse the list of all open windows in X and show their status. Here's what this tool outputs; notice how I can tell if the window is visible ("shown" by the window manager):

+ 8388621 ([email protected],324) [Visible]
  teabag(.../home/jls/projects/navmacro)
  "xterm" "XTerm" 
+ 44040205 ([email protected],324) [Hidden]
  snack(~) % @ snack
  "xterm" "XTerm" 
+ 29360192 ([email protected],1008) [Hidden]
  HMUG: man XWindowAttributes (3) - Mozilla Firefox
  "firefox-bin" "Firefox-bin"

The other piece of learning I did tonight was to learn GTK2. Enough fiddling around and I was able to get a input field that pops up over everything and is as wide as the screen to input your macros in. GTK's not that bad. Its API design is fairly intuitive and I didn't have much trouble getting things working. I even figured out how to ask GTK what it's X window ID is. Most of this knowledge comes from the GDK X Windows Interaction documentation.

#include <gtk/gtk.h>
#include <gdk/gdkx.h>

static void activate(GtkWidget *widget, gpointer data) {
  // widget->window is the GdkWindow containing this widget.
  g_print("Display handle: %x\n", GDK_WINDOW_XDISPLAY(widget->window));
  g_print("Window id: %d\n", GDK_WINDOW_XID(widget->window));
}

int main(int argc, char **argv) {
  GtkWidget *window;

  gtk_init (&argc, &argv);
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);

  g_signal_connect(G_OBJECT(window), "realize",
                   G_CALLBACK(activate), NULL);

  gtk_widget_show_all(window);
  gtk_main();
  return 0;
}
Compiled with: gcc `pkg-config --cflags --libs x11` test.c

The little bit of GTK I wrote tonight can be found here. It's not much, but it does example how to use GTK and Xlib at the same time, on the same windows.

Oops... it's getting light outside. Naptime ;)

Command line xpath tool

I've recently found myself needing to do one-off scrapers to pull information from various services. However, using 'w3m -dump' doesn't always suffice when I need to parse html and maybe throw it at awk.

I know XSLT and XPath, but I don't know of a good xpath tool for the commandline. XML::XPath in perl comes with one, but it's not up to my demands.

So, like most problems I come across, I solved it myself. A simple query of "Show all external links" is very cumbersome to do in a one-off manner unless you've got the right tools. Here's how you do basically do it with xpath:

//a[not(contains(@href,"semicomplete.com")) and starts-with(@href, "http://")]/@href
It's a bit complicated, but whatever, I can express what I want, right? Toss this along with my new xpathtool project, and I can find out where the urls are going:
% GET www.semicomplete.com \
| ./xpathtool.sh --ihtml \
  '//a[not(contains(@href,"semicomplete.com")) and starts-with(@href, "http://")]'

http://www.viewvc.org/
http://www.oreillynet.com/sysadmin/
... etc ...
You can specify that the input is html with '--ihtml'. The output can be chosen as text, html, or xml. If you specify html or xml output, it will use <xsl:copy-of> instead of <xsl:value-of> for each node matched.
# output in xml, every anchor tag not obviously pointing locally
GET www.semicomplete.com \
| ./xpathtool.sh --ihtml --oxml \
  '//a[not(contains(@href,"semicomplete.com")) and starts-with(@href, "http://")]' \
| head -4

<?xml version="1.0"?>
<toplevel>
  <a href="http://www.viewvc.org/">ViewVC</a>
  <a href="http://www.oreillynet.com/sysadmin/">http://www.oreillynet.com/sysadmin/</a>

  ... etc ...
Interested? Try xpathtool.

How to annoy your coworkers a little less

I'm almost guaranteed to be wearing headphones while at work. I like music. However, when I leave my desk, I rarely pause mplayer. This leaves my headphones leaking out some barely audible nois that may annoy coworkers.

I always lock my workstation when I'm not at my desk. How do I automate a solution here?

xscreensaver lets you watch the state of the screensaver. Let's use this to pause mplayer when I leave, and unpause it when I return.

xscreensaver-command -watch \
  | while read a; do
    echo "$a" | grep '^LOCK' && pkill -STOP mplayer
    echo "$a" | grep '^UNBLANK' && pkill -CONT mplayer
  done
Running the above, mplayer gets suspended when I lock my workstation, and resumed when I unlock it.

keynav being ported to windows.

I'm in the process of porting keynav to Windows. I've never programmed in Visual Studio before, but I think it's going quite well considering I've never coded for this platform.

The current total lines of code is 277. I expect it to be about this number once I'm finished.

I'm writing it using Visual C++ Express, a free version of Visual Studio. Free (after free registration). From Microsoft. Very cool :)

So far I have screen splitting working correctly. My clip code is kinda borked. After I fix that, it should be completely trivial to add mouse movement calls. Since Windows doesn't typically use sloppy focus, I think I'll add extra code to figure out what window the mouse is over and give that window focus.

Keynav 1.0 (presented at Yahoo! Hack Day '06)

I finally took some time after work today to write up a good description of the keyboard screen navigation system I demoed at Hack Day. With the project page is a screencast demo. Hopefully you find it useful.

Go to the keynav project page

Reverse x2x invocation.

I have a machine that runs X but doesn't listen to inet connections (via -nolisten-tcp). What if I want to use x2x to this machine? Simple.
 ssh -tY thatmachine 'x2x -from $DISPLAY -to :0 -west' 
This will ssh to 'thatmachine' and forward X. This set's $DISPLAY on the remote machine, which you can then invoke x2x with specifying 'from' as $DISPLAY. This has the same effect as invoking:
 x2x -to thatmachine:0 -west 
Except you don't need to allow tcp X connections. :)

BarCamp San Francisco - Day 2 (barcampsf)

8am wake up. Concrete is bad for good sleep.

The concrete flooring here at the Microsoft office was certainly not the most comfortable. I woke up a number of times to adjust position. Oh well, I got sleep. It's not quite BarCamp if I don't sleep over, right? ;)

I held 4 sessions today, wow! Here goes for a summary of them:

In keeping with tradition, I gave an introductory presentation on AJAX. There was good attendance, and as in NYC there were still a great number of people who came to BarCamp but don't have huge clue about what some of these technologies actually are. I'm always glad to spread the clue. I also held a discussion about productivity software. During the productivity session, someone introduced me to ActiveWords. I watched some of the demo videos and I was left fairly impressed with the capabilities. Check it out for yourself if you run Windows, it's quite cool. Later today I was approached by a man who introduced himself as "Buzz" asking if I'm the guy with the pajamas. Turns out, this is Buzz Bruggeman, big whig man at ActiveWords Systems, Inc. Neat! He sat me down and showed me all of the cool things he does with ActiveWords. As a result, I found out about some new productivity software, and for that I consider the productivity session a huge success, personally.

ActiveWords is super cool. It addresses one of my bigger issues with computer interaction: Impulse-driven use is nearly impossible. Let me explain. Everyone has impulses during workflow. For instance, "I want to bring up gmail" - simple, right? First I've got to find firefox in the taskbar, bring it up, assuming I can find the particular firefox window I need. Then I have to hunt through a series of tabs which may or may not have useful information in the icon and titles. Hopefully I eventually find it, right? Quickly? Probably not. Why can't I just say "bring up gmail" and have it happen just like I described, but without the need for any extra effort on my part? You can't, though. ActiveWords attempts to address that. I was relieved with the ease by which it seemed you can do all of this impulse-driven work flow with ActiveWords.

Buzz is certainly a good salesman, I was sold after a few minutes. While I may not buy it, because my work environment is unix, I'm happy to plug it. I'm installing it as I'm writing this, so I'll review it shortly. Meanwhile, back to BarCamp SanFrancisco!

Where was I? It's about 11:30pm. There's a physician blogger sitting down the hall who many people are polling about funky medical questions and such.

Sessions, right. After the AJAX and productivity sessions, I mingled with many of the fine folks here at BarCamp. I think Chris Messina put it best when he described BarCamp as putting the hallway-type conversations in the spotlight. That is, conversations people have outside of the scope of work and deadlines and whatnot. Those are the best conversations anyway, right?

The next session I held was a firewall bypass session, mostly covering the use of SSH to tunnel traffic (for fun and profit?). Those in attendance seemed to think it was cool, so success there. I'll post notes to the BarCamp wiki later.

The next session I helped orchestrate was the "BarCamp Network Kit" project. The impetus for this session was due to random networking issues plagueing the network this morning and through the early afternon. I rememebered how BarCampNYC had lots of slow network issues, so I put up a session to discuss a potential "BarCamp Network In A Box" project. There were a good deal of strong network/sysadmin people here, The results of our discussion can be found www.barcamp.org/StarCampNetworkKit. With luck and lots of collaboration, and assuming someone steps up for organizing a BarCampEarth event in the bay area, perhaps the network kit can be demonstrated then?

[2 hours later...] I took a break from writing and went with some folks to a bar in North Beach(?). Something around 20th and Mission. Car bombs, talking about work, talking about other interests, and further alcohol consumption. Good times.

So it's not 3AM, and I'm exhausted from today's activities. Tonight is much better than the last, as many people are still awake. Two (swedish?) folks are working on getting some WordPress thing running, others are discussing politics and technology. I've been doing some ad-hoc sysadmin help for a folks that have been fighting the typical LAMP stuff just to get some form of blog or website online. It really ought to be easier to get a website up, eh? One particular instance was Debian running Apache2. I'm used to Apache2 built from source, but Debian makes *lots* of changes downstream before packages get to users. Why? Is it too much to ask for a bit of consistency?

There's been some interest in both my vim and unix seminars, so I'll probably do both tomorrow. Anyway, it's getting to be quite the naptime. I'm looking forward to tomorrow's events.