qmk_firmware/feature_userspace.html

117 lines
130 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en-US" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Userspace: Sharing Code Between Keymaps | QMK Firmware</title>
<meta name="description" content="Documentation for QMK Firmware">
<meta name="generator" content="VitePress v1.1.3">
<link rel="preload stylesheet" href="/assets/style.DWuET1QV.css" as="style">
<script type="module" src="/assets/app.BDA1YtVA.js"></script>
<link rel="preload" href="/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
<link rel="modulepreload" href="/assets/chunks/framework.DyMmIvSC.js">
<link rel="modulepreload" href="/assets/chunks/theme.BjSqPv6D.js">
<link rel="modulepreload" href="/assets/feature_userspace.md.BsmY9yWw.lean.js">
<script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
<script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
</head>
<body>
<div id="app"><div class="Layout" data-v-5d98c3a5><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0f60ec36></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0f60ec36> Skip to content </a><!--]--><!----><header class="VPNav" data-v-5d98c3a5 data-v-ae24b3ad><div class="VPNavBar has-sidebar top" data-v-ae24b3ad data-v-ccf7ddec><div class="wrapper" data-v-ccf7ddec><div class="container" data-v-ccf7ddec><div class="title" data-v-ccf7ddec><div class="VPNavBarTitle has-sidebar" data-v-ccf7ddec data-v-ab179fa1><a class="title" href="/" data-v-ab179fa1><!--[--><!--]--><!--[--><!--[--><!--[--><img class="VPImage dark logo" src="/qmk-logo-dark.svg" alt data-v-8426fc1a><!--]--><!--[--><img class="VPImage light logo" src="/qmk-logo-light.svg" alt data-v-8426fc1a><!--]--><!--]--><!--]--><span data-v-ab179fa1>QMK Firmware</span><!--[--><!--]--></a></div></div><div class="content" data-v-ccf7ddec><div class="content-body" data-v-ccf7ddec><!--[--><!--]--><div class="VPNavBarSearch search" data-v-ccf7ddec><!--[--><!----><div id="local-search"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><span class="vp-icon DocSearch-Search-Icon"></span><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-ccf7ddec data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="./" tabindex="0" data-v-7f418b0f data-v-9c663999><!--[--><span data-v-9c663999>Home</span><!--]--></a><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-ccf7ddec data-v-e6aabb21><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="Switch to dark theme" aria-checked="false" data-v-e6aabb21 data-v-d1f28634 data-v-1d5665e3><span class="check" data-v-1d5665e3><span class="icon" data-v-1d5665e3><!--[--><span class="vpi-sun sun" data-v-d1f28634></span><span class="vpi-moon moon" data-v-d1f28634></span><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-ccf7ddec data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://reddit.com/r/olkb" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-eee4e7cb><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="50px" height="50px"><path d="M 29 3 C 28.0625 3 27.164063 3.382813 26.5 4 C 25.835938 4.617188 25.363281 5.433594 25 6.40625 C 24.355469 8.140625 24.085938 10.394531 24.03125 13.03125 C 19.234375 13.179688 14.820313 14.421875 11.28125 16.46875 C 10.214844 15.46875 8.855469 14.96875 7.5 14.96875 C 6.089844 14.96875 4.675781 15.511719 3.59375 16.59375 C 1.425781 18.761719 1.425781 22.238281 3.59375 24.40625 L 3.84375 24.65625 C 3.3125 26.035156 3 27.488281 3 29 C 3 33.527344 5.566406 37.585938 9.5625 40.4375 C 13.558594 43.289063 19.007813 45 25 45 C 30.992188 45 36.441406 43.289063 40.4375 40.4375 C 44.433594 37.585938 47 33.527344 47 29 C 47 27.488281 46.6875 26.035156 46.15625 24.65625 L 46.40625 24.40625 C 48.574219 22.238281 48.574219 18.761719 46.40625 16.59375 C 45.324219 15.511719 43.910156 14.96875 42.5 14.96875 C 41.144531 14.96875 39.785156 15.46875 38.71875 16.46875 C 35.195313 14.433594 30.800781 13.191406 26.03125 13.03125 C 26.09375 10.546875 26.363281 8.46875 26.875 7.09375 C 27.164063 6.316406 27.527344 5.757813 27.875 5.4375 C 28.222656 5.117188 28.539063 5 29 5 C 29.460938 5 29.683594 5.125 30.03125 5.40625 C 30.378906 5.6875 30.785156 6.148438 31.3125 6.6875 C 32.253906 7.652344 33.695313 8.714844 36.09375 8.9375 C 36.539063 11.238281 38.574219 13 41 13 C 43.75 13 46 10.75 46 8 C 46 5.25 43.75 3 41 3 C 38.605469 3 36.574219 4.710938 36.09375 6.96875 C 34.3125 6.796875 33.527344 6.109375 32.75 5.3125 C 32.300781 4.851563 31.886719
</code></pre><p>For example,</p><pre><code>make planck:jack
</code></pre><p>Will include the <code>/users/jack/</code> folder in the path, along with <code>/users/jack/rules.mk</code>.</p><div class="warning custom-block"><p class="custom-block-title">WARNING</p><p>This <code>name</code> can be <a href="#override-default-userspace">overridden</a>, if needed.</p></div><h2 id="rules-mk" tabindex="-1"><code>Rules.mk</code> <a class="header-anchor" href="#rules-mk" aria-label="Permalink to &quot;`Rules.mk`&quot;"></a></h2><p>The <code>rules.mk</code> is one of the two files that gets processed automatically. This is how you add additional source files (such as <code>&lt;name&gt;.c</code>) will be added when compiling.</p><p>It&#39;s highly recommended that you use <code>&lt;name&gt;.c</code> as the default source file to be added. And to add it, you need to add it the SRC in <code>rules.mk</code> like this:</p><pre><code>SRC += &lt;name&gt;.c
</code></pre><p>Additional files may be added in the same way - it&#39;s recommended you have one named <code>&lt;name&gt;</code>.c/.h to start off with, though.</p><p>The <code>/users/&lt;name&gt;/rules.mk</code> file will be included in the build <em>after</em> the <code>rules.mk</code> from your keymap. This allows you to have features in your userspace <code>rules.mk</code> that depend on individual QMK features that may or may not be available on a specific keyboard.</p><p>For example, if you have RGB control features shared between all your keyboards that support RGB lighting, you can add support for that if the RGBLIGHT feature is enabled:</p><div class="language-make vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">make</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">ifeq</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">$(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">strip</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> $(</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">RGBLIGHT_ENABLE</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">))</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, yes)</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # Include my fancy rgb functions source here</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SRC += cool_rgb_stuff.c</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">endif</span></span></code></pre></div><p>Alternatively, you can <code>define RGB_ENABLE</code> in your keymap&#39;s <code>rules.mk</code> and then check for the variable in your userspace&#39;s <code>rules.mk</code> like this:</p><div class="language-make vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">make</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">ifdef</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> RGB_ENABLE</span></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> # Include my fancy rgb functions source here</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SRC += cool_rgb_stuff.c</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">endif</span></span></code></pre></div><h3 id="override-default-userspace" tabindex="-1">Override default userspace <a class="header-anchor" href="#override-default-userspace" aria-label="Permalink to &quot;Override default userspace&quot;"></a></h3><p>By default the userspace used will be the same as the keymap name. In some situations this isn&#39;t desirable. For instance, if you use the <a href="./feature_layouts">layout</a> feature you can&#39;t use the same name for different keymaps (e.g. ANSI and ISO). You can name your layouts <code>mylayout-ansi</code> and <code>mylayout-iso</code> and add the following line to your layout&#39;s <code>rules.mk</code>:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>USER_NAME := mylayout</span></span></code></pre></div><p>This is also useful if you have multiple different keyboards with different features physically present on the board (such as one with RGB Lights, and one with Audio, or different number of LEDs, or connected to a different PIN on the controller).</p><h2 id="configuration-options-config-h" tabindex="-1">Configuration Options (<code>config.h</code>) <a class="header-anchor" href="#configuration-options-config-h" aria-label="Permalink to &quot;Configuration Options (`config.h`)&quot;"></a></h2><p>Additionally, <code>config.h</code> here will be processed like the same file in your keymap folder. This is handled separately from the <code>&lt;name&gt;.h</code> file.</p><p>The reason for this, is that <code>&lt;name&gt;.h</code> won&#39;t be added in time to add settings (such as <code>#define TAPPING_TERM 100</code>), and including the <code>&lt;name.h&gt;</code> file in any <code>config.h</code> files will result in compile issues.</p><p>!&gt;You should use the <code>config.h</code> for <a href="./config_options">configuration options</a>, and the <code>&lt;name&gt;.h</code> file for user or keymap specific settings (such as the enum for layer or keycodes)</p><h2 id="readme-readme-md" tabindex="-1">Readme (<code>readme.md</code>) <a class="header-anchor" href="#readme-readme-md" aria-label="Permalink to &quot;Readme (`readme.md`)&quot;"></a></h2><p>Please include authorship (your name, GitHub username, email), and optionally <a href="https://www.gnu.org/licenses/license-list.html#GPLCompatibleLicenses" target="_blank" rel="noreferrer">a license that&#39;s GPL compatible</a>.</p><p>You can use this as a template:</p><div class="language- vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span>Copyright &lt;year&gt; &lt;name&gt; &lt;email&gt; @&lt;github_username&gt;</span></span>
<span class="line"><span></span></span>
<span class="line"><span>This program is free software: you can redistribute it and/or modify</span></span>
<span class="line"><span>it under the terms of the GNU General Public License as published by</span></span>
<span class="line"><span>the Free Software Foundation, either version 2 of the License, or</span></span>
<span class="line"><span>(at your option) any later version.</span></span>
<span class="line"><span></span></span>
<span class="line"><span>This program is distributed in the hope that it will be useful,</span></span>
<span class="line"><span>but WITHOUT ANY WARRANTY; without even the implied warranty of</span></span>
<span class="line"><span>MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span></span>
<span class="line"><span>GNU General Public License for more details.</span></span>
<span class="line"><span></span></span>
<span class="line"><span>You should have received a copy of the GNU General Public License</span></span>
<span class="line"><span>along with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.</span></span></code></pre></div><p>You&#39;d want to replace the year, name, email and GitHub username with your info.</p><p>Additionally, this is a good place to document your code, if you wish to share it with others.</p><h2 id="build-all-keyboards-that-support-a-specific-keymap" tabindex="-1">Build All Keyboards That Support a Specific Keymap <a class="header-anchor" href="#build-all-keyboards-that-support-a-specific-keymap" aria-label="Permalink to &quot;Build All Keyboards That Support a Specific Keymap&quot;"></a></h2><p>Want to check all your keymaps build in a single command? You can run:</p><pre><code>make all:&lt;name&gt;
</code></pre><p>For example,</p><pre><code>make all:jack
</code></pre><p>This is ideal for when you want ensure everything compiles successfully when preparing a <a href="https://github.com/qmk/qmk_firmware/pulls" target="_blank" rel="noreferrer"><em>Pull request</em></a>.</p><h2 id="examples" tabindex="-1">Examples <a class="header-anchor" href="#examples" aria-label="Permalink to &quot;Examples&quot;"></a></h2><p>For a brief example, checkout <a href="https://github.com/qmk/qmk_firmware/tree/master/users/_example" target="_blank" rel="noreferrer"><code>/users/_example/</code></a>.<br> For a more complicated example, checkout <a href="https://github.com/qmk/qmk_firmware/tree/master/users/drashna" target="_blank" rel="noreferrer"><code>/users/drashna/</code></a>&#39;s userspace.</p><h3 id="customized-functions" tabindex="-1">Customized Functions <a class="header-anchor" href="#customized-functions" aria-label="Permalink to &quot;Customized Functions&quot;"></a></h3><p>QMK has a bunch of <a href="./custom_quantum_functions">functions</a> that have <a href="./custom_quantum_functions#a-word-on-core-vs-keyboards-vs-keymap"><code>_quantum</code>, <code>_kb</code>, and <code>_user</code> versions</a> that you can use. You will pretty much always want to use the user version of these functions. But the problem is that if you use them in your userspace, then you don&#39;t have a version that you can use in your keymap.</p><p>However, you can actually add support for keymap version, so that you can use it in both your userspace and your keymap!</p><p>For instance, let&#39;s look at the <code>layer_state_set_user()</code> function. You can enable the <a href="./ref_functions#olkb-tri-layers">Tri Layer State</a> functionality on all of your boards, while also retaining the Tri Layer functionality in your <code>keymap.c</code> files.</p><p>In your <code>&lt;name.c&gt;</code> file, you&#39;d want to add this:</p><div class="language-c vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">c</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">__attribute__</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ((weak))</span></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">layer_state_t</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> layer_state_set_keymap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">layer_state_t</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> state</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> state;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">layer_state_t</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> layer_state_set_user</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">layer_state_t</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> state</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> state </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> update_tri_layer_state</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(state, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">2</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">3</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">5</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> layer_state_set_keymap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (state);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>The <code>__attribute__ ((weak))</code> part tells the compiler that this is a placeholder function that can then be replaced by a version in your <code>keymap.c</code>. That way, you don&#39;t need to add it to your <code>keymap.c</code>, but if you do, you won&#39;t get any conflicts because the function is the same name.</p><p>The <code>_keymap</code> part here doesn&#39;t matter, it just needs to be something other than <code>_quantum</code>, <code>_kb</code>, or <code>_user</code>, since those are already in use. So you could use <code>layer_state_set_mine</code>, <code>layer_state_set_fn</code>, or anything else.</p><p>You can see a list of this and other common functions in <a href="https://github.com/qmk/qmk_firmware/blob/master/users/drashna/template.c" target="_blank" rel="noreferrer"><code>template.c</code></a> in <a href="https://github.com/qmk/qmk_firmware/tree/master/users/drashna" target="_blank" rel="noreferrer"><code>users/drashna</code></a>.</p><h3 id="custom-features" tabindex="-1">Custom Features <a class="header-anchor" href="#custom-features" aria-label="Permalink to &quot;Custom Features&quot;"></a></h3><p>Since the Userspace feature can support a staggering number of boards, you may have boards that you want to enable certain functionality for, but not for others. And you can actually create &quot;features&quot; that you can enable or disable in your own userspace.</p><p>For instance, if you wanted to have a bunch of macros available, but only on certain boards (to save space), you could &quot;hide&quot; them being a <code>#ifdef MACROS_ENABLED</code>, and then enable it per board. To do this, add this to your rules.mk</p><div class="language-make vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">make</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">ifeq</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">$(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">strip</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> $(</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">MACROS_ENABLED</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">))</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, yes)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> OPT_DEFS += -DMACROS_ENABLED</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">endif</span></span></code></pre></div><p>The <code>OPT_DEFS</code> setting causes <code>MACROS_ENABLED</code> to be defined for your keyboards (note the <code>-D</code> in front of the name), and you could use <code>#ifdef MACROS_ENABLED</code> to check the status in your c/h files, and handle that code based on that.</p><p>Then you add <code>MACROS_ENABLED = yes</code> to the <code>rules.mk</code> for you keymap to enable this feature and the code in your userspace.</p><p>And in your <code>process_record_user</code> function, you&#39;d do something like this:</p><div class="language-c vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">c</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">bool</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> process_record_user</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">uint16_t</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> keycode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">keyrecord_t</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> *</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">record</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> switch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (keycode) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">#ifdef</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> MACROS_ENABLED</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> case MACRO1:</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">record</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">event.pressed) {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SEND_STRING</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;This is macro 1!&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> break</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> case MACRO2:</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">record</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">event.pressed) {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SEND_STRING</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;This is macro 2!&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> break</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">#endif</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><h3 id="consolidated-macros" tabindex="-1">Consolidated Macros <a class="header-anchor" href="#consolidated-macros" aria-label="Permalink to &quot;Consolidated Macros&quot;"></a></h3><p>If you wanted to consolidate macros and other functions into your userspace for all of your keymaps, you can do that. This builds upon the <a href="#customized-functions">Customized Functions</a> example above. This lets you maintain a bunch of macros that are shared between the different keyboards, and allow for keyboard specific macros, too.</p><p>First, you&#39;d want to go through all of your <code>keymap.c</code> files and replace <code>process_record_user</code> with <code>process_record_keymap</code> instead. This way, you can still use keyboard specific codes on those boards, and use your custom &quot;global&quot; keycodes as well. You&#39;ll also want to replace <code>SAFE_RANGE</code> with <code>NEW_SAFE_RANGE</code> so that you wont have any overlapping keycodes</p><p>Then add <code>#include &quot;&lt;name&gt;.h&quot;</code> to all of your keymap.c files. This allows you to use these new keycodes without having to redefine them in each keymap.</p><p>Once you&#39;ve done that, you&#39;ll want to set the keycode definitions that you need to the <code>&lt;name&gt;.h</code> file. For instance:</p><div class="language-c vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">c</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">#pragma</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> once</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;quantum.h&quot;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;action.h&quot;</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;version.h&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;">// Define all of</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">enum</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> custom_keycodes {</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> KC_MAKE </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> SAFE_RANGE,</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> NEW_SAFE_RANGE</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> //use &quot;NEW_SAFE_RANGE&quot; for keymap specific codes</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">};</span></span></code></pre></div><p>Now you want to create the <code>&lt;name&gt;.c</code> file, and add this content to it:</p><div class="language-c vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">c</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">#include</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> &quot;&lt;name&gt;.h&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">__attribute__</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ((weak))</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">bool</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> process_record_keymap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">uint16_t</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> keycode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">keyrecord_t</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> *</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">record</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;"> true</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">bool</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> process_record_user</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">uint16_t</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;"> keycode</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, </span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">keyrecord_t</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> *</span><span style="--shiki-light:#E36209;--shiki-dark:#FFAB70;">record</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> switch</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (keycode) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> case</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> KC_MAKE:</span><span style="--shiki-light:#6A737D;--shiki-dark:#6A737D;"> // Compiles the firmware, and adds the flash command based on keyboard bootloader</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">!</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">record</span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">-&gt;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">event.pressed) {</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> uint8_t</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> temp_mod </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> get_mods</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">();</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> uint8_t</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> temp_osm </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> get_oneshot_mods</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">();</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> clear_mods</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(); </span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;">clear_oneshot_mods</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">();</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SEND_STRING</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;make &quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> QMK_KEYBOARD </span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;:&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> QMK_KEYMAP);</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> #ifndef</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> FLASH_BOOTLOADER</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ((temp_mod </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">|</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> temp_osm) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MOD_MASK_SHIFT)</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> #endif</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SEND_STRING</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot;:flash&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> if</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> ((temp_mod </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">|</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> temp_osm) </span><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">&amp;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> MOD_MASK_CTRL) {</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> SEND_STRING</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">&quot; -j8 --output-sync&quot;</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> tap_code</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(KC_ENT);</span></span>
<span class="line"><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> set_mods</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(temp_mod);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> break</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">;</span></span>
<span class="line"></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> }</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;"> return</span><span style="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> process_record_keymap</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">(keycode, record);</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>For boards that may not have a shift button (such as on a macro pad), we need a way to always include the bootloader option. To do that, add the following to the <code>rules.mk</code> in your userspace folder:</p><div class="language-make vp-adaptive-theme"><button title="Copy Code" class="copy"></button><span class="lang">make</span><pre class="shiki shiki-themes github-light github-dark vp-code"><code><span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">ifeq</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> (</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">$(</span><span style="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">strip</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;"> $(</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">FLASH_BOOTLOADER</span><span style="--shiki-light:#032F62;--shiki-dark:#9ECBFF;">))</span><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">, yes)</span></span>
<span class="line"><span style="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> OPT_DEFS += -DFLASH_BOOTLOADER</span></span>
<span class="line"><span style="--shiki-light:#D73A49;--shiki-dark:#F97583;">endif</span></span></code></pre></div><p>This will add a new <code>KC_MAKE</code> keycode that can be used in any of your keymaps. And this keycode will output <code>make &lt;keyboard&gt;:&lt;keymap&gt;</code>, making frequent compiling easier. And this will work with any keyboard and any keymap as it will output the current boards info, so that you don&#39;t have to type this out every time.</p><p>Also, holding Shift will add the flash target (<code>:flash</code>) to the command. Holding Control will add some commands that will speed up compiling time by processing multiple files at once.</p><p>And for the boards that lack a shift key, or that you want to always attempt the flashing part, you can add <code>FLASH_BOOTLOADER = yes</code> to the <code>rules.mk</code> of that keymap.</p><div class="tip custom-block"><p class="custom-block-title">TIP</p><p>This should flash the newly compiled firmware automatically, using the correct utility, based on the bootloader settings (or default to just generating the HEX file). However, it should be noted that this may not work on all systems. AVRDUDE doesn&#39;t work on WSL, namely.</p></div></div></div></main><footer class="VPDocFooter" data-v-39a288b8 data-v-09de1c0f><!--[--><!--]--><!----><nav class="prev-next" data-v-09de1c0f><div class="pager" data-v-09de1c0f><a class="VPLink link pager-link prev" href="/feature_unicode" data-v-09de1c0f><!--[--><span class="desc" data-v-09de1c0f>Previous page</span><span class="title" data-v-09de1c0f>Unicode</span><!--]--></a></div><div class="pager" data-v-09de1c0f><a class="VPLink link pager-link next" href="/feature_wpm" data-v-09de1c0f><!--[--><span class="desc" data-v-09de1c0f>Next page</span><span class="title" data-v-09de1c0f>WPM Calculation</span><!--]--></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
<script>window.__VP_HASH_MAP__=JSON.parse("{\"capabilities_inc.md\":\"Ca9zpMce\",\"changelog_20200229.md\":\"DNsowwM1\",\"breaking_changes.md\":\"BtdqWQlY\",\"apa102_driver.md\":\"DGTINeKZ\",\"api_development_environment.md\":\"EhJClb9f\",\"changelog_20210227.md\":\"BWOtCaeS\",\"api_development_overview.md\":\"Dcey4ntL\",\"chibios_upgrade_instructions.md\":\"B5dMtL5R\",\"adc_driver.md\":\"DGNSFJQa\",\"cli_development.md\":\"CczMJOE3\",\"coding_conventions_c.md\":\"DdrpXBEh\",\"configurator_step_by_step.md\":\"GvmPtScT\",\"contributing.md\":\"DLsp4vSA\",\"configurator_default_keymaps.md\":\"B3v8dlHd\",\"configurator_troubleshooting.md\":\"BxGLPT8G\",\"changelog_20240225.md\":\"CGDoAFQ4\",\"changelog_20240526.md\":\"iGLFD0SP\",\"changelog_20200530.md\":\"Dk-vRpTQ\",\"changelog_20220528.md\":\"BdSPPJS6\",\"changelog_20231126.md\":\"D2Ok5QAf\",\"eeprom_driver.md\":\"CJGhJYmK\",\"faq_build.md\":\"Bryo1ywz\",\"changelog_20230226.md\":\"CEQKb2Sw\",\"faq_debug.md\":\"uJtFRvCN\",\"capabilities.md\":\"D_J-XtW-\",\"changelog_20230528.md\":\"BMuuw__T\",\"api_overview.md\":\"0FPaUsMb\",\"faq_keymap.md\":\"BNm1UZCq\",\"faq_general.md\":\"BC3pFw4U\",\"feature_os_detection.md\":\"DZib_QdQ\",\"feature_macros.md\":\"DpKdCniT\",\"feature_midi.md\":\"6rA7lbe-\",\"feature_mouse_keys.md\":\"Iyt3Hb3p\",\"changelog_20221126.md\":\"BOpHhXi2\",\"faq_misc.md\":\"qGrhOTu4\",\"keycodes_magic.md\":\"CGO3hgMm\",\"breaking_changes_history.md\":\"CkzdD6x8\",\"documentation_best_practices.md\":\"D_UwEt1C\",\"feature_advanced_keycodes.md\":\"jN1BLaPG\",\"feature_audio.md\":\"CSdy-B0q\",\"driver_installation_zadig.md\":\"BIO-iq8r\",\"newbs.md\":\"DnEWW2K4\",\"easy_maker.md\":\"BLadB4D_\",\"support.md\":\"CwJ_H6Qx\",\"custom_quantum_functions.md\":\"BabGw-ye\",\"syllabus.md\":\"0-MOMJnE\",\"getting_started_make_guide.md\":\"fsRi0mqX\",\"api_docs.md\":\"CRoD6CbL\",\"mod_tap.md\":\"CCeBcMHE\",\"feature_secure.md\":\"DTio1NtX\",\"cli_configuration.md\":\"CGSB128P\",\"feature_split_keyboard.md\":\"dSXqGTcC\",\"feature_oled_driver.md\":\"C3msZUgf\",\"coding_conventions_python.md\":\"BV-OK1s5\",\"cli.md\":\"BLzAdA6l\",\"changelog_20201128.md\":\"7XXL02Bn\",\"cli_commands.md\":\"DCpejdln\",\"getting_started_docker.md\":\"mz6HE4Bl\",\"feature_ps2_mouse.md\":\"DgKRvSpd\",\"support_deprecation_policy.md\":\"CCo4ljiw\",\"flashing_bootloadhid.md\":\"aXGP0bN5\",\"changelog_20200829.md\":\"CoqrOffn\",\"uart_driver.md\":\"Cby_2B9q\",\"understanding_qmk.md\":\"f-Bc_eHQ\",\"gpio_control.md\":\"BXAY05Da\",\"changelog_20210529.md\":\"CR1YNfZX\",\"unit_testing.md\":\"u3fgbGUj\",\"changelog_20220226.md\":\"Ee8ZP8S1\",\"hand_wire.md\":\"CieyXSH7\",\"cli_tab_complete.md\":\"ChaxfzYo\",\"data_driven_config.md\":\"BvLQ7P20\",\"arm_debugging.md\":\"BH-H2Ukz\",\"changelog_20190830.md\":\"Drtq3lMy\",\"feature_caps_word.md\":\"DFEidvi5\",\"feature_converters.md\":\"Bmv29bqN\",\"feature_bootmagic.md\":\"CHslUBOY\",\"feature_grave_esc.md\":\"Dfk03Mwq\",\"feature_led_indicators.md\":\"CZMu7H5E\",\"breaking_changes_instructions.md\":\"BAjIGeJb\",\"newbs_building_firmware_configurator.md\":\"yyo-1QDE\",\"changelog_20230827.md\":\"CkGh7Wzq\",\"feature_leader_key.md\":\"Bmrl3zQy\",\"feature_layouts.md\":\"qcy8hNMO\",\"newbs_building_firmware.md\":\"C7XiOjZf\",\"feature_led_matrix.md\":\"xGxJCIdk\",\"newbs_building_firmware_workflow.md\":\"YeGfwwbu\",\"newbs_flashing.md\":\"B42m5Wln\",\"newbs_external_userspace.md\":\"pD9Lc-a5\",\"feature_space_cadet.md\":\"BadigqA6\",\"feature_sequencer.md\":\"B9A4Z8EN\",\"compatible_microcontrollers.md\":\"6HA6FJZJ\",\"config_options.md\":\"D0qoSxZG\",\"tap_hold.md\":\"54I6XHRj\",\"feature_auto_shift.md\":\"0xqmu9IK\",\"feature_send_string.md\":\"ucKdf_1f\",\"hardware_drivers.md\":\"DFF5LGTT\",\"how_a_matrix_works.md\":\"JINKbCuX\",\"feature_rawhid.md\":\"_qE_L8rS\",\"ws2812_driver.md\":\"DXixRTSx\",\"hardware_keyboard_guidelines.md\":\"D6JrfTvT\",\"how_keyboards_work.md\":\"CB7z8ocb\",\"feature_userspace.md\":\"BsmY9yWw\",\"feature_wpm.md\":\"C-SARAXc\",\"flash_driver.md\":\"BTZjpIxy\",\"changelog_20210828.md\":\"X99NaKjy\",\"index.md\":\"B4QYzvHE\",\"
</body>
</html>