summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2018-02-09 22:03:21 -0500
committerLuke Shumaker <lukeshu@lukeshu.com>2018-02-09 22:04:32 -0500
commitc49a93bedf3e7cb7328aa8b354c0307199405480 (patch)
tree1daa07c23c122b7e36bdaf66fc1cf7315f0ccbf9
parent4bd8ed3045197132ae8a3eef5303757dbecb8514 (diff)
parent031ceb664aa37672cfc0835d13f97a99f2451ea4 (diff)
make: add posix-pricing article
-rw-r--r--public/index.atom131
-rw-r--r--public/index.html2
-rw-r--r--public/index.md2
-rw-r--r--public/kbd-xmodmap.html117
-rw-r--r--public/kbd-xmodmap.md244
-rw-r--r--public/posix-pricing.html24
-rw-r--r--public/posix-pricing.md31
7 files changed, 550 insertions, 1 deletions
diff --git a/public/index.atom b/public/index.atom
index bc1b887..8f3fefa 100644
--- a/public/index.atom
+++ b/public/index.atom
@@ -5,12 +5,141 @@
<link rel="self" type="application/atom+xml" href="./index.atom"/>
<link rel="alternate" type="text/html" href="./"/>
<link rel="alternate" type="text/markdown" href="./index.md"/>
- <updated>2016-09-30T00:00:00+00:00</updated>
+ <updated>2018-02-09T00:00:00+00:00</updated>
<author><name>Luke Shumaker</name><uri>https://lukeshu.com/</uri><email>lukeshu@sbcglobal.net</email></author>
<id>https://lukeshu.com/blog/</id>
<entry xmlns="http://www.w3.org/2005/Atom">
+ <link rel="alternate" type="text/html" href="./posix-pricing.html"/>
+ <link rel="alternate" type="text/markdown" href="./posix-pricing.md"/>
+ <id>https://lukeshu.com/blog/posix-pricing.html</id>
+ <updated>2018-02-09T00:00:00+00:00</updated>
+ <published>2018-02-09T00:00:00+00:00</published>
+ <title>POSIX pricing and availability; or: Do you really need the PDF?</title>
+ <content type="html">&lt;h1 id="posix-pricing-and-availability-or-do-you-really-need-the-pdf"&gt;POSIX pricing and availability; or: Do you really need the PDF?&lt;/h1&gt;
+&lt;p&gt;The Open Group and IEEE are weird about POSIX pricing. They’re protective of the PDF, making you pay &lt;a href="http://standards.ieee.org/findstds/standard/1003.1-2008.html"&gt;hundreds of dollars&lt;/a&gt; for the PDF; but will happily post an HTML version for free both &lt;a href="http://pubs.opengroup.org/onlinepubs/9699919799/"&gt;online&lt;/a&gt;, and (with free account creation) download as a &lt;a href="https://www2.opengroup.org/ogsys/catalog/t101"&gt;a .zip&lt;/a&gt;.&lt;/p&gt;
+&lt;p&gt;They also offer a special license to the “Linux man-pages” project, allowing them to &lt;a href="https://www.kernel.org/pub/linux/docs/man-pages/man-pages-posix/"&gt;distribute&lt;/a&gt; the man page portions of POSIX (most of it is written as a series of man pages) for free; so on a GNU/Linux box, you probably have most of POSIX already downloaded in manual sections 0p, 1p, and 3p.&lt;/p&gt;
+&lt;p&gt;Anyway, the only thing you aren’t getting with the free HTML version is a line number next to every line of text. It’s generated from the same troff sources. So, in an article or in a discussion, I’m not cheating you out of specification details by citing the webpage.&lt;/p&gt;
+&lt;p&gt;If you’re concerned that you’re looking at the correct version of the webpage or man pages, the current version (as of February 2018) of POSIX is “POSIX-2008, 2016 edition.”&lt;/p&gt;
+</content>
+ <author><name>Luke Shumaker</name><uri>https://lukeshu.com/</uri><email>lukeshu@sbcglobal.net</email></author>
+ <rights type="html">&lt;p&gt;The content of this page is Copyright © 2018 &lt;a href="mailto:lukeshu@sbcglobal.net"&gt;Luke Shumaker&lt;/a&gt;.&lt;/p&gt;
+&lt;p&gt;This page is licensed under the &lt;a href="https://creativecommons.org/licenses/by-sa/3.0/"&gt;CC BY-SA-3.0&lt;/a&gt; license.&lt;/p&gt;</rights>
+ </entry>
+
+ <entry xmlns="http://www.w3.org/2005/Atom">
+ <link rel="alternate" type="text/html" href="./kbd-xmodmap.html"/>
+ <link rel="alternate" type="text/markdown" href="./kbd-xmodmap.md"/>
+ <id>https://lukeshu.com/blog/kbd-xmodmap.html</id>
+ <updated>2018-02-09T00:00:00+00:00</updated>
+ <published>2018-02-09T00:00:00+00:00</published>
+ <title>GNU/Linux Keyboard Maps: xmodmap</title>
+ <content type="html">&lt;h1 id="gnulinux-keyboard-maps-xmodmap"&gt;GNU/Linux Keyboard Maps: xmodmap&lt;/h1&gt;
+&lt;p&gt;The modmap subsystem is part of the core &lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html"&gt;X11 protocol&lt;/a&gt;. However, it has been replaced by the &lt;a href="https://www.x.org/releases/current/doc/kbproto/xkbproto.html"&gt;X Keyboard (XKB) Extension&lt;/a&gt; to the protocol, which defines a facade that emulates the legacy modmap subsystem so that old programs still work—including those that manipulate the modmap directly!&lt;/p&gt;
+&lt;p&gt;For people who like to Keep It Stupid Simple, the XKB extension looks horribly complicated and gross—even ignoring protocol details, the configuration syntax is a monstrosity! There’s no way to say something like “I’d like to remap Caps-Lock to be Control”, you have to copy and edit the entire keyboard definition, which includes mucking with vector graphics of the physical keyboard layout! So it’s very tempting to pretend that XKB doesn’t exist, and it’s still using modmap.&lt;/p&gt;
+&lt;p&gt;However, this is a leaky abstraction; for instance: when running the &lt;code&gt;xmodmap&lt;/code&gt; command to manipulate the modmap, if you have multiple keyboards plugged in, the result can depend on which keyboard you used to press “enter” after typing the command!&lt;/p&gt;
+&lt;p&gt;Despite only existing as a compatibility shim today, I think it is important to understand the modmap subsystem to understand modern XKB.&lt;/p&gt;
+&lt;h2 id="conceptual-overview"&gt;Conceptual overview&lt;/h2&gt;
+&lt;p&gt;There are 3 fundamental tasks that the modmap subsystem performs:&lt;/p&gt;
+&lt;ol type="1"&gt;
+&lt;li&gt;&lt;code&gt;keyboard: map keycode -&amp;gt; keysym&lt;/code&gt; (client-side)&lt;/li&gt;
+&lt;li&gt;&lt;code&gt;keyboard: map keycode -&amp;gt; modifier bitmask&lt;/code&gt; (server-side)&lt;/li&gt;
+&lt;li&gt;&lt;code&gt;pointer: map physical button -&amp;gt; logical button&lt;/code&gt; (server-side)&lt;/li&gt;
+&lt;/ol&gt;
+&lt;p&gt;You’re thinking: “Great, so the X server does these things for us!” Nope! Not entirely, anyway. It does the keycode-&amp;gt;modifier lookup, and the mouse-button lookup, but the keycode-&amp;gt;keysym lookup must be done client-side by querying the mapping stored on the server. Generally, this is done automatically inside of libX11/libxcb, and the actual client application code doesn’t need to worry about it.&lt;/p&gt;
+&lt;p&gt;So, what’s the difference between a keycode and a keysym, and how’s the modifier bitmask work?&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;p&gt;keycode: A numeric ID for a hardware button; this is as close the the hardware as X11 modmaps let us get. These are conceptually identical to Linux kernel keycodes, but the numbers don’t match up. Xorg keycodes are typically &lt;code&gt;linux_keycode+8&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;keysym: A 29-bit integer code that is meaningful to applications. A mapping of these to symbolic names is defined in &lt;code&gt;&amp;lt;X11/keysymdef.h&amp;gt;&lt;/code&gt; and augmented by &lt;code&gt;/usr/share/X11/XKeysymDB&lt;/code&gt;. See: &lt;code&gt;XStringToKeysym()&lt;/code&gt; and &lt;code&gt;XKeysymToString()&lt;/code&gt;. We will generally use the symbolic name in the modmap file. The symbolic names are case-sensitive.&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;Modifier state: An 8-bit bitmask of modifier keys (names are case-insensitive):&lt;/p&gt;
+&lt;pre&gt;&lt;code&gt;1 &amp;lt;&amp;lt; 0 : shift
+1 &amp;lt;&amp;lt; 1 : lock
+1 &amp;lt;&amp;lt; 2 : control
+1 &amp;lt;&amp;lt; 3 : mod1
+1 &amp;lt;&amp;lt; 4 : mod2
+1 &amp;lt;&amp;lt; 5 : mod3
+1 &amp;lt;&amp;lt; 6 : mod4
+1 &amp;lt;&amp;lt; 7 : mod5&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;With that knowledge, and the libX11/libxcb API docs, you can probably figure out how to interact with the modmap subsystem from C, but who does that? Everyone just uses the &lt;code&gt;xmodmap(1)&lt;/code&gt; command.&lt;/p&gt;
+&lt;h2 id="the-x11-protocol"&gt;The X11 protocol&lt;/h2&gt;
+&lt;p&gt;As I said, the modifier and button lookup is handled server-side; each of the &lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:input"&gt;input events&lt;/a&gt; ({Key,Button}{Press,Release}, and MotionNotify) and &lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:pointer_window"&gt;pointer window events&lt;/a&gt; ({Enter,Leave}Notify) include a bitmask of active keyboard modifiers and pointer buttons. Each are given an 8-bit bitmask—hence 8 key modifiers. For some reason, only up to Button5 is included in the bitmask; the upper 3 bits are always zero; but the Button{Press,Release} events will happily deliver events for up to Button255!&lt;/p&gt;
+&lt;p&gt;The X11 protocol has 6 request types for dealing with these 3 mappings; an accessor and a mutator pair for each. Since the 2 of the mappings are done server-side, of these, most clients will only use GetKeyboardMapping. Anyway, let’s look at those 6 requests, grouped by the mappings that they work with (pardon the Java-like pseudo-code syntax for indicating logical argument and return types):&lt;/p&gt;
+&lt;ol type="1"&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;keyboard: map keycode -&amp;gt; keysym&lt;/code&gt;&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetKeyboardMapping"&gt;GetKeyboardMapping&lt;/a&gt; :: &lt;code&gt;List&amp;lt;keycode&amp;gt; -&amp;gt; Map&amp;lt;keycode,List&amp;lt;keysym&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangeKeyboardMapping"&gt;ChangeKeyboardMapping&lt;/a&gt; :: &lt;code&gt;Map&amp;lt;keycode,List&amp;lt;keysym&amp;gt;&amp;gt; -&amp;gt; ()&lt;/code&gt;&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;&lt;code&gt;GetKeyboardMapping&lt;/code&gt; returns the keycode-&amp;gt;keysym mappings for the requested keycodes; this way clients can choose to look up only the keycodes that they need to handle (the ones that got sent to them). Each keycode gets a list of keysyms; which keysym they should use from that list depends on which modifiers are pressed. &lt;code&gt;ChangeKeyboardMapping&lt;/code&gt; changes the mapping for the given keycodes; not all keycodes must be given, any keycodes that aren’t included in the request aren’t changed.&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;keyboard: map keycode -&amp;gt; modifier bitmask&lt;/code&gt;&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetModifierMapping"&gt;GetModifierMapping&lt;/a&gt; :: &lt;code&gt;() -&amp;gt; Map&amp;lt;modifier,List&amp;lt;keycode&amp;gt;&amp;gt;&lt;/code&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:SetModifierMapping"&gt;SetModifierMapping&lt;/a&gt; :: &lt;code&gt;Map&amp;lt;modifier,List&amp;lt;keycode&amp;gt;&amp;gt; -&amp;gt; ()&lt;/code&gt;&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;The modifiers mapping is a lot smaller than the keysym mapping; you must operate on the entire mapping at once. For each modifier bit, there’s a list of keycodes that will cause that modifier bit to be flipped in the events that are delivered while it is pressed.&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;pointer: map physical button -&amp;gt; logical button&lt;/code&gt;&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetPointerMapping"&gt;GetPointerMapping&lt;/a&gt; &lt;code&gt;() -&amp;gt; List&amp;lt;logicalButton&amp;gt;&lt;/code&gt; (indexed by &lt;code&gt;physicalButton-1&lt;/code&gt;)&lt;/li&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:SetPointerMapping"&gt;SetPointerMapping&lt;/a&gt; &lt;code&gt;List&amp;lt;logicalButton&amp;gt; -&amp;gt; ()&lt;/code&gt; (indexed by &lt;code&gt;physicalButton-1&lt;/code&gt;)&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;Like the modifier mapping, the button mapping is expected to be small, most mice only have 5-7 buttons (left, middle, right, scroll up, scroll down, scroll left, scroll right—that’s right, X11 handles scroll events as button presses), though some fancy gaming mice have more than that, but not much more.&lt;/p&gt;&lt;/li&gt;
+&lt;/ol&gt;
+&lt;p&gt;I mentioned earlier that the keycode-&amp;gt;keysym mapping isn’t actually done by the X server, and is done in the client; whenever a client receives a key event or pointer button event, it must do a &lt;code&gt;Get*Mapping&lt;/code&gt; request to see what that translates to. Of course, doing a that for every keystroke would be crazy; but at the same time, the each client is expected to know about changes to the mappings that happen at run-time. So, each of the “set”/“change” commands generate a &lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:MappingNotify"&gt;MappingNotify&lt;/a&gt; event that is sent to all clients, so they know when they must dump their cache of mappings.&lt;/p&gt;
+&lt;p&gt;For completeness, if you are looking at this as background for understanding XKB, I should also mention:&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetKeyboardControl"&gt;GetKeyboardControl&lt;/a&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangeKeyboardControl"&gt;ChangeKeyboardControl&lt;/a&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetPointerControl"&gt;GetPointerControl&lt;/a&gt;&lt;/li&gt;
+&lt;li&gt;&lt;a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangePointerControl"&gt;ChangePointerControl&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+&lt;h2 id="the-xmodmap-command"&gt;The &lt;code&gt;xmodmap&lt;/code&gt; command&lt;/h2&gt;
+&lt;p&gt;The &lt;code&gt;xmodmap&lt;/code&gt; command reads a configuration file and modifies the maps in the X server to match. The &lt;code&gt;xmodmap&lt;/code&gt; config file has its own little quirky syntax. For one, the comment character is &lt;code&gt;!&lt;/code&gt; (and comments may only start at the &lt;em&gt;beginning&lt;/em&gt; of the line, but that’s fairly common).&lt;/p&gt;
+&lt;p&gt;There are 8 commands that &lt;code&gt;xmodmap&lt;/code&gt; recognizes. Let’s look at those, grouped by the 3 tasks that the modmap subsystem performs:&lt;/p&gt;
+&lt;ol type="1"&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;keyboard: map keycode -&amp;gt; keysym&lt;/code&gt;&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;keycode KEYCODE = PLAIN [SHIFT [MODE_SWITCH [MODE_SWITCH+SHIFT ]]]&lt;/code&gt;&lt;/p&gt;
+&lt;p&gt;Actually takes a list of up to 8 keysyms, but only the first 4 have standard uses.&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;keysym OLD_KEYSYM = NEW_KEYSYMS...&lt;/code&gt;&lt;/p&gt;
+&lt;p&gt;Takes the keycodes mapped to &lt;code&gt;OLD_KEYSYM&lt;/code&gt; and maps them to &lt;code&gt;NEW_KEYSYM&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;keysym any = KEYSYMS...&lt;/code&gt;&lt;/p&gt;
+&lt;p&gt;Finds an otherwise unused keycode, and has it map to the specified keysyms.&lt;/p&gt;&lt;/li&gt;
+&lt;/ul&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;keyboard: map keycode -&amp;gt; modifier bitmask&lt;/code&gt;&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;code&gt;clear MODIFIER&lt;/code&gt;&lt;/li&gt;
+&lt;li&gt;&lt;code&gt;add MODIFIERNAME = KEYSYMS...&lt;/code&gt;&lt;/li&gt;
+&lt;li&gt;&lt;code&gt;remove MODIFIERNAME = KEYSYMS...&lt;/code&gt;&lt;/li&gt;
+&lt;/ul&gt;
+&lt;p&gt;Wait, the modmap subsystem maps &lt;em&gt;keycodes&lt;/em&gt; to modifiers, but the commands take &lt;em&gt;keysyms&lt;/em&gt;? Yup! When executing one of these commands, it first looks up those keysyms in the keyboard map to translate them in to a set of keycodes, then associates those keycodes with that modifier. But how does it look up keysym-&amp;gt;keycode; the protocol only supports querying keycode-&amp;gt;keysym? It &lt;a href="https://cgit.freedesktop.org/xorg/app/xmodmap/tree/handle.c?h=xmodmap-1.0.9#n59"&gt;loops&lt;/a&gt; over &lt;em&gt;every&lt;/em&gt; keycode finding all the matches.&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;pointer: map physical button -&amp;gt; logical button&lt;/code&gt;&lt;/p&gt;
+&lt;ul&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;pointer = default&lt;/code&gt;&lt;/p&gt;
+&lt;p&gt;This is equivalent to &lt;code&gt;pointer = 1 2 3 4 5 6...&lt;/code&gt; where the list is as long as the number of buttons that there are.&lt;/p&gt;&lt;/li&gt;
+&lt;li&gt;&lt;p&gt;&lt;code&gt;pointer = NUMBERS...&lt;/code&gt;&lt;/p&gt;
+&lt;p&gt;&lt;code&gt;pointer = A B C D...&lt;/code&gt; sets the physical button 1 to logical button A, physical button 2 to logical button B, and so on. Setting a physical button to logical button 0 disables that button.&lt;/p&gt;&lt;/li&gt;
+&lt;/ul&gt;&lt;/li&gt;
+&lt;/ol&gt;
+&lt;h2 id="appendix"&gt;Appendix:&lt;/h2&gt;
+&lt;p&gt;I use this snippet in my Emacs configuration to make editing xmodmap files nicer:&lt;/p&gt;
+&lt;pre&gt;&lt;code&gt;;; http://www.emacswiki.org/emacs/XModMapMode
+(when (not (fboundp &amp;#39;xmodmap-mode))
+ (define-generic-mode &amp;#39;xmodmap-mode
+ &amp;#39;(?!)
+ &amp;#39;(&amp;quot;add&amp;quot; &amp;quot;clear&amp;quot; &amp;quot;keycode&amp;quot; &amp;quot;keysym&amp;quot; &amp;quot;pointer&amp;quot; &amp;quot;remove&amp;quot;)
+ nil
+ &amp;#39;(&amp;quot;[xX]modmap\\(rc\\)?\\&amp;#39;&amp;quot;)
+ nil
+ &amp;quot;Simple mode for xmodmap files.&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
+</content>
+ <author><name>Luke Shumaker</name><uri>https://lukeshu.com/</uri><email>lukeshu@sbcglobal.net</email></author>
+ <rights type="html">&lt;p&gt;The content of this page is Copyright © 2018 &lt;a href="mailto:lukeshu@sbcglobal.net"&gt;Luke Shumaker&lt;/a&gt;.&lt;/p&gt;
+&lt;p&gt;This page is licensed under the &lt;a href="https://creativecommons.org/licenses/by-sa/3.0/"&gt;CC BY-SA-3.0&lt;/a&gt; license.&lt;/p&gt;</rights>
+ </entry>
+
+ <entry xmlns="http://www.w3.org/2005/Atom">
<link rel="alternate" type="text/html" href="./http-notes.html"/>
<link rel="alternate" type="text/markdown" href="./http-notes.md"/>
<id>https://lukeshu.com/blog/http-notes.html</id>
diff --git a/public/index.html b/public/index.html
index 87e9985..e967651 100644
--- a/public/index.html
+++ b/public/index.html
@@ -20,6 +20,8 @@ time {
}
</style>
<ul>
+<li><time>2018-02-09</time> - <a href="./posix-pricing.html">POSIX pricing and availability; or: Do you really need the PDF?</a></li>
+<li><time>2018-02-09</time> - <a href="./kbd-xmodmap.html">GNU/Linux Keyboard Maps: xmodmap</a></li>
<li><time>2016-09-30</time> - <a href="./http-notes.html">Notes on subtleties of HTTP implementation</a></li>
<li><time>2016-02-28</time> - <a href="./x11-systemd.html">My X11 setup with systemd</a></li>
<li><time>2016-02-28</time> - <a href="./java-segfault-redux.html">My favorite bug: segfaults in Java (redux)</a></li>
diff --git a/public/index.md b/public/index.md
index a479d58..20a0750 100644
--- a/public/index.md
+++ b/public/index.md
@@ -10,6 +10,8 @@ time {
}
</style>
+ * <time>2018-02-09</time> - [POSIX pricing and availability; or: Do you really need the PDF?](./posix-pricing.html)
+ * <time>2018-02-09</time> - [GNU/Linux Keyboard Maps: xmodmap](./kbd-xmodmap.html)
* <time>2016-09-30</time> - [Notes on subtleties of HTTP implementation](./http-notes.html)
* <time>2016-02-28</time> - [My X11 setup with systemd](./x11-systemd.html)
* <time>2016-02-28</time> - [My favorite bug: segfaults in Java (redux)](./java-segfault-redux.html)
diff --git a/public/kbd-xmodmap.html b/public/kbd-xmodmap.html
new file mode 100644
index 0000000..7bed4d8
--- /dev/null
+++ b/public/kbd-xmodmap.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>GNU/Linux Keyboard Maps: xmodmap — Luke Shumaker</title>
+ <link rel="stylesheet" href="assets/style.css">
+ <link rel="alternate" type="application/atom+xml" href="./index.atom" name="web log entries"/>
+</head>
+<body>
+<header><a href="/">Luke Shumaker</a> » <a href=/blog>blog</a> » kbd-xmodmap</header>
+<article>
+<h1 id="gnulinux-keyboard-maps-xmodmap">GNU/Linux Keyboard Maps: xmodmap</h1>
+<p>The modmap subsystem is part of the core <a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html">X11 protocol</a>. However, it has been replaced by the <a href="https://www.x.org/releases/current/doc/kbproto/xkbproto.html">X Keyboard (XKB) Extension</a> to the protocol, which defines a facade that emulates the legacy modmap subsystem so that old programs still work—including those that manipulate the modmap directly!</p>
+<p>For people who like to Keep It Stupid Simple, the XKB extension looks horribly complicated and gross—even ignoring protocol details, the configuration syntax is a monstrosity! There’s no way to say something like “I’d like to remap Caps-Lock to be Control”, you have to copy and edit the entire keyboard definition, which includes mucking with vector graphics of the physical keyboard layout! So it’s very tempting to pretend that XKB doesn’t exist, and it’s still using modmap.</p>
+<p>However, this is a leaky abstraction; for instance: when running the <code>xmodmap</code> command to manipulate the modmap, if you have multiple keyboards plugged in, the result can depend on which keyboard you used to press “enter” after typing the command!</p>
+<p>Despite only existing as a compatibility shim today, I think it is important to understand the modmap subsystem to understand modern XKB.</p>
+<h2 id="conceptual-overview">Conceptual overview</h2>
+<p>There are 3 fundamental tasks that the modmap subsystem performs:</p>
+<ol type="1">
+<li><code>keyboard: map keycode -&gt; keysym</code> (client-side)</li>
+<li><code>keyboard: map keycode -&gt; modifier bitmask</code> (server-side)</li>
+<li><code>pointer: map physical button -&gt; logical button</code> (server-side)</li>
+</ol>
+<p>You’re thinking: “Great, so the X server does these things for us!” Nope! Not entirely, anyway. It does the keycode-&gt;modifier lookup, and the mouse-button lookup, but the keycode-&gt;keysym lookup must be done client-side by querying the mapping stored on the server. Generally, this is done automatically inside of libX11/libxcb, and the actual client application code doesn’t need to worry about it.</p>
+<p>So, what’s the difference between a keycode and a keysym, and how’s the modifier bitmask work?</p>
+<ul>
+<li><p>keycode: A numeric ID for a hardware button; this is as close the the hardware as X11 modmaps let us get. These are conceptually identical to Linux kernel keycodes, but the numbers don’t match up. Xorg keycodes are typically <code>linux_keycode+8</code>.</p></li>
+<li><p>keysym: A 29-bit integer code that is meaningful to applications. A mapping of these to symbolic names is defined in <code>&lt;X11/keysymdef.h&gt;</code> and augmented by <code>/usr/share/X11/XKeysymDB</code>. See: <code>XStringToKeysym()</code> and <code>XKeysymToString()</code>. We will generally use the symbolic name in the modmap file. The symbolic names are case-sensitive.</p></li>
+<li><p>Modifier state: An 8-bit bitmask of modifier keys (names are case-insensitive):</p>
+<pre><code>1 &lt;&lt; 0 : shift
+1 &lt;&lt; 1 : lock
+1 &lt;&lt; 2 : control
+1 &lt;&lt; 3 : mod1
+1 &lt;&lt; 4 : mod2
+1 &lt;&lt; 5 : mod3
+1 &lt;&lt; 6 : mod4
+1 &lt;&lt; 7 : mod5</code></pre></li>
+</ul>
+<p>With that knowledge, and the libX11/libxcb API docs, you can probably figure out how to interact with the modmap subsystem from C, but who does that? Everyone just uses the <code>xmodmap(1)</code> command.</p>
+<h2 id="the-x11-protocol">The X11 protocol</h2>
+<p>As I said, the modifier and button lookup is handled server-side; each of the <a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:input">input events</a> ({Key,Button}{Press,Release}, and MotionNotify) and <a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:pointer_window">pointer window events</a> ({Enter,Leave}Notify) include a bitmask of active keyboard modifiers and pointer buttons. Each are given an 8-bit bitmask—hence 8 key modifiers. For some reason, only up to Button5 is included in the bitmask; the upper 3 bits are always zero; but the Button{Press,Release} events will happily deliver events for up to Button255!</p>
+<p>The X11 protocol has 6 request types for dealing with these 3 mappings; an accessor and a mutator pair for each. Since the 2 of the mappings are done server-side, of these, most clients will only use GetKeyboardMapping. Anyway, let’s look at those 6 requests, grouped by the mappings that they work with (pardon the Java-like pseudo-code syntax for indicating logical argument and return types):</p>
+<ol type="1">
+<li><p><code>keyboard: map keycode -&gt; keysym</code></p>
+<ul>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetKeyboardMapping">GetKeyboardMapping</a> :: <code>List&lt;keycode&gt; -&gt; Map&lt;keycode,List&lt;keysym&gt;&gt;</code></li>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangeKeyboardMapping">ChangeKeyboardMapping</a> :: <code>Map&lt;keycode,List&lt;keysym&gt;&gt; -&gt; ()</code></li>
+</ul>
+<p><code>GetKeyboardMapping</code> returns the keycode-&gt;keysym mappings for the requested keycodes; this way clients can choose to look up only the keycodes that they need to handle (the ones that got sent to them). Each keycode gets a list of keysyms; which keysym they should use from that list depends on which modifiers are pressed. <code>ChangeKeyboardMapping</code> changes the mapping for the given keycodes; not all keycodes must be given, any keycodes that aren’t included in the request aren’t changed.</p></li>
+<li><p><code>keyboard: map keycode -&gt; modifier bitmask</code></p>
+<ul>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetModifierMapping">GetModifierMapping</a> :: <code>() -&gt; Map&lt;modifier,List&lt;keycode&gt;&gt;</code></li>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:SetModifierMapping">SetModifierMapping</a> :: <code>Map&lt;modifier,List&lt;keycode&gt;&gt; -&gt; ()</code></li>
+</ul>
+<p>The modifiers mapping is a lot smaller than the keysym mapping; you must operate on the entire mapping at once. For each modifier bit, there’s a list of keycodes that will cause that modifier bit to be flipped in the events that are delivered while it is pressed.</p></li>
+<li><p><code>pointer: map physical button -&gt; logical button</code></p>
+<ul>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetPointerMapping">GetPointerMapping</a> <code>() -&gt; List&lt;logicalButton&gt;</code> (indexed by <code>physicalButton-1</code>)</li>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:SetPointerMapping">SetPointerMapping</a> <code>List&lt;logicalButton&gt; -&gt; ()</code> (indexed by <code>physicalButton-1</code>)</li>
+</ul>
+<p>Like the modifier mapping, the button mapping is expected to be small, most mice only have 5-7 buttons (left, middle, right, scroll up, scroll down, scroll left, scroll right—that’s right, X11 handles scroll events as button presses), though some fancy gaming mice have more than that, but not much more.</p></li>
+</ol>
+<p>I mentioned earlier that the keycode-&gt;keysym mapping isn’t actually done by the X server, and is done in the client; whenever a client receives a key event or pointer button event, it must do a <code>Get*Mapping</code> request to see what that translates to. Of course, doing a that for every keystroke would be crazy; but at the same time, the each client is expected to know about changes to the mappings that happen at run-time. So, each of the “set”/“change” commands generate a <a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:MappingNotify">MappingNotify</a> event that is sent to all clients, so they know when they must dump their cache of mappings.</p>
+<p>For completeness, if you are looking at this as background for understanding XKB, I should also mention:</p>
+<ul>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetKeyboardControl">GetKeyboardControl</a></li>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangeKeyboardControl">ChangeKeyboardControl</a></li>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetPointerControl">GetPointerControl</a></li>
+<li><a href="https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangePointerControl">ChangePointerControl</a></li>
+</ul>
+<h2 id="the-xmodmap-command">The <code>xmodmap</code> command</h2>
+<p>The <code>xmodmap</code> command reads a configuration file and modifies the maps in the X server to match. The <code>xmodmap</code> config file has its own little quirky syntax. For one, the comment character is <code>!</code> (and comments may only start at the <em>beginning</em> of the line, but that’s fairly common).</p>
+<p>There are 8 commands that <code>xmodmap</code> recognizes. Let’s look at those, grouped by the 3 tasks that the modmap subsystem performs:</p>
+<ol type="1">
+<li><p><code>keyboard: map keycode -&gt; keysym</code></p>
+<ul>
+<li><p><code>keycode KEYCODE = PLAIN [SHIFT [MODE_SWITCH [MODE_SWITCH+SHIFT ]]]</code></p>
+<p>Actually takes a list of up to 8 keysyms, but only the first 4 have standard uses.</p></li>
+<li><p><code>keysym OLD_KEYSYM = NEW_KEYSYMS...</code></p>
+<p>Takes the keycodes mapped to <code>OLD_KEYSYM</code> and maps them to <code>NEW_KEYSYM</code>.</p></li>
+<li><p><code>keysym any = KEYSYMS...</code></p>
+<p>Finds an otherwise unused keycode, and has it map to the specified keysyms.</p></li>
+</ul></li>
+<li><p><code>keyboard: map keycode -&gt; modifier bitmask</code></p>
+<ul>
+<li><code>clear MODIFIER</code></li>
+<li><code>add MODIFIERNAME = KEYSYMS...</code></li>
+<li><code>remove MODIFIERNAME = KEYSYMS...</code></li>
+</ul>
+<p>Wait, the modmap subsystem maps <em>keycodes</em> to modifiers, but the commands take <em>keysyms</em>? Yup! When executing one of these commands, it first looks up those keysyms in the keyboard map to translate them in to a set of keycodes, then associates those keycodes with that modifier. But how does it look up keysym-&gt;keycode; the protocol only supports querying keycode-&gt;keysym? It <a href="https://cgit.freedesktop.org/xorg/app/xmodmap/tree/handle.c?h=xmodmap-1.0.9#n59">loops</a> over <em>every</em> keycode finding all the matches.</p></li>
+<li><p><code>pointer: map physical button -&gt; logical button</code></p>
+<ul>
+<li><p><code>pointer = default</code></p>
+<p>This is equivalent to <code>pointer = 1 2 3 4 5 6...</code> where the list is as long as the number of buttons that there are.</p></li>
+<li><p><code>pointer = NUMBERS...</code></p>
+<p><code>pointer = A B C D...</code> sets the physical button 1 to logical button A, physical button 2 to logical button B, and so on. Setting a physical button to logical button 0 disables that button.</p></li>
+</ul></li>
+</ol>
+<h2 id="appendix">Appendix:</h2>
+<p>I use this snippet in my Emacs configuration to make editing xmodmap files nicer:</p>
+<pre><code>;; http://www.emacswiki.org/emacs/XModMapMode
+(when (not (fboundp &#39;xmodmap-mode))
+ (define-generic-mode &#39;xmodmap-mode
+ &#39;(?!)
+ &#39;(&quot;add&quot; &quot;clear&quot; &quot;keycode&quot; &quot;keysym&quot; &quot;pointer&quot; &quot;remove&quot;)
+ nil
+ &#39;(&quot;[xX]modmap\\(rc\\)?\\&#39;&quot;)
+ nil
+ &quot;Simple mode for xmodmap files.&quot;))</code></pre>
+
+</article>
+<footer>
+<p>The content of this page is Copyright © 2018 <a href="mailto:lukeshu@sbcglobal.net">Luke Shumaker</a>.</p>
+<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p>
+</footer>
+</body>
+</html>
diff --git a/public/kbd-xmodmap.md b/public/kbd-xmodmap.md
new file mode 100644
index 0000000..80012d8
--- /dev/null
+++ b/public/kbd-xmodmap.md
@@ -0,0 +1,244 @@
+GNU/Linux Keyboard Maps: xmodmap
+================================
+---
+date: "2018-02-09"
+---
+
+The modmap subsystem is part of the core [X11 protocol][xproto].
+However, it has been replaced by the [X Keyboard (XKB)
+Extension][kbproto] to the protocol, which defines a facade that
+emulates the legacy modmap subsystem so that old programs still
+work---including those that manipulate the modmap directly!
+
+[xproto]: https://www.x.org/releases/current/doc/xproto/x11protocol.html
+[kbproto]: https://www.x.org/releases/current/doc/kbproto/xkbproto.html
+
+For people who like to Keep It Stupid Simple, the XKB extension looks
+horribly complicated and gross---even ignoring protocol details, the
+configuration syntax is a monstrosity! There's no way to say
+something like "I'd like to remap Caps-Lock to be Control", you have
+to copy and edit the entire keyboard definition, which includes
+mucking with vector graphics of the physical keyboard layout! So it's
+very tempting to pretend that XKB doesn't exist, and it's still using
+modmap.
+
+However, this is a leaky abstraction; for instance: when running the
+`xmodmap` command to manipulate the modmap, if you have multiple
+keyboards plugged in, the result can depend on which keyboard you used
+to press "enter" after typing the command!
+
+Despite only existing as a compatibility shim today, I think it is
+important to understand the modmap subsystem to understand modern XKB.
+
+Conceptual overview
+-------------------
+
+There are 3 fundamental tasks that the modmap subsystem performs:
+
+ 1. `keyboard: map keycode -> keysym` (client-side)
+ 2. `keyboard: map keycode -> modifier bitmask` (server-side)
+ 3. `pointer: map physical button -> logical button` (server-side)
+
+You're thinking: "Great, so the X server does these things for us!"
+Nope! Not entirely, anyway. It does the keycode->modifier lookup,
+and the mouse-button lookup, but the keycode->keysym lookup must be
+done client-side by querying the mapping stored on the server.
+Generally, this is done automatically inside of libX11/libxcb, and the
+actual client application code doesn't need to worry about it.
+
+So, what's the difference between a keycode and a keysym, and how's
+the modifier bitmask work?
+
+ - keycode: A numeric ID for a hardware button; this is as close the
+ the hardware as X11 modmaps let us get. These are conceptually
+ identical to Linux kernel keycodes, but the numbers don't match
+ up. Xorg keycodes are typically `linux_keycode+8`.
+
+ - keysym: A 29-bit integer code that is meaningful to applications.
+ A mapping of these to symbolic names is defined in
+ `<X11/keysymdef.h>` and augmented by `/usr/share/X11/XKeysymDB`.
+ See: `XStringToKeysym()` and `XKeysymToString()`. We will
+ generally use the symbolic name in the modmap file. The symbolic
+ names are case-sensitive.
+
+ - Modifier state: An 8-bit bitmask of modifier keys (names are
+ case-insensitive):
+
+ 1 << 0 : shift
+ 1 << 1 : lock
+ 1 << 2 : control
+ 1 << 3 : mod1
+ 1 << 4 : mod2
+ 1 << 5 : mod3
+ 1 << 6 : mod4
+ 1 << 7 : mod5
+
+With that knowledge, and the libX11/libxcb API docs, you can probably
+figure out how to interact with the modmap subsystem from C, but who
+does that? Everyone just uses the `xmodmap(1)` command.
+
+The X11 protocol
+----------------
+
+As I said, the modifier and button lookup is handled server-side; each
+of the [input events][] ({Key,Button}{Press,Release}, and
+MotionNotify) and [pointer window events][] ({Enter,Leave}Notify)
+include a bitmask of active keyboard modifiers and pointer buttons.
+Each are given an 8-bit bitmask---hence 8 key modifiers. For some
+reason, only up to Button5 is included in the bitmask; the upper 3
+bits are always zero; but the Button{Press,Release} events will
+happily deliver events for up to Button255!
+
+[input events]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:input
+[pointer window events]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:pointer_window
+
+The X11 protocol has 6 request types for dealing with these 3
+mappings; an accessor and a mutator pair for each. Since the 2 of the
+mappings are done server-side, of these, most clients will only use
+GetKeyboardMapping. Anyway, let's look at those 6 requests, grouped
+by the mappings that they work with (pardon the Java-like pseudo-code
+syntax for indicating logical argument and return types):
+
+ 1. `keyboard: map keycode -> keysym`
+
+ - [GetKeyboardMapping][] :: `List<keycode> -> Map<keycode,List<keysym>>`
+ - [ChangeKeyboardMapping][] :: `Map<keycode,List<keysym>> -> ()`
+
+ `GetKeyboardMapping` returns the keycode->keysym mappings for the
+ requested keycodes; this way clients can choose to look up only
+ the keycodes that they need to handle (the ones that got sent to
+ them). Each keycode gets a list of keysyms; which keysym they
+ should use from that list depends on which modifiers are pressed.
+ `ChangeKeyboardMapping` changes the mapping for the given
+ keycodes; not all keycodes must be given, any keycodes that aren't
+ included in the request aren't changed.
+
+ 2. `keyboard: map keycode -> modifier bitmask`
+
+ - [GetModifierMapping][] :: `() -> Map<modifier,List<keycode>>`
+ - [SetModifierMapping][] :: `Map<modifier,List<keycode>> -> ()`
+
+ The modifiers mapping is a lot smaller than the keysym mapping;
+ you must operate on the entire mapping at once. For each modifier
+ bit, there's a list of keycodes that will cause that modifier bit
+ to be flipped in the events that are delivered while it is
+ pressed.
+
+ 3. `pointer: map physical button -> logical button`
+
+ - [GetPointerMapping][] `() -> List<logicalButton>` (indexed by `physicalButton-1`)
+ - [SetPointerMapping][] `List<logicalButton> -> ()` (indexed by `physicalButton-1`)
+
+ Like the modifier mapping, the button mapping is expected to be
+ small, most mice only have 5-7 buttons (left, middle, right,
+ scroll up, scroll down, scroll left, scroll right---that's right,
+ X11 handles scroll events as button presses), though some fancy
+ gaming mice have more than that, but not much more.
+
+[ChangeKeyboardMapping]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangeKeyboardMapping
+[SetModifierMapping]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:SetModifierMapping
+[SetPointerMapping]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:SetPointerMapping
+
+[GetKeyboardMapping]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetKeyboardMapping
+[GetModifierMapping]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetModifierMapping
+[GetPointerMapping]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetPointerMapping
+
+I mentioned earlier that the keycode->keysym mapping isn't actually
+done by the X server, and is done in the client; whenever a client
+receives a key event or pointer button event, it must do a
+`Get*Mapping` request to see what that translates to. Of course,
+doing a that for every keystroke would be crazy; but at the same time,
+the each client is expected to know about changes to the mappings that
+happen at run-time. So, each of the "set"/"change" commands generate
+a [MappingNotify][] event that is sent to all clients, so they know
+when they must dump their cache of mappings.
+
+[MappingNotify]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#events:MappingNotify
+
+For completeness, if you are looking at this as background for
+understanding XKB, I should also mention:
+
+ - [GetKeyboardControl][]
+ - [ChangeKeyboardControl][]
+ - [GetPointerControl][]
+ - [ChangePointerControl][]
+
+[GetKeyboardControl]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetKeyboardControl
+[ChangeKeyboardControl]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangeKeyboardControl
+[GetPointerControl]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:GetPointerControl
+[ChangePointerControl]: https://www.x.org/releases/current/doc/xproto/x11protocol.html#requests:ChangePointerControl
+
+The `xmodmap` command
+---------------------
+
+The `xmodmap` command reads a configuration file and modifies the maps
+in the X server to match. The `xmodmap` config file has its own
+little quirky syntax. For one, the comment character is `!` (and
+comments may only start at the *beginning* of the line, but that's
+fairly common).
+
+There are 8 commands that `xmodmap` recognizes. Let's look at those,
+grouped by the 3 tasks that the modmap subsystem performs:
+
+ 1. `keyboard: map keycode -> keysym`
+
+ - `keycode KEYCODE = PLAIN [SHIFT [MODE_SWITCH [MODE_SWITCH+SHIFT ]]]`
+
+ Actually takes a list of up to 8 keysyms, but only the first
+ 4 have standard uses.
+
+ - `keysym OLD_KEYSYM = NEW_KEYSYMS...`
+
+ Takes the keycodes mapped to `OLD_KEYSYM` and maps them to
+ `NEW_KEYSYM`.
+
+ - `keysym any = KEYSYMS...`
+
+ Finds an otherwise unused keycode, and has it map to the
+ specified keysyms.
+
+ 2. `keyboard: map keycode -> modifier bitmask`
+
+ - `clear MODIFIER`
+ - `add MODIFIERNAME = KEYSYMS...`
+ - `remove MODIFIERNAME = KEYSYMS...`
+
+ Wait, the modmap subsystem maps *keycodes* to modifiers, but the
+ commands take *keysyms*? Yup! When executing one of these
+ commands, it first looks up those keysyms in the keyboard map to
+ translate them in to a set of keycodes, then associates those
+ keycodes with that modifier. But how does it look up
+ keysym->keycode; the protocol only supports querying
+ keycode->keysym? It
+ [loops](https://cgit.freedesktop.org/xorg/app/xmodmap/tree/handle.c?h=xmodmap-1.0.9#n59)
+ over *every* keycode finding all the matches.
+
+ 3. `pointer: map physical button -> logical button`
+
+ - `pointer = default`
+
+ This is equivalent to `pointer = 1 2 3 4 5 6...` where the
+ list is as long as the number of buttons that there are.
+
+ - `pointer = NUMBERS...`
+
+ `pointer = A B C D...` sets the physical button 1 to logical
+ button A, physical button 2 to logical button B, and so on.
+ Setting a physical button to logical button 0 disables that
+ button.
+
+Appendix:
+---------
+
+I use this snippet in my Emacs configuration to make editing xmodmap
+files nicer:
+
+ ;; http://www.emacswiki.org/emacs/XModMapMode
+ (when (not (fboundp 'xmodmap-mode))
+ (define-generic-mode 'xmodmap-mode
+ '(?!)
+ '("add" "clear" "keycode" "keysym" "pointer" "remove")
+ nil
+ '("[xX]modmap\\(rc\\)?\\'")
+ nil
+ "Simple mode for xmodmap files."))
diff --git a/public/posix-pricing.html b/public/posix-pricing.html
new file mode 100644
index 0000000..47a82b4
--- /dev/null
+++ b/public/posix-pricing.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>POSIX pricing and availability; or: Do you really need the PDF? — Luke Shumaker</title>
+ <link rel="stylesheet" href="assets/style.css">
+ <link rel="alternate" type="application/atom+xml" href="./index.atom" name="web log entries"/>
+</head>
+<body>
+<header><a href="/">Luke Shumaker</a> » <a href=/blog>blog</a> » posix-pricing</header>
+<article>
+<h1 id="posix-pricing-and-availability-or-do-you-really-need-the-pdf">POSIX pricing and availability; or: Do you really need the PDF?</h1>
+<p>The Open Group and IEEE are weird about POSIX pricing. They’re protective of the PDF, making you pay <a href="http://standards.ieee.org/findstds/standard/1003.1-2008.html">hundreds of dollars</a> for the PDF; but will happily post an HTML version for free both <a href="http://pubs.opengroup.org/onlinepubs/9699919799/">online</a>, and (with free account creation) download as a <a href="https://www2.opengroup.org/ogsys/catalog/t101">a .zip</a>.</p>
+<p>They also offer a special license to the “Linux man-pages” project, allowing them to <a href="https://www.kernel.org/pub/linux/docs/man-pages/man-pages-posix/">distribute</a> the man page portions of POSIX (most of it is written as a series of man pages) for free; so on a GNU/Linux box, you probably have most of POSIX already downloaded in manual sections 0p, 1p, and 3p.</p>
+<p>Anyway, the only thing you aren’t getting with the free HTML version is a line number next to every line of text. It’s generated from the same troff sources. So, in an article or in a discussion, I’m not cheating you out of specification details by citing the webpage.</p>
+<p>If you’re concerned that you’re looking at the correct version of the webpage or man pages, the current version (as of February 2018) of POSIX is “POSIX-2008, 2016 edition.”</p>
+
+</article>
+<footer>
+<p>The content of this page is Copyright © 2018 <a href="mailto:lukeshu@sbcglobal.net">Luke Shumaker</a>.</p>
+<p>This page is licensed under the <a href="https://creativecommons.org/licenses/by-sa/3.0/">CC BY-SA-3.0</a> license.</p>
+</footer>
+</body>
+</html>
diff --git a/public/posix-pricing.md b/public/posix-pricing.md
new file mode 100644
index 0000000..54637a2
--- /dev/null
+++ b/public/posix-pricing.md
@@ -0,0 +1,31 @@
+POSIX pricing and availability; or: Do you really need the PDF?
+===============================================================
+---
+date: "2018-02-09"
+---
+
+The Open Group and IEEE are weird about POSIX pricing. They're
+protective of the PDF, making you pay [hundreds of
+dollars][POSIX-IEEE] for the PDF; but will happily post an HTML
+version for free both [online][POSIX-WWW], and (with free account
+creation) download as a [a .zip][POSIX-TOG].
+
+They also offer a special license to the "Linux man-pages" project,
+allowing them to [distribute][POSIX-MAN] the man page portions of
+POSIX (most of it is written as a series of man pages) for free; so on
+a GNU/Linux box, you probably have most of POSIX already downloaded in
+manual sections 0p, 1p, and 3p.
+
+Anyway, the only thing you aren't getting with the free HTML version
+is a line number next to every line of text. It's generated from the
+same troff sources. So, in an article or in a discussion, I'm not
+cheating you out of specification details by citing the webpage.
+
+If you're concerned that you're looking at the correct version of the
+webpage or man pages, the current version (as of February 2018) of
+POSIX is "POSIX-2008, 2016 edition."
+
+[POSIX-IEEE]: http://standards.ieee.org/findstds/standard/1003.1-2008.html
+[POSIX-TOG]: https://www2.opengroup.org/ogsys/catalog/t101
+[POSIX-WWW]: http://pubs.opengroup.org/onlinepubs/9699919799/
+[POSIX-MAN]: https://www.kernel.org/pub/linux/docs/man-pages/man-pages-posix/