Pasting the Primary X Selection into Firefox
Sometimes I need to take a URL from some text app -- like a shell window, or an IRC comment -- and open it in Firefox.
If it's a standard http://, that's trivial: I highlight the URL with my house (often a doubleclick will do it), go to my Firefox window and middleclick somewhere in the content area, anywhere that's not a link, and Firefox goes to the URL.
That works because selecting anything, in X, copies the selection to the Primary selection buffer. The Primary selection is different from the Clipboard selection that's used with Windows and Mac style Ctrl-X/Ctrl-C/Ctrl-V copy and paste; it's faster and doesn't require switching between keyboard and mouse. Since your hand is already on the mouse (from selecting the text), you don't have to move to the keyboard to type Ctrl-C, then back to the mouse to go to the Firefox window, then back to the keyboard to type Ctrl-V.
But it fails in some cases. Like when someone says in IRC,
"There's a great example of that at coolhacks.org/greatexample".
You can highlight coolhacks.org/greatexample
and middleclick
in Firefox all you want, but Firefox doesn't recognize it as a URL and
won't go there. Or if I want to highlight a couple of search terms and
pass them into a Google search.
(Rant: middlemouse used to work for these cases, but it was
disabled -- without even an option for getting it back -- due to a lot of
whining in bugzilla by people coming from Windows backgrounds who
didn't like middleclick paste because they found it unexpected, yet
who weren't willing to turn it off with the
middlemouse.contentLoadURL
pref).
So in those cases, what I've been doing is:
- Highlight the URL or search terms
- Switch to the Firefox window
- Ctrl-L -- this focuses and highlights the URL bar without changing the X selection
- Backspace (or Ctrl-U, Ctrl-K, any key that clears the URLbar)
- Move the mouse to the URL bar (a small target) and middleclick
- Hit Enter
It works, but it's a lot more steps, and entails several switches between keyboard and mouse. Frustrating!
It would be a little less frustrating if I had a key binding in Firefox that said "Paste the current X primary selection." A web search shows that quite a few other people have been bothered by this problem -- for instance, discussions here and here, and plenty of bugs, like 228011, 1070518, and 1461168 -- but without any solutions, even though one of those bugs has a patch attached. Apparently in most apps, Ctrl-Insert inserts the Primary X selection -- but in Firefox and a few others, it inserts the Clipboard instead, just like Ctrl-C.
I could write my own fix, by unzipping Firefox's omni.ja file and editing various .xul and .js files inside it. (Update a decade later: probably not any more, as Mozilla has steadily reduced the number of things you can change in omni.ja and moved them into C++ code.) But if I were doing that, I could just as easily revert Firefox's original behavior of going to the link. Neither of these is difficult; the problem is that every time I Firefox updates (which is about twice a week these days), things break until I manually go in and unzip the jar and make my changes again. I used to do that, but I got tired of needing to do it so often. And I tried to do it via a Firefox extension, until Mozilla changed the Firefox extension API so that extensions couldn't modify key bindings any more.
Since Firefox changes so often, it's nicer to have a solution that's entirely outside of Firefox. And a comment in one of those discussion threads gave me an idea: make a key binding in my window manager that uses xset to copy the primary selection to the clipboard, then use my crikey program to insert a fake Ctrl-V that Firefox will see.
Here's a command to do that:
xsel -o -p | xsel -i -b; crikey -s 1 "^V"
xsel -o
prints a current X selection, and -p specifies
the Primary. xsel -i
sets an X selection to whatever it
gets on standard input (which in this case will be whatever was in the
Primary selection), and -b tells it to set the Clipboard selection.
Then crikey -s 1 "^V" waits one second (I'll probably reduce this after more testing) and then generates an X event for a Ctrl-V.
I bound that command to Ctrl-Insert in my window manager, Openbox, like this:
<keybind key="C-Insert"> <action name="Execute"> <execute>/bin/sh -c 'xsel -o -p | xsel -i -b; crikey -s 1 "^V"'</execute> </action> </keybind>Openbox didn't seem happy with the pipe, so I wrapped the whole thing in a
sh -c
.
Now, whenever I type Ctrl-Insert, whatever program I'm in will do a Ctrl-V but insert the Primary selection rather than the Clipboard. It should work in other recalcitrant programs, like LibreOffice, as well. In Firefox, now, I just have to type Ctrl-L Ctrl-Insert Return.
Of course, it's easy enough to make a binding specific to Firefox that does the Ctrl-L and the Return automatically. I've bound that to Alt-Insert, and its execute line looks like this:
<execute>/bin/sh -c 'xsel -o -p | xsel -i -b; crikey -s 1 "^L^V\\n"'</execute>
Fun with Linux! Now the only hard part will be remembering to use the bindings instead of doing things the hard way.
Update, August 2025:
For a cleaner workaround that maintains separation between the Primary and
Clipboard selections, see
this askbuntu thread
which uses
sh -c 'xsel | xvkbd -xsendevent -file - 2>/dev/null'
(the -xsendevent part doesn't seem to be needed).
Update, August 2025:
For a cleaner workaround that maintains separation between the Primary and
Clipboard selections, see
this askbuntu thread
which uses
sh -c 'xsel | xvkbd -xsendevent -file - 2>/dev/null'
(the -xsendevent part doesn't seem to be needed). Other people in
that thread suggest
xdotool click --clearmodifiers 2
or
xdotool click --delay 0 --clearmodifiers 2
or
since xdotool correctly handles multi-byte strings, unlike xvkbd.
However, you have to position the mouse before you simulate the
middle-mouse click. There are some other approaches there too.
The thread is well worth reading if you're frustrated by Firefox's
silly nonstandard behavior or just want to learn about
ways of handling X selections.
[ 20:35 Mar 26, 2013 More linux/cmdline | permalink to this entry | ]
Wed, 19 Aug 2009
Crikey 0.8.3: bug fixes and several new syntaxes
Sometimes I love open source. A user contacted me about my program Crikey!, which lets you generate key events to do things like assign a key that will type in a string you don't want to type in by hand. He had some thorny problems where crikey was failing, and a few requests, like sending Alt and other modifier keys.We corresponded a bit, figured out exactly how things should work and some test cases, went through a couple iterations of changes where I got lots of detailed and thoughtful feedback and more test cases, and now Crikey can do an assortment of new useful stuff.
New features: crikey now handles number codes like \27, modifier keys like \A for alt, does a better job with symbols like \(Return\), and handles a couple of new special characters like \e for escape. It also works better at sending window manager commands, like "\A\t" to change the active window.
I've added some better documentation on all the syntaxes it understands, both on the web page and in the -h and -l (longhelp) command-line arguments, and made a release: crikey 0.8.3.
Plus: a list of great regression tests that I can use when testing future updates (in the file TESTING in the tarball).
[ 17:38 Aug 19, 2009 More programming | permalink to this entry | ]
Wed, 14 Jan 2009
Crikey 0.8
Mostly this week has been consumed with preparations for LCA ... but programming is a sickness. When you get email from someone suggesting something relatively simple and obviously useful, well ... it's simply impossible not to pull out that emacs window and start typing.And so it was when I got a request for a backspace character in crikey. Of course backspace and delete seem like perfectly reasonable and useful characters to want; don't know why I didn't think of putting them in before. So I did.
But while I was in there, suddenly it occurred to me that it really wouldn't be much harder to let users specify any key by symbol. (Did I mention being a programmer is a sickness?) And then I realized that specifying control characters with a caret, like ^H, would also be quite useful. (Did I mention that ...)
So anyway, now there's a Crikey 0.8 and it's time to get back to packing and endless fiddling with my talk slides. Except, wait, I need to update my netscheme script to work right with the new laptop, and ...
Did I mention that programming is a sickness?
[ 21:56 Jan 14, 2009 More programming | permalink to this entry | ]
Sun, 25 May 2008
Crikey in Python, and generating key events with XTest
A user on the One Laptop Per Child (OLPC, also known as the XO) platform wrote to ask me how to use crikey on that platform.There are two stages to getting crikey running on a new platform:
- Build it, and
- Figure out how to make a key run a specific program.
The crikey page contains instructions I've collected for binding keys in various window managers, since that's usually the hard part. On normal Linux machines the first step is normally no problem. But apparently the OLPC comes with gcc but without make or the X header files. (Not too surprising: it's not a machine aimed at developers and I assume most people developing for the machine cross-compile from a more capable Linux box.)
We're still working on that (if my correspondant gets it working, I'll post the instructions), but while I was googling for information about the OLPC's X environment I stumbled upon a library I didn't know existed: python-xlib. It turns out it's possible to do most or all of what crikey does from Python. The OLPC is Python based; if I could write crikey in Python, it might solve the problem. So I whipped up a little key event generating script as a test.
Unfortunately, it didn't solve the OLPC problem (they don't include python-xlib on the machine either) but it was a fun exercises, and might be useful as an example of how to generate key events in python-xlib. It supports both event generating methods: the X Test extension and XSendEvent. Here's the script: /pykey-0.1.
But while I was debugging the X Test code, I had to solve a bug that I didn't remember ever solving in the C version of crikey. Sure enough, it needed the same fix I'd had to do in the python version. Two fixes, actually. First, when you send a fake key event through XTest, there's no way to specify a shift mask. So if you need a shifted character like A, you have to send KeyPress Shift, KeyPress a. But if that's all you send, XTest on some systems does exactly what the real key would do if held down and never released: it autorepeats. (But only for a little while, not forever. Go figure.)
So the real answer is to send KeyPress Shift, KeyPress a, KeyRelease a, KeyRelease Shift. Then everything works nicely. I've updated crikey accordingly and released version 0.7 (though since XTest isn't used by default, most users won't see any change from 0.6). In the XSendEvent case, crikey still doesn't send the KeyRelease event -- because some systems actually see it as another KeyPress. (Hey, what fun would computers be if they were consistent and always predictable, huh?)
Both C and Python versions are linked off the crikey page.
[ 15:50 May 25, 2008 More programming | permalink to this entry | ]