<spanclass="line"><span>}</span></span></code></pre></div><p>That datastructure is a direct representation of the matrix for a 5 row by 4 column numpad. When a key is pressed that key's position within the matrix will be returned as <code>1</code> instead of <code>0</code>.</p><p>Matrix Scanning runs many times per second. The exact rate varies but typically it runs at least 10 times per second to avoid perceptible lag.</p><h5id="matrix-to-physical-layout-map"tabindex="-1">Matrix to Physical Layout Map <aclass="header-anchor"href="#matrix-to-physical-layout-map"aria-label="Permalink to "Matrix to Physical Layout Map""></a></h5><p>Once we know the state of every switch on our keyboard we have to map that to a keycode. In QMK this is done by making use of C macros to allow us to separate the definition of the physical layout from the definition of keycodes.</p><p>At the keyboard level we define a C macro (typically named <code>LAYOUT()</code>) which maps our keyboard's matrix to physical keys. Sometimes the matrix does not have a switch in every location, and we can use this macro to pre-populate those with KC_NO, making the keymap definition easier to work with. Here's an example <code>LAYOUT()</code> macro for a numpad:</p><divclass="language-c vp-adaptive-theme"><buttontitle="Copy Code"class="copy"></button><spanclass="lang">c</span><preclass="shiki shiki-themes github-light github-dark vp-code"><code><spanclass="line"><spanstyle="--shiki-light:#D73A49;--shiki-dark:#F97583;">#define</span><spanstyle="--shiki-light:#6F42C1;--shiki-dark:#B392F0;"> LAYOUT</span><spanstyle="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">( </span><spanstyle="--shiki-light:#005CC5;--shiki-dark:#79B8FF;">\</span></span>
<spanclass="line"><spanstyle="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>Notice how the second block of our <code>LAYOUT()</code> macro matches the Matrix Scanning array above? This macro is what will map the matrix scanning array to keycodes. However, if you look at a 17 key numpad you'll notice that it has 3 places where the matrix could have a switch but doesn't, due to larger keys. We have populated those spaces with <code>KC_NO</code> so that our keymap definition doesn't have to.</p><p>You can also use this macro to handle unusual matrix layouts, for example the <ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/keyboards/sneakbox/aliceclone/aliceclone.h#L24"target="_blank"rel="noreferrer">Alice</a>. Explaining that is outside the scope of this document.</p><h5id="keycode-assignment"tabindex="-1">Keycode Assignment <aclass="header-anchor"href="#keycode-assignment"aria-label="Permalink to "Keycode Assignment""></a></h5><p>At the keymap level we make use of our <code>LAYOUT()</code> macro above to map keycodes to physical locations to matrix locations. It looks like this:</p><divclass="language-c vp-adaptive-theme"><buttontitle="Copy Code"class="copy"></button><spanclass="lang">c</span><preclass="shiki shiki-themes github-light github-dark vp-code"><code><spanclass="line"><spanstyle="--shiki-light:#D73A49;--shiki-dark:#F97583;">const</span><spanstyle="--shiki-light:#D73A49;--shiki-dark:#F97583;"> uint16_t</span><spanstyle="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> PROGMEM keymaps</span><spanstyle="--shiki-light:#D73A49;--shiki-dark:#F97583;">[]</span><spanstyle="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">[MATRIX_ROWS][MATRIX_COLS] </span><spanstyle="--shiki-light:#D73A49;--shiki-dark:#F97583;">=</span><spanstyle="--shiki-light:#24292E;--shiki-dark:#E1E4E8;"> {</span></span>
<spanclass="line"><spanstyle="--shiki-light:#24292E;--shiki-dark:#E1E4E8;">}</span></span></code></pre></div><p>Notice how all of these arguments match up with the first half of the <code>LAYOUT()</code> macro from the last section? This is how we take a keycode and map it to our Matrix Scan from earlier.</p><h5id="state-change-detection"tabindex="-1">State Change Detection <aclass="header-anchor"href="#state-change-detection"aria-label="Permalink to "State Change Detection""></a></h5><p>The matrix scanning described above tells us the state of the matrix at a given moment, but your computer only wants to know about changes, it doesn't care about the current state. QMK stores the results from the last matrix scan and compares the results from this matrix to determine when a key has been pressed or released.</p><p>Let's look at an example. We'll hop into the middle of a keyboard scanning loop to find that our previous scan looks like this:</p><divclass="language- vp-adaptive-theme"><buttontitle="Copy Code"class="copy"></button><spanclass="lang"></span><preclass="shiki shiki-themes github-light github-dark vp-code"><code><spanclass="line"><span>{</span></span>
<spanclass="line"><span> {0,0,0,0},</span></span>
<spanclass="line"><span> {0,0,0,0},</span></span>
<spanclass="line"><span> {0,0,0,0},</span></span>
<spanclass="line"><span> {0,0,0,0},</span></span>
<spanclass="line"><span> {0,0,0,0}</span></span>
<spanclass="line"><span>}</span></span></code></pre></div><p>And when our current scan completes it will look like this:</p><divclass="language- vp-adaptive-theme"><buttontitle="Copy Code"class="copy"></button><spanclass="lang"></span><preclass="shiki shiki-themes github-light github-dark vp-code"><code><spanclass="line"><span>{</span></span>
<spanclass="line"><span> {1,0,0,0},</span></span>
<spanclass="line"><span> {0,0,0,0},</span></span>
<spanclass="line"><span> {0,0,0,0},</span></span>
<spanclass="line"><span> {0,0,0,0},</span></span>
<spanclass="line"><span> {0,0,0,0}</span></span>
<spanclass="line"><span>}</span></span></code></pre></div><p>Comparing against our keymap we can see that the pressed key is <code>KC_NUM</code>. From here we dispatch to the <code>process_record</code> set of functions.</p><h5id="process-record"tabindex="-1">Process Record <aclass="header-anchor"href="#process-record"aria-label="Permalink to "Process Record""></a></h5><p>The <code>process_record()</code> function itself is deceptively simple, but hidden within is a gateway to overriding functionality at various levels of QMK. The chain of events is listed below, using cluecard whenever we need to look at the keyboard/keymap level functions. Depending on options set in <code>rules.mk</code> or elsewhere, only a subset of the functions below will be included in final firmware.</p><ul><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/action.c#L78-L140"target="_blank"rel="noreferrer"><code>void action_exec(keyevent_t event)</code></a><ul><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/quantum.c#L204"target="_blank"rel="noreferrer"><code>void pre_process_record_quantum(keyrecord_t *record)</code></a><ul><li><ahref="https://github.com/qmk/qmk_firmware/blob/27119fa77e8a1b95fff80718d3db4f3e32849298/quantum/quantum.c#L117"target="_blank"rel="noreferrer"><code>bool pre_process_record_kb(uint16_t keycode, keyrecord_t *record)</code></a><ul><li><ahref="https://github.com/qmk/qmk_firmware/blob/27119fa77e8a1b95fff80718d3db4f3e32849298/quantum/quantum.c#L121"target="_blank"rel="noreferrer"><code>bool pre_process_record_user(uint16_t keycode, keyrecord_t *record)</code></a></li></ul></li><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/process_keycode/process_combo.c#L521"target="_blank"rel="noreferrer"><code>bool process_combo(uint16_t keycode, keyrecord_t *record)</code></a></li></ul></li><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/action.c#L254"target="_blank"rel="noreferrer"><code>void process_record(keyrecord_t *record)</code></a><ul><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/quantum.c#L224"target="_blank"rel="noreferrer"><code>bool process_record_quantum(keyrecord_t *record)</code></a><ul><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/quantum.c#L225"target="_blank"rel="noreferrer">Map this record to a keycode</a></li><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/velocikey.c#L27"target="_blank"rel="noreferrer"><code>void velocikey_accelerate(void)</code></a></li><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/wpm.c#L109"target="_blank"rel="noreferrer"><code>void update_wpm(uint16_t keycode)</code></a></li><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/process_keycode/process_tap_dance.c#L118"target="_blank"rel="noreferrer"><code>void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record)</code></a></li><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/process_keycode/process_key_lock.c#L64"target="_blank"rel="noreferrer"><code>bool process_key_lock(uint16_t keycode, keyrecord_t *record)</code></a></li><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/process_keycode/process_dynamic_macro.c#L160"target="_blank"rel="noreferrer"><code>bool process_dynamic_macro(uint16_t keycode, keyrecord_t *record)</code></a></li><li><ahref="https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/process_keycode/process_clicky.c#L84"target="_blank"rel="noreferrer"><code>bool process_clicky(uint16_t keycode, keyrecord_t *record)</code></a></li><li><ahref="https: