<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Posts on Illusion and Trifle</title><link>https://victorhge.github.io/posts/</link><description>Recent content in Posts on Illusion and Trifle</description><generator>Hugo -- 0.156.0</generator><language>en</language><copyright>Source code here, licensed under GPLv3 ·</copyright><lastBuildDate>Thu, 12 Mar 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://victorhge.github.io/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>X Macros</title><link>https://victorhge.github.io/posts/xmacro/</link><pubDate>Thu, 12 Mar 2026 00:00:00 +0800</pubDate><guid>https://victorhge.github.io/posts/xmacro/</guid><description>A simple technique for solving consistency problems in C/C++ projects</description><content:encoded><![CDATA[<blockquote>
<p>No problem can be solved at the same level of thinking that created it.<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>
&mdash; &ldquo;Albert Einstein&rdquo;</p>
</blockquote>
<h2 id="consistency-challenge">Consistency Challenge</h2>
<p>The first time I ran into X Macros was while debugging an out-of-bounds access issue.</p>
<p>Here is a simplified example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">// a.h
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">enum</span> {
</span></span><span style="display:flex;"><span>    SYS_OK,
</span></span><span style="display:flex;"><span>    SYS_ERR_TIMEOUT,
</span></span><span style="display:flex;"><span>    SYS_ERR_BUSY,
</span></span><span style="display:flex;"><span>    SYS_ERR_INVALID_ARG,
</span></span><span style="display:flex;"><span>    SYS_ERR_NOT_FOUND
</span></span><span style="display:flex;"><span>} SysState;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">// a.c
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>state_desc[] <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    [SYS_OK] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;System OK&#34;</span>,
</span></span><span style="display:flex;"><span>    [SYS_ERR_TIMEOUT] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Timeout&#34;</span>,
</span></span><span style="display:flex;"><span>    [SYS_ERR_BUSY] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;System Busy&#34;</span>,
</span></span><span style="display:flex;"><span>    [SYS_ERR_INVALID_ARG] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Invalid Argument&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">// SYS_ERR_NOT_FOUND is missing here
</span></span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">int</span> <span style="color:#a6e22e">main</span>()
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">printf</span>(<span style="color:#e6db74">&#34;State = %s</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, state_desc[SYS_ERR_NOT_FOUND]);
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The issue is easy to spot: <code>SYS_ERR_NOT_FOUND</code> was added to the enum,
but the string table was not updated.</p>
<p>When the program evaluates <code>state_desc[SYS_ERR_NOT_FOUND]</code>, it reads past the
end of the array and eventually crashes.</p>
<p>Of course, we could fix this by adding the missing entry to the string table.
But that only fixes this specific bug — it does not prevent the same type of
problem from happening again.</p>
<p>The underlying issue is that we are maintaining <strong>two pieces of information that
must always stay consistent</strong>:</p>
<ul>
<li>the enum definition</li>
<li>the string table</li>
</ul>
<p>As long as these are maintained separately and rely on manual synchronization,
mistakes like this are inevitable.</p>
<p>What we really need is a way to eliminate this class of problems entirely.</p>
<h2 id="x-macros">X Macros</h2>
<p>While looking for a solution, I came across an article by Randy Meyers
published in <em>Dr. Dobb&rsquo;s Journal</em> titled <strong>The New C: X Macros</strong> <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.
The article introduces a technique that uses the C preprocessor to generate
code from a single data definition.</p>
<p>This technique is commonly known as <strong>X Macros</strong>.</p>
<p>The idea is simple: maintain a single data list, and generate the necessary
code structures by redefining a macro.</p>
<p>Let&rsquo;s modify the previous example to see how this works.</p>
<p>First, define a <strong>Single source of truth</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">#define SYS_STATE_LIST                         \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_OK,              &#34;System OK&#34;)        \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_ERR_TIMEOUT,     &#34;Timeout&#34;)          \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_ERR_BUSY,        &#34;System Busy&#34;)      \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_ERR_INVALID_ARG, &#34;Invalid Argument&#34;) \
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">    X(SYS_ERR_NOT_FOUND,   &#34;Not Found&#34;)
</span></span></span></code></pre></div><p>This list becomes the master definition of our data.
Each entry is wrapped inside a placeholder macro <code>X()</code>.</p>
<p>The name <code>X</code> is simply a convention. It has no special meaning and can be
replaced with any name.</p>
<p>Next, we define the macro <code>X</code> to generate the enum:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">#define X(name, desc) name,
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">typedef</span> <span style="color:#66d9ef">enum</span> {
</span></span><span style="display:flex;"><span>    SYS_STATE_LIST
</span></span><span style="display:flex;"><span>} SysState;
</span></span><span style="display:flex;"><span><span style="color:#75715e">#undef X
</span></span></span></code></pre></div><p>Then we redefine <code>X</code> so that the same list generates the string table:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-C" data-lang="C"><span style="display:flex;"><span><span style="color:#75715e">#define X(name, desc) [name] = desc,
</span></span></span><span style="display:flex;"><span><span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>state_desc[] <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    SYS_STATE_LIST
</span></span><span style="display:flex;"><span>};
</span></span><span style="display:flex;"><span><span style="color:#75715e">#undef X
</span></span></span></code></pre></div><p>If you come from dynamic languages such as Python or Java, this might look
somewhat like a lightweight form of reflection.</p>
<p>X Macros gather scattered information into a single data list. By redefining
and undefining <code>X</code> (<code>#undef</code>), the same data can be injected into multiple
code templates. Adding, removing, or reordering entries will not introduce
inconsistencies.</p>
<p>This technique works well in many situations where related data must stay
synchronized, for example:</p>
<ul>
<li>Managing error codes, states, or event types together with their descriptions</li>
<li>Generating command tables or protocol definitions</li>
<li>Serialization and deserialization</li>
<li>Configuration data initialization and access code generating</li>
</ul>
<h2 id="advanced-notes">Advanced Notes</h2>
<p>X Macros are powerful, but they do come with trade-offs. Macro-heavy code can
reduce readability and make debugging more difficult.</p>
<p>Some practical tips:</p>
<ul>
<li>
<p><strong>Improve readability</strong>: Andrew Lucas suggests passing the macro <code>X</code> as a
parameter to the data list to make the structure clearer <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</p>
</li>
<li>
<p><strong>Large data sets</strong>: If the list becomes very long, you may hit compiler
line-length limits. Randy Meyers recommends placing the list in a separate<code>.def</code> or <code>.h</code> file and using <code>#include</code> to reuse it.</p>
</li>
<li>
<p><strong>Inspect preprocessed output</strong>: You can use <code>gcc -E</code> to view the expanded
source code. Many modern IDEs with language servers can also show this.</p>
</li>
<li>
<p><strong>Team communication</strong>: Not everyone is familiar with this technique. Good
comments and documentation help avoid confusion.</p>
</li>
<li>
<p><strong>Use it sparingly</strong>: Like most macro tricks, X Macros should be used
thoughtfully rather than everywhere.</p>
</li>
</ul>
<h2 id="summary">Summary</h2>
<p>X Macros are essentially a lightweight metaprogramming technique built on top
of the C/C++ preprocessor. In environments without reflection or code
generation tools, they provide a practical way to keep related definitions
synchronized.</p>
<p>By maintaining a <strong>Single Source of Truth</strong> and generating code through macro
expansion, X Macros eliminate the risk of inconsistent duplicated definitions.</p>
<p>The idea dates back to assembly programming in the 1960s. Even today, whenever
large amounts of structured data need to remain consistent, it remains a
surprisingly useful technique — and a valuable tool in the C/C++ programmer&rsquo;s
toolbox.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>AI translated.  I discovered this link when I tried to find the source of this quote:<a href="https://www.quora.com/Einstein-said-that-you-cannot-solve-a-problem-from-the-same-level-of-consciousness-that-created-it-What-did-he-mean-with-it-Can-you-use-a-concrete-example">https://www.quora.com/Einstein-said-that-you-cannot-solve-a-problem-from-the-same-level-of-consciousness-that-created-it-What-did-he-mean-with-it-Can-you-use-a-concrete-example</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>Randy Meyers. &ldquo;The New C: X macros&rdquo;, Dr.Dobb&rsquo;s 2001, accessible at:<a href="https://jacobfilipp.com/DrDobbs/articles/CUJ/2001/0105/meyers/meyers.htm">https://jacobfilipp.com/DrDobbs/articles/CUJ/2001/0105/meyers/meyers.htm</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>Andrew Lucas. <a href="https://www.embedded.com/reduce-c-language-coding-errors-with-x-macros-part-1/">&ldquo;Reduce C-language coding errors with X macros&rdquo;</a>, Embedded.com, 2013.&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Translationese</title><link>https://victorhge.github.io/posts/translationese/</link><pubDate>Wed, 11 Mar 2026 00:00:00 +0800</pubDate><guid>https://victorhge.github.io/posts/translationese/</guid><description>&lt;p&gt;I recently set up a small blog on GitHub Pages. It was almost effortless—pick a
theme, tweak a few parameters, and the site is live. Since I was already
tinkering, I decided to make it bilingual. Every post now starts in Chinese,
then gets translated into English with the help of an AI model.&lt;/p&gt;
&lt;p&gt;The quality of machine translation today is, frankly, impressive. Most of the
time, a light round of editing is enough before publishing.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I recently set up a small blog on GitHub Pages. It was almost effortless—pick a
theme, tweak a few parameters, and the site is live. Since I was already
tinkering, I decided to make it bilingual. Every post now starts in Chinese,
then gets translated into English with the help of an AI model.</p>
<p>The quality of machine translation today is, frankly, impressive. Most of the
time, a light round of editing is enough before publishing.</p>
<p>And yet, something never quite sits right.</p>
<p>The sentences are correct. The meaning is intact. But the text feels…
distant. As if there’s a thin layer between the words and the reader—hard to
name, harder to ignore.</p>
<p>That unease sharpened one day when I worked on a longer piece. The translated
version felt particularly off. So I did a side-by-side comparison of several
posts, Chinese against English. The result was unsettling—like catching your
reflection in a mirror and realizing, for a split second, that it isn’t you.</p>
<p>It brought to mind an old line of poetry about crossing a threshold and becoming
a stranger ever after:</p>
<p><em>Once you enter the noble&rsquo;s gate, it&rsquo;s as deep as th sea;</em>
<em>from then on, the former love is but a stranger.</em></p>
<p>The problem, I realized, wasn’t the translation. It was the Chinese.</p>
<p>For years, I’ve worked in environments where English is the default. Emails,
documentation, code, comments—everything happens in English. Chinese never
disappeared, but it retreated into casual conversation: chats, messages,
everyday exchanges.</p>
<p>Looking back at my recent blog posts, I noticed something uncomfortable. The
Chinese and the English versions aligned almost word for word. On the surface,
they were written in Chinese. But structurally, they followed English logic so
closely that they could be mapped directly onto each other.</p>
<p>Somewhere along the way, I had developed a habit. Whenever I “write,” my
thoughts take a detour through English before landing in Chinese. What I had
taken for Chinese writing was, in fact, English composition wearing Chinese
characters.</p>
<p>No wonder it reads like a translation.</p>
<p>I suspect I’m not alone in this.</p>
<p>For many bilingual speakers, written expression gradually leans toward
English. Chinese recedes into speech, rarely called upon for sustained, complex
thought. And like any skill left unused, it begins to dull.</p>
<p>You don’t notice it at first. Only when you try to write something serious do
you realize the words no longer come as easily.</p>
<p>Use it, or lose it.</p>
<p>In an odd way, this blog has been a wake-up call. It forced me to see the
problem clearly. And the solution, though simple, is not easy: start writing in
Chinese again—deliberately, persistently, and with attention.</p>
<p>As I write this, I find myself examining each sentence as it forms:</p>
<p>Could this be translated directly into English?</p>
<p>If the answer is yes, something is probably off.</p>
]]></content:encoded></item><item><title>Splitting Ctrl+Space</title><link>https://victorhge.github.io/posts/ctrl_space/</link><pubDate>Mon, 02 Mar 2026 00:00:00 +0800</pubDate><guid>https://victorhge.github.io/posts/ctrl_space/</guid><description>&lt;p&gt;Emacs comes with numerous default keybindings, which inevitably conflict with
system-level shortcuts. For Emacs beginners, resolving these conflicts can be a
significant challenge.&lt;/p&gt;
&lt;p&gt;One of the most common conflicts is with the command &lt;code&gt;set-mark-command&lt;/code&gt;, which
default binding is &lt;code&gt;C-SPC~(Ctrl+Space)&lt;/code&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. On Windows, &lt;code&gt;Ctrl+Space&lt;/code&gt; is
often used to toggle between English and Chinese input methods, which can make&lt;code&gt;Ctrl+Space&lt;/code&gt; unusable for marking in Emacs.&lt;/p&gt;
&lt;p&gt;To resolve this issue, you can either use the alternative binding for&lt;code&gt;set-mark-command&lt;/code&gt;, &lt;code&gt;C-@&lt;/code&gt;, or disable the &lt;code&gt;Ctrl+Space&lt;/code&gt; functionality in
Windows. Additionally, since the spacebar can
be operated easily with either thumb, there is a &amp;ldquo;third option&amp;rdquo;: you can
configure the &lt;code&gt;Ctrl+Space&lt;/code&gt; so that one side &lt;code&gt;Ctrl+Space&lt;/code&gt; is reserved for
Windows, while the other side &lt;code&gt;Ctrl+Space&lt;/code&gt; is available for Emacs or other
applications. This is the solution I adopted because it allows me to
maintain my habit of using both thumbs for operation.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Emacs comes with numerous default keybindings, which inevitably conflict with
system-level shortcuts.  For Emacs beginners, resolving these conflicts can be a
significant challenge.</p>
<p>One of the most common conflicts is with the command <code>set-mark-command</code>, which
default binding is <code>C-SPC~(Ctrl+Space)</code><sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>.  On Windows, <code>Ctrl+Space</code> is
often used to toggle between English and Chinese input methods, which can make<code>Ctrl+Space</code> unusable for marking in Emacs.</p>
<p>To resolve this issue, you can either use the alternative binding for<code>set-mark-command</code>, <code>C-@</code>, or disable the <code>Ctrl+Space</code> functionality in
Windows.  Additionally, since the spacebar can
be operated easily with either thumb, there is a &ldquo;third option&rdquo;: you can
configure the <code>Ctrl+Space</code> so that one side <code>Ctrl+Space</code> is reserved for
Windows, while the other side <code>Ctrl+Space</code> is available for Emacs or other
applications.  This is the solution I adopted because it allows me to
maintain my habit of using both thumbs for operation.</p>
<p>In the latest version of Windows 11, you can achieve this as follows:</p>
<ol>
<li>
<p>Go to <code>Settings &gt; Time &amp; Language &gt; Language &amp; region &gt; Options &gt; Microsoft Pinyin &gt; Keys</code>, and uncheck the <code>Ctrl + Space</code> box while leaving <code>Shift</code>
checked.<img loading="lazy" src="/ox-hugo/disable_Ctrl+Space.png"></p>
</li>
<li>
<p>Open PowerToys (install it if you don&rsquo;t already have it). In the <code>Keyboard Manager</code> section, add a key remapping: map <code>Ctrl(Left) + Space</code> to <code>Shift</code> or<code>Win(Left) + Space</code>.<img loading="lazy" src="/ox-hugo/remap_shortcuts.png"></p>
</li>
</ol>
<p>For older versions of Windows, where there&rsquo;s a UI bug preventing such
changes <sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>, you can solve this by manually editing the registry:</p>
<ol>
<li>Navigate to <code>HKEY_CURRENT_USER\Control Panel\Input Method\Hot Keys\00000010</code>. Modify the value of <code>Key Modifiers</code> to <code>02 80 00 00</code>, or <code>02 40 00 00</code> <sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>.</li>
<li>If you want to apply this change for all new users, make the same
modification under <code>HKEY_USERS\.DEFAULT\Control Panel\Input Method\Hot Keys\00000010</code>.</li>
</ol>
<p>After making these changes, restart your computer to take effect.</p>
<p>It seems that only <code>Ctrl+Space</code> can be “split,” as other key combinations are
naturally easier to reach with one hand. For example, <code>Ctrl+a</code> inherently implies<code>Right Ctrl+a</code>.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Emacs uses unique convention for keybinngs, where <code>C-SPC</code> is shorthand for<code>Ctrl+Space</code>.  This article adopts the common convention for now.&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p><a href="https://superuser.com/questions/327479/ctrl-space-always-toggles-chinese-ime-windows-7">https://superuser.com/questions/327479/ctrl-space-always-toggles-chinese-ime-windows-7</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3">
<p>02 indicates Ctrl, 80 indicates the left side, and 40 indicates the right side.<a href="https://learn.microsoft.com/en-us/windows/win32/tsf/tf-mod--constants">https://learn.microsoft.com/en-us/windows/win32/tsf/tf-mod--constants</a>&#160;<a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item><item><title>Swapping Ctrl and Alt Keys</title><link>https://victorhge.github.io/posts/swap_ctrl_alt/</link><pubDate>Wed, 25 Feb 2026 20:59:00 +0800</pubDate><guid>https://victorhge.github.io/posts/swap_ctrl_alt/</guid><description>&lt;figure&gt;
&lt;img loading="lazy" src="https://victorhge.github.io/ox-hugo/lisp-machine-keyboard-2.jpg"/&gt;
&lt;/figure&gt;
&lt;p&gt;This is an essential configuration for all the computers I use, all because of
Emacs.&lt;/p&gt;
&lt;p&gt;Emacs was originally developed as a set of macros for the TECO editor (&lt;a href="https://blog.djmnet.org/2008/08/05/origin-of-emacs/"&gt;Editing
MACroS&lt;/a&gt;). At that time, the keyboard layout used by the developers placed the
Ctrl key next to the spacebar&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;, making it convenient for operation with
the thumbs. For some reason, standard keyboards that became widespread with
personal computers moved the Ctrl key to the outermost position, which forces
usage with the pinky finger. This design easily fatigues the pinky.&lt;/p&gt;</description><content:encoded><![CDATA[<figure>
    <img loading="lazy" src="/ox-hugo/lisp-machine-keyboard-2.jpg"/> 
</figure>

<p>This is an essential configuration for all the computers I use, all because of
Emacs.</p>
<p>Emacs was originally developed as a set of macros for the TECO editor (<a href="https://blog.djmnet.org/2008/08/05/origin-of-emacs/">Editing
MACroS</a>). At that time, the keyboard layout used by the developers placed the
Ctrl key next to the spacebar<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>, making it convenient for operation with
the thumbs. For some reason, standard keyboards that became widespread with
personal computers moved the Ctrl key to the outermost position, which forces
usage with the pinky finger. This design easily fatigues the pinky.</p>
<p>Therefore, I choose to swap the Ctrl and Alt keys, returning the Ctrl key
to a thumb-operable position, alleviating pinky strain and significantly
improving efficiency.</p>
<p>Here’s how I do it:</p>
<ul>
<li>Windows: Using <a href="https://github.com/randyrants/sharpkeys">SharpKeys</a> for key remapping.</li>
<li>Linux (GNOME desktop): GNOME Tweak Tool makes this easy to configure<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>.</li>
</ul>
<p>This is a &ldquo;once-you-use-it-you-can&rsquo;t-go-back&rdquo; configuration.  It also has a&lsquo;hidden feature&rsquo; - driving others crazy when they try to use my keyboard.</p>
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>Knight Keyboard <a href="http://xahlee.info/kbd/knight_keyboard.html">http://xahlee.info/kbd/knight_keyboard.html</a>&#160;<a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2">
<p>GNOME Treak Tool <a href="https://askubuntu.com/questions/885045/how-to-swap-ctrl-and-alt-keys-in-ubuntu-16-04/885047">https://askubuntu.com/questions/885045/how-to-swap-ctrl-and-alt-keys-in-ubuntu-16-04/885047</a>&#160;<a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</div>
]]></content:encoded></item></channel></rss>