├── .github └── workflows │ ├── main.yml │ └── trigger-deploy.yml ├── .gitignore ├── .vscode └── extensions.json ├── .yarn ├── install-state.gz └── releases │ └── yarn-4.7.0.cjs ├── .yarnrc.yml ├── LICENSE ├── README.md ├── components └── render-built-in-menus.tsx ├── docs ├── built_in_menus.mdx ├── configuring_qmk.md ├── custom_ui.mdx ├── download_firmware.mdx ├── layouts.md ├── mdx.md ├── specification.md ├── supported_keyboards.mdx ├── v3_changes.md └── whats_new.md ├── docusaurus.config.js ├── package.json ├── scripts └── generate-dynamic-content.js ├── sidebars.js ├── src ├── css │ └── custom.css ├── keyboard-names.json └── pages │ ├── index.js │ └── styles.module.css ├── static ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── img │ ├── custom_ui_button_control.png │ ├── custom_ui_color_control.png │ ├── custom_ui_dropdown_control.png │ ├── custom_ui_keycode_control.png │ ├── custom_ui_range_control.png │ ├── custom_ui_toggle_control.png │ ├── custom_ui_top_level_menus.png │ ├── encoder-with-push.png │ ├── favicon.ico │ ├── icon.png │ ├── just-encoder.png │ ├── optional-encoder.png │ ├── result.png │ ├── split_backspace.png │ ├── switch_matrix_coordinates.png │ ├── undraw_different_love.svg │ ├── undraw_game_world.svg │ ├── undraw_walking_around.svg │ ├── whats_new │ │ ├── cubey.png │ │ ├── key_tester.png │ │ ├── macro_recorder.png │ │ ├── via_2d.png │ │ └── via_3d.png │ └── wt60_d_layout_options.png ├── mstile-144x144.png ├── mstile-150x150.png ├── mstile-310x150.png ├── mstile-310x310.png ├── mstile-70x70.png ├── safari-pinned-tab.svg └── site.webmanifest ├── staticwebapp.config.json ├── templates ├── download_firmware.hbs └── supported_keyboards.hbs └── yarn.lock /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | # Controls when the workflow will run 5 | on: 6 | schedule: 7 | - cron: "0 14 * * *" 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | 11 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 12 | jobs: 13 | # This workflow contains a single job called "build" 14 | build: 15 | name: Request Netlify Webhook 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: POST to Build Hook 19 | run: curl -s -X POST -d {} ${{secrets.WEBHOOK}} 20 | -------------------------------------------------------------------------------- /.github/workflows/trigger-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Trigger Deployment 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | repository_dispatch: 9 | types: [definition_update] 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build_and_deploy_job: 14 | runs-on: ubuntu-latest 15 | name: Trigger deploy hook 16 | steps: 17 | - name: Send request to trigger deploy hook 18 | run: | 19 | curl -s -X POST "${{secrets.DEPLOY_HOOK_URL}}" 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | .DS_Store 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | dist/* 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (https://nodejs.org/api/addons.html) 36 | build/Release 37 | build/ 38 | .docusaurus 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # Optional npm cache directory 48 | .npm 49 | 50 | # Optional eslint cache 51 | .eslintcache 52 | 53 | # Optional REPL history 54 | .node_repl_history 55 | 56 | # Output of 'npm pack' 57 | *.tgz 58 | 59 | # Yarn Integrity file 60 | .yarn-integrity 61 | 62 | # dotenv environment variables file 63 | .env 64 | 65 | # next.js build output 66 | .next 67 | 68 | # Local Netlify folder 69 | .netlify 70 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "unifiedjs.vscode-mdx" 4 | ] 5 | } -------------------------------------------------------------------------------- /.yarn/install-state.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/.yarn/install-state.gz -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | checksumBehavior: update 3 | 4 | yarnPath: .yarn/releases/yarn-4.7.0.cjs 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [VIA Website](https://www.caniusevia.com) - Your keyboards best friend 2 | 3 | ![android-chrome-192x192](https://user-images.githubusercontent.com/1714072/222621960-ddfb8ee6-a486-4c66-8852-b204ba7c807b.png) 4 | 5 | VIA is a powerful, open-source web-based interface for configuring your [QMK](https://qmk.fm)-powered mechanical keyboard. It allows you to customize your keymaps, create macros, and adjust RGB settings (if it has RGB) on the fly, without needing to recompile your keyboard's firmware. This makes keyboard customization easier and more accessible for everyone. 6 | 7 | ## Getting VIA to support your keyboard 8 | 9 | Are you a keyboard maker or a developer interested in adding support for your keyboard? We welcome contributions to the VIA project! 10 | 11 | 1. The source code of the keyboard **has to be merged** in [QMK Firmware Repositories](https://github.com/qmk/qmk_firmware) Master branch. 12 | 2. Your `keymaps/via` keymap **has to be merged** in [VIA's QMK Userspace Repository](https://github.com/the-via/qmk_userspace_via) Main branch. 13 | 3. Create a definition in JSON format for your keyboard and submit it as a pull request to [VIA's Keyboards Repository](https://github.com/the-via/keyboards) Master branch. 14 | 15 | Please follow our [Specification documentation](https://www.caniusevia.com/docs/specification) carefully to ensure your pull request is smoothly reviewed and merged. 16 | 17 | ## Local development setup 18 | 19 | This website is built using [Docusaurus 2](https://v2.docusaurus.io/), a modern static website generator. 20 | 21 | ### Installation 22 | 23 | ```bash 24 | $ yarn 25 | ``` 26 | 27 | ### Local Development 28 | 29 | ```bash 30 | $ yarn start 31 | ``` 32 | 33 | This command starts a local development server and open up a browser window. Most changes are reflected live without having to restart the server. 34 | 35 | ### Build 36 | 37 | ```bash 38 | $ yarn build 39 | ``` 40 | 41 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 42 | 43 | ### Deployment 44 | 45 | ```bash 46 | $ GIT_USER= USE_SSH=true yarn deploy 47 | ``` 48 | 49 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 50 | 51 | ## Facing Issues? 52 | 53 | If you encounter any issues or bugs while using the [VIA Web Application](https://usevia.app), please report them by opening an issue in the [VIA Web Application Repository](https://github.com/the-via/app/issues). This will help us to track down and resolve problems, and improve the VIA experience for everyone. 54 | 55 | Before reporting, please make sure to check if an issue has already been reported. Thank you! 56 | -------------------------------------------------------------------------------- /components/render-built-in-menus.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { commonMenus } from "@the-via/reader"; 3 | import CodeBlock from "@theme/CodeBlock"; 4 | import stringify from "json-stringify-pretty-compact"; 5 | import Heading from "@theme/Heading"; 6 | 7 | export const RenderCommonMenus = () => 8 | Object.entries(commonMenus).map(([key, value]) => { 9 | return ( 10 |
11 | 12 | {key} 13 | 14 | 15 | {stringify(value)} 16 | 17 |
18 | ); 19 | }); 20 | -------------------------------------------------------------------------------- /docs/built_in_menus.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: built_in_menus 3 | title: Built-in Menus 4 | sidebar_label: Built-in Menus 5 | --- 6 | 7 | import { RenderCommonMenus } from "../components/render-built-in-menus"; 8 | import { commonMenus } from "@the-via/reader"; 9 | export const toc = Object.keys(commonMenus).map((key) => ({ 10 | value: key, 11 | id: key, 12 | level: 2, 13 | })); 14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/configuring_qmk.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: configuring_qmk 3 | title: Configuring QMK 4 | sidebar_label: Configuring QMK 5 | --- 6 | 7 | ## Overview 8 | 9 | VIA works by communicating with the firmware that is running on the device and sending it commands across USB. Enabling the VIA feature in QMK enables both the ability to communicate with the VIA Configurator and the ability to store keymaps and other settings. 10 | 11 | - Create a `via` keymap directory and files within that are separate from the default keymap 12 | - Make changes to the keyboard's `info.json` and `rules.mk` to make the firmware compatible 13 | 14 | ## Create a `via` Keymap Directory and Files in QMK Source 15 | 16 | VIA compatible firmware must be a separate QMK build target from the default keymap. Create a `via` keymap directory, e.g. `keyboards//keymaps/via` 17 | 18 | For acceptance into the upstream QMK repository this folder must be named `via`, but that is not an absolute requirement for your copy of the repository. It is possible to add VIA support to any keymap with the correct configuration. 19 | 20 | ## Create a `rules.mk` in `keyboards//keymaps/via` 21 | 22 | In most cases this file will only require: 23 | 24 | VIA_ENABLE = yes 25 | 26 | Make sure `yes` is lowercase. `YES` will not enable VIA and you will be most confused. 27 | 28 | This will enable dynamic keymaps, raw HID message handling and bootmagic lite. 29 | 30 | ‘Bootmagic Lite’ is the ability to hold down Esc (or some other key) while plugging in the keyboard to both jump to bootloader and reset the EEPROM. Thus if for some reason the EEPROM contains data that is out of sync with the firmware, and things aren’t working as expected (e.g. garbage keycodes in VIA), the device can be ‘factory reset’. It also makes redundant the need for a ‘QK_BOOT’ keycode in the keymap. 31 | 32 | Do not put `VIA_ENABLE = yes` in the keyboard directory’s `rules.mk`. This configuration should only be added to VIA-specific keymaps, not enabled by default at the keyboard level. 33 | 34 | ## Create a `keymap.c` or `keymap.json` in `keyboards//keymaps/via` 35 | 36 | The keymap in the `via` keymap folder should use a `LAYOUT_*()` macro that allows all the electrical positions to be mapped, even if that layout isn't physically possible. 37 | 38 | By default, dynamic keymaps have 4 layers. These will be automatically populated with `KC_TRNS` keycodes as necessary, so there is no need to create more than 4 layers in your keymap in the default case. 39 | 40 | There typically is no need to use a `config.h` in the `via` keymap directory. 41 | 42 | > Q: Can I use more or less than 4 layers? 43 | > 44 | > A: Yes, if it can fit in the EEPROM space. This is advanced usage and requires understanding how dynamic keymaps works and overriding the default settings. 45 | 46 | ## Changes to keyboard directory’s `info.json` 47 | 48 | ### Change `usb.vid` and `usb.pid` 49 | 50 | There is a high probability that these values are the defaults from the QMK new keyboard script or were copied from another keyboard implementation and left unchanged, e.g: 51 | 52 | "usb": { 53 | "vid": "0xFEED", 54 | "pid": "0x0000", 55 | } 56 | 57 | VIA Configurator uses these to identify the device, so they must be unique to the device. 58 | 59 | Note that multiple versions/revisions of a keyboard PCB can use the same vendor/product if they function identically from VIA Configurator’s point of view, i.e. they have the same (or compatible) physical key layout and switch matrix topology and the same “layout macro” (mapping physical key layout to switch matrix layout) is used. VIA Configurator doesn’t care which I/O pins are being used, it just reads/writes keycodes to the dynamic keymaps stored in switch matrix addressing. As such, please consider carefully whether you actually need to create more than one vendor/product ID pair for multiple versions of the same keyboard PCB. 60 | 61 | It is recommended to choose a value of `vid` that unique to the keyboard PCB’s designer/vendor, i.e. it will be the same for all keyboards with a common parent directory. 62 | 63 | For example, keyboards in `/keyboards/wilba_tech` use: 64 | 65 | "vid": "0x6582" 66 | 67 | After choosing a `vid` value, search for this value in all `info.json` files to ensure it is unique. To confirm your search is working correctly, the `info.json` being changed should be in the search results. 68 | 69 | A suggested method of choosing a unique `vid` is choosing two letters from the keyboard’s designer/vendor name and using the two 8-bit ASCII values of these letters. 70 | 71 | For example, keyboards in `/keyboards/kingly_keys` will all use: 72 | 73 | "vid": "0x4B4B" 74 | 75 | The ASCII value of the letter “K” is 4B. Thus **K**ingly **K**eys becomes 0x4B4B. 76 | 77 | Choose a `pid` that is unique for all keyboards using the same `vid`. They can simply be numbered sequentially, e.g. 0x0001, 0x0002. 78 | 79 | > Q: Wouldn’t it be better if all VIA compatible keyboards used the same vendor/product IDs (perhaps an officially licenced one) and then VIA queries to get the device identity? 80 | > 81 | > A: Yes, it would be slightly better, but this method continues QMK’s unofficial use of arbitrary vendor/product IDs and doesn’t introduce another unique ID. 82 | 83 | ### Change `keyboard_name` 84 | 85 | The value of `keyboard_name` in `info.json` is what will appear in the list of devices (for example, in the ‘Bluetooth & other devices’ page of Windows, and in a notification when the device is first connected and being ‘installed’). 86 | 87 | "keyboard_name": "WT60-D" 88 | 89 | VIA Configurator will switch to using the value of `keyboard_name` when displaying the device’s name in the future, rather than using the name in the VIA layout definition. This will allow firmware level customization. 90 | 91 | Note that spaces are allowed. 92 | 93 | ### Set `bootmagic.matrix` (optional) 94 | 95 | If the Esc key (or top left key) of the keyboard is not at matrix position (0,0), then explicitly set its matrix position in `info.json` at the keyboard level. 96 | 97 | "bootmagic": { 98 | "matrix": [3, 4] 99 | } 100 | 101 | For consistency, it should be set to the top left key of the keyboard, even if this is not the Esc key (e.g. left side numpad keyboards, 40% and smaller keyboards, etc). Always test this works before submitting the PR to QMK. 102 | 103 | You may want to consider enabling bootmagic lite at the keyboard level (i.e. adding `"bootmagic": true` to the `features` list in `info.json`). This will automatically be enabled for VIA-enabled builds, but it is still useful for VIA-disabled builds so that the device can be switched into bootloader mode without requiring a `QK_BOOT` keycode or pressing the reset button on the PCB. 104 | 105 | ## VIA settings in `config.h` 106 | 107 | The VIA implementation in QMK will automatically define its own settings for EEPROM usage, the number of layers used for dynamic keymaps, etc. Unless the keyboard requires loading/saving its own state to EEPROM outside of QMK’s core EEPROM usage, there is no need to override the default settings. 108 | 109 | However, if you are doing something advanced and require changing VIA’s settings, add a `config.h` to the `via` keymap directory. 110 | 111 | ### `VIA_EEPROM_LAYOUT_OPTIONS_SIZE` 112 | 113 | `VIA_EEPROM_LAYOUT_OPTIONS_SIZE` controls the size of EEPROM memory to store layout options (1-4 bytes, default 1). The number of bits to store one layout option is the number of bits to store the largest choice number, i.e. 1 bit for 2 choices, 2 bits for 3-4 choices, 3 bits for 5-8 choices, 4 bits for 9-16 choices. You only need to override this in `config.h` if you need more than 8 bits total. 114 | 115 | ### `VIA_EEPROM_CUSTOM_CONFIG_SIZE` 116 | 117 | `VIA_EEPROM_CUSTOM_CONFIG_SIZE` controls the size of EEPROM memory to store keyboard specific configuration, such as lighting settings, rotary encoder settings, display settings. It defaults to 0 bytes. Keyboard level code can use `VIA_EEPROM_CUSTOM_CONFIG_ADDR` as the start address of EEPROM reserved for its use. 118 | 119 | ## EEPROM Memory Usage 120 | 121 | When VIA is enabled, EEPROM memory is assigned as: 122 | 123 | - QMK Core 124 | - VIA (`VIA_EEPROM_MAGIC_ADDR` to `VIA_EEPROM_CUSTOM_CONFIG_ADDR-1`) 125 | - Custom Config (`VIA_EEPROM_CUSTOM_CONFIG_ADDR` to `VIA_EEPROM_CUSTOM_CONFIG_ADDR+VIA_EEPROM_CUSTOM_CONFIG_SIZE-1`) 126 | - Dynamic Keymaps (`DYNAMIC_KEYMAP_EEPROM_ADDR` to `DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR-1`) 127 | - Macros (`DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR` to `DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR+DYNAMIC_KEYMAP_MACRO_EEPROM_SIZE-1`) 128 | 129 | Unless a keyboard is implementing its own storage of state, there is no need to set anything. By enabling VIA, the defaults are set to use EEPROM memory as above. By default, dynamic keymaps have 4 layers. If your keymap does not specify keycodes for all 4 layers, the rest will be automatically filled in with `KC_TRNS`; there is no need to hardcode "filler" `KC_TRNS` layers. 130 | 131 | ## Running out of space? 132 | 133 | Keyboards with many features and/or large keymaps may fail to compile with VIA support if there is not enough flash memory or EEPROM available. 134 | 135 | Reducing the number of dynamic keymap layers available will lower EEPROM usage and firmware size. This can be accomplished by setting `dynamic_keymap.layer_count` appropriately in `info.json`: 136 | 137 | "dynamic_keymap": { 138 | "layer_count": 3 139 | } 140 | 141 | To reduce firmware size, consider turning on link time optimization by adding `LTO_ENABLE = yes` to the keymap directory's `rules.mk` file. This may have unexpected side effects on keyboards using ARM processors, so test thoroughly with it enabled and disabled. 142 | 143 | If link time optimization doesn't get the job done or exposes buggy behavior, you may have to disable QMK features. More advice on this can be found [in QMK's documentation](https://docs.qmk.fm/#/squeezing_avr). 144 | -------------------------------------------------------------------------------- /docs/custom_ui.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: custom_ui 3 | title: Custom UI 4 | sidebar_label: Custom UI 5 | --- 6 | 7 | import { commonMenus } from "@the-via/reader"; 8 | import Link from "@docusaurus/Link"; 9 | 10 | ## Introduction 11 | 12 | The built-in menus of VIA (`Keymap`, `Layouts`, `Macros`, `Save + Load`) will be displayed depending on keyboard definition and firmware. 13 | 14 | The `menus` element is used to define more menus in VIA. It can contain **one or more** of the following built-in UI definitions: 15 | 16 |
    17 | {Object.keys(commonMenus).map((key) => ( 18 |
  • 19 | {key} 20 |
  • 21 | ))} 22 | 23 |
24 | 25 | **and/or** a definition of custom UI, i.e. explicitly defining all the UI controls required. 26 | 27 | For example, a definition enabling the built-in UI for QMK RGB Matrix could be done like so: 28 | 29 | ```json 30 | "menus": ["qmk_rgb_matrix" ] 31 | ``` 32 | 33 | **or alternatively** defined explicitly using custom UI definitions, like so: 34 | 35 | ```json 36 | ... 37 | "menus": [ 38 | { 39 | "label": "Lighting", 40 | "content": [ 41 | { 42 | "label": "Backlight", 43 | "content": [ 44 | { 45 | "label": "Brightness", 46 | "type": "range", 47 | "options": [0, 255], 48 | "content": ["id_qmk_rgb_matrix_brightness", 3, 1] 49 | }, 50 | ... 51 | ] 52 | } 53 | ] 54 | } 55 | ] 56 | ``` 57 | 58 | The `"qmk_backlight"`, `"qmk_rgblight"`, `"qmk_rgb_matrix"`, `"qmk_backlight_rgblight"` and `"qmk_audio"` strings enable the built-in UI definitions that match the default implementation of VIA protocol handlers in QMK, with respect to `channel_id`, `value_id`, etc. 59 | 60 | These [built-in UI definitions](/docs/built_in_menus) are defined the same way as custom UI definitions (i.e. JSON format). They can be used as examples to create custom UI definitions. 61 | 62 | Definitions containing multiple top level menus with the same name (e.g. `Lighting`) will not merge into one top level menu. Thus, combining `"qmk_backlight"` and `"qmk_rgblight"` will result in two top-level `Lighting` menus. Use `"qmk_backlight_rgblight"` instead. 63 | 64 | Similarly, combining built-in UI definitions with custom UI that has the same top-level menu name will result in multiple top-level menus, not a merged one. If you want to combine a built-in UI like `qmk_rgb_matrix` with extra lighting sub-menus under a single `Lighting` top level menu, explicitly define all the UI controls using the built-in UI definition as the base. 65 | 66 | ## Structure 67 | 68 | A custom UI definition (as a child element of `menu`) consists of a single top-level menu element with `label` and `content` elements. 69 | 70 | A top-level menu element must contain one or more sub-menu elements as an array in `content`. 71 | 72 | Each sub-menu element consists of a `label` and `content` element, and must contain one or more UI control elements as an array in the `content` element. 73 | 74 | Each UI control element must have `label`, `type` and `content` elements. 75 | 76 | Thus the "tree" has a maximum depth of three: top-level menu, sub-menu and UI control, and the type of entity is inferred from the depth. 77 | 78 | ## Top Level Menus and Sub-Menus 79 | 80 | Each element in the `menus` element defines a top-level menu, either a built-in one or a custom defined one. When custom defined, `label` defines the name displayed in the top left menu of the VIA app, and `content` is an array of sub-menu elements. 81 | 82 | The following example defines: 83 | 84 | - a top level menu `Lighting` with sub-menus `Underglow` and `Indicators` 85 | - a top level menu `Display` with sub-menus `General` and `Advanced` 86 | 87 | ```json 88 | "menus": [ 89 | { 90 | "label": "Lighting", 91 | "content": [ 92 | { 93 | "label": "Underglow", 94 | ... 95 | }, 96 | { 97 | "label": "Indicators", 98 | ... 99 | } 100 | ] 101 | }, 102 | { 103 | "label": "Display", 104 | "content": [ 105 | { 106 | "label": "General", 107 | ... 108 | }, 109 | { 110 | "label": "Advanced", 111 | ... 112 | } 113 | ] 114 | } 115 | ] 116 | ``` 117 | 118 | VIA will then display `Lighting` and `Display` in the top left menu, and then display the sub-menus in the bottom left, like this: 119 | 120 | ![Top Level Menus](/img/custom_ui_top_level_menus.png) 121 | 122 | **Note: Top-level menus should be consistent across all keyboards in VIA.** 123 | 124 | For example, all custom UI defined for any kind of lighting should use a top-level menu called `Lighting`, and then the sub-menus should be named with the specifics of that lighting, such as `Underglow`, `Buttglow®`, `Backlight`, `Indicators`. 125 | 126 | Other top-level menus should be similarly generalized, such as `Audio`, `Display`, `Knobs`, etc. 127 | 128 | Top-level menus will be displayed with an icon based on the `label`. The current list is: 129 | 130 | - `"Lighting"` 131 | - `"Audio"` 132 | - `"Display"` 133 | 134 | Top level menus with a `label` not in this list will be displayed with a generic icon. 135 | 136 | In the case where a built-in definition requires some changes to match the firmware, the built-in definition can be inserted in place in the `menus` element and modified. In most cases, the default handlers in the firmware can be used. 137 | 138 | Examples of this are: 139 | 140 | - Replacing the sub-menu name `Underglow` with a different name 141 | - Configuring the set of lighting effects (e.g. changing the array of string/number pairs) 142 | - Adding a new sub-menu and controls to match keyboard-level code which overrides the default behaviour (e.g. customized indicators) 143 | 144 | This is facilitated by the use of `channel_id` in the set/get custom value commands. See [#Channels](#channels) 145 | 146 | ## UI Controls 147 | 148 | ### Definition 149 | 150 | The sub-menu element has a `content` element, which is an array of UI control elements. Each UI control element must have `label`, `type` and `content` elements. 151 | 152 | Example: 153 | 154 | ```json 155 | "menus": [ 156 | { 157 | "label": "Lighting", 158 | "content": [ 159 | { 160 | "label": "Underglow", 161 | "content": [ 162 | { 163 | "label": "Brightness", 164 | "type": "range", 165 | "options": [0, 255], 166 | "content": ["id_qmk_rgblight_brightness", 2, 1] 167 | }, 168 | { 169 | "label": "Effect", 170 | "type": "dropdown", 171 | "content": ["id_qmk_rgblight_effect", 2, 2], 172 | "options": [ 173 | "All Off", 174 | "Solid Color", 175 | "Breathing 1", 176 | ... 177 | ] 178 | } 179 | ] 180 | } 181 | ] 182 | } 183 | ] 184 | ``` 185 | 186 | `label` defines the text label on the left of the control 187 | 188 | `type` defines the type of control. Valid values are: 189 | - `button` 190 | - `toggle` 191 | - `range` 192 | - `dropdown` 193 | - `color` 194 | - `keycode` 195 | 196 | `options` defines the possible values of the control (the numerical range, or string/integer values) 197 | 198 | `content` defines the binding of the control to the `channel_id` and `value_id` used in the VIA protocol. These values are preceeded by a `value_key` string that is used by VIA. The `value_key` should match the name of the enum value in the firmware for uniqueness and readability. It must be unique for all UI controls in a UI definition. 199 | 200 | For example: 201 | 202 | ```json 203 | { 204 | "label": "Brightness", 205 | "type": "range", 206 | "options": [0, 255], 207 | "content": ["id_qmk_rgblight_brightness", 2, 1] 208 | } 209 | ``` 210 | 211 | ... defines a range (slider) UI control, labelled `Brightness`, with a range of 0 to 255. It will be using `channel_id` of `2` and `value_id` of `1` in the VIA protocol to set/get the value in the firmware. It has a `value_key` of `"id_qmk_rgblight_brightness"` because the `value_id` of `1` matches the integer value of `id_qmk_rgblight_brightness` in enum `id_qmk_rgblight` in the firmware code. 212 | 213 | ### Button Control 214 | 215 | The button control is a clickable that sends a numeric value. 216 | 217 | 218 | ![Custom UI Button Control](/img/custom_ui_button_control.png) 219 | 220 | ```json 221 | { 222 | "label": "Test button", 223 | "type": "button", 224 | "options": [10], 225 | "content": ["id_test_button", 0, 3] 226 | } 227 | ``` 228 | 229 | The `options` element defines value to be sent, e.g. `"options": [10],`. The value data is one byte (i.e. <=255), otherwise it is two bytes. See [Handling 16-bit Values](#handling-16-bit-values) for handling two byte values. 230 | 231 | 232 | ### Toggle Control 233 | 234 | The toggle control is a toggle switch that controls a boolean (on/off) value. 235 | 236 | ![Custom UI Toggle Control](/img/custom_ui_toggle_control.png) 237 | 238 | ```json 239 | { 240 | "label": "God Mode", 241 | "type": "toggle", 242 | "content": ["id_god_mode", 0, 1] 243 | } 244 | ``` 245 | 246 | The default value data is one byte, either `0` or `1`. The `options` element can be used to define the two values if required, using an array of two values. 247 | 248 | ### Range Control 249 | 250 | The range control is a slider that controls a numeric value. The `options` element defines the range limits, e.g. `"options": [0, 255],`. The value data is one byte if the range maximum can fit in one byte (i.e. <=255), otherwise it is two bytes. See [Handling 16-bit Values](#handling-16-bit-values) for handling two byte values. 251 | 252 | ![Custom UI Range Control](/img/custom_ui_range_control.png) 253 | 254 | ```json 255 | { 256 | "label": "Audacity", 257 | "type": "range", 258 | "options": [0, 255], 259 | "content": ["id_audacity", 0, 2] 260 | } 261 | ``` 262 | 263 | ### Dropdown Control 264 | 265 | The dropdown control is a drop-down menu of strings, which maps to an integer value. The `options` element defines the item labels and associated number. 266 | 267 | ![Custom UI Dropdown Control](/img/custom_ui_dropdown_control.png) 268 | 269 | ```json 270 | { 271 | "label": "Date Format", 272 | "type": "dropdown", 273 | "options": [ 274 | ["yyyy-mm-dd", 0], 275 | ["dd/mm/yyyy", 1], 276 | ["mm/dd/yyyy", 2] 277 | ], 278 | "content": ["id_date_format", 0, 5] 279 | } 280 | ``` 281 | 282 | The numbers can be omitted from `options`, in which case, the array is of strings and the numbers implicitly assigned starting at zero, for example: 283 | 284 | ```json 285 | "options": [ 286 | "yyyy-mm-dd", 287 | "dd/mm/yyyy", 288 | "mm/dd/yyyy" 289 | ] 290 | ``` 291 | 292 | This allows easier definition of things like lighting effects, which can be conditionally enabled. Firmware authors can copy the full set of strings from the built-in UI definition and edit it to match the firmware, without needing to define the numbers. 293 | 294 | ### Color Control 295 | 296 | The color control is a swatch of color showing the current color value, which pops up a color picker when clicked. It allows selection of hue and saturation values only, since brightness is usually controlled separately in lighting code. 297 | 298 | ![Custom UI Color Control](/img/custom_ui_color_control.png) 299 | 300 | ```json 301 | { 302 | "label": "Color", 303 | "type": "color", 304 | "content": ["id_qmk_rgblight_color", 2, 4] 305 | } 306 | ``` 307 | 308 | ### Keycode Control 309 | 310 | The keycode control allows display and editing of a QMK keycode. Firmware writers can use this for custom rotary encoder handling or any other way of triggering keycode events. 311 | 312 | ![Custom UI Keycode Control](/img/custom_ui_keycode_control.png) 313 | 314 | ```json 315 | { 316 | "label": "Head Slam", 317 | "type": "keycode", 318 | "content": ["id_head_slam", 0, 6] 319 | } 320 | ``` 321 | 322 | Keycodes are 16-bit values, so the value data is two bytes. See [Handling 16-bit Values](#handling-16-bit-values) 323 | 324 | ### Showing/Hiding Controls 325 | 326 | Sometimes good UI design requires only showing a control when another control is in a given state. For example, a dropdown control for a "mode" and only showing controls which are used in that "mode". 327 | 328 | The `showIf` element can be used to show one (or more) UI controls only if the expression evaluates true. 329 | 330 | The built-in UI for `qmk_rgblight` shows an example of `showIf`. The `Effect Speed` and `Color` are only shown for some `Effect` values. Note how the value of a dropdown control evaluates to the number value of the string/number pair. 331 | 332 | Example: 333 | 334 | ```json 335 | { 336 | "label": "Effect", 337 | "type": "dropdown", 338 | "content": ["id_qmk_rgblight_effect", 2, 2], 339 | "options": [ 340 | "All Off", 341 | "Solid Color", 342 | "Breathing 1", 343 | "Breathing 2", 344 | "Breathing 3", 345 | "Breathing 4", 346 | ... 347 | ] 348 | }, 349 | { 350 | "showIf": "{id_qmk_rgblight_effect} >= 2", 351 | "label": "Effect Speed", 352 | "type": "range", 353 | "options": [0, 3], 354 | "content": ["id_qmk_rgblight_effect_speed", 2, 3] 355 | }, 356 | { 357 | "showIf": "{id_qmk_rgblight_effect} > 0", 358 | "label": "Color", 359 | "type": "color", 360 | "content": ["id_qmk_rgblight_color", 2, 4] 361 | } 362 | ``` 363 | 364 | Alternatively, the `showIf` element can "contain" one or more UI controls, which are only shown if the expression evaluates true. 365 | 366 | For example, the following will only display the `Audacity` and `Tenacity` range controls if the `God Mode` toggle is on. 367 | 368 | ```json 369 | { 370 | "label": "God Mode", 371 | "type": "toggle", 372 | "content": ["id_god_mode", 0, 1] 373 | }, 374 | { 375 | "showIf": "{id_god_mode} == 1", 376 | "content": [ 377 | { 378 | "label": "Audacity", 379 | "type": "range", 380 | "options": [0, 255], 381 | "content": ["id_audacity", 0, 2] 382 | }, 383 | { 384 | "label": "Tenacity", 385 | "type": "range", 386 | "options": [0, 255], 387 | "content": ["id_tenacity", 0, 3] 388 | } 389 | ] 390 | } 391 | ... 392 | ``` 393 | 394 | The expression evaluator uses operators such as `==`, `!=`, `<`, `<=`, `>`, `>=`, `||`, `&&`, `!`, `(`, `)`. Values are referenced by enclosing their key string in `{` and `}`. 395 | 396 | ### Array Values 397 | 398 | Sometimes firmware has a set of the same type of values, for which enumerating each in an enum, and using a range of `value_id` values, is not elegant. 399 | 400 | In this situation, **one or more numbers** can be added after the `value_id` in the `content` element, These can be used for any purpose in the firmware, such as an index to an array. 401 | 402 | Example: 403 | 404 | ```json 405 | "content": ["id_some_value_array[0]", 9, 99, 0] 406 | ``` 407 | 408 | For example, to control 3 color values, rather than defining 3 enum values in firmware, a single enum value `id_buttglow_color` can be used, a single integer value used for `value_id`, and a value index appended in the UI control definition, as follows: 409 | 410 | ```json 411 | { 412 | "label": "Color 1", 413 | "type": "color", 414 | "content": ["id_buttglow_color[0]", 0, 4, 0] 415 | }, 416 | { 417 | "label": "Color 2", 418 | "type": "color", 419 | "content": ["id_buttglow_color[1]", 0, 4, 1] 420 | }, 421 | { 422 | "label": "Color 3", 423 | "type": "color", 424 | "content": ["id_buttglow_color[2]", 0, 4, 2] 425 | } 426 | ``` 427 | 428 | Note that the `value_key` (the string in `content`) must be unique per UI control, so for array values, include the array index in the string. 429 | 430 | See [Handling Array Values](#handling-array-values) 431 | 432 | ## Firmware Implementation 433 | 434 | Custom UI is handled in firmware by handling three commands of the VIA protocol: 435 | 436 | - `id_custom_set_value` 437 | - `id_custom_get_value` 438 | - `id_custom_save` 439 | 440 | When enabling VIA and a feature (like lighting) in QMK Core, by default, the command handlers that match the built-in UI definitions will be compiled. Firmware authors who do not add or extend a feature do not need to write handlers of the above commands. 441 | 442 | The following describes how to implement handlers for the above commands, in keyboard level code, to match the custom UI definitions in VIA. 443 | 444 | ### Channel ID 445 | 446 | `id_custom_set_value` and `id_custom_get_value` commands use a `channel_id` for routing commands to handlers for that feature, and a `value_id` to identify the value. 447 | 448 | `channel_id` is a qualifier to `value_id`, allowing multiple enums with overlapping integer ranges to be used, rather than a single enum that must be the superset of all values for all features. 449 | 450 | The built-in UI definitions use `channel_id` values that match the default values in firmware. When using custom UI definitions, the `channel_id` values can be defined to anything on both sides (QMK and VIA). 451 | 452 | `id_custom_save` command uses a `channel_id` to signal saving the current state of values associated with that channel. See [Saving Values](#saving-values) 453 | 454 | ### Value ID 455 | 456 | When implementing a new feature, either in QMK Core or at the keyboard level, define a new enum for the possible `value_id` values, explicitly assigning integer values starting with `1`. 457 | 458 | For example: 459 | 460 | ```c 461 | enum via_buttglow_value { 462 | id_buttglow_brightness = 1, 463 | id_buttglow_effect = 2, 464 | id_buttglow_effect_speed = 3, 465 | id_buttglow_color = 4 466 | }; 467 | ``` 468 | 469 | ### Command Handlers 470 | 471 | `via_custom_value_command()` (in `via.c`) has the default handling of custom value commands for QMK Core modules like lighting. It will use the `channel_id` to route the commands to handlers specific to that feature. If the `channel_id` in the command does not match the channels it is enabled to handle, it will call `via_custom_value_command_kb()`, allowing keyboard level code to handle the commands for that `channel_id`. 472 | 473 | Thus, overriding `via_custom_value_command_kb()` in the keyboard level code allows firmware authors to write a command handler to set/get the values defined by the custom UI definition in VIA. 474 | 475 | In the simple case of implementing a few keyboard specific custom values, it is recommended to use a `channel_id` of `id_custom_channel = 0`, which won't conflict with the channels being handled in `via.c`, as these start with `1`. However, firmware authors could choose to use multiple `channel_id` values, to support multiple features. 476 | 477 | It is possible to combine the default command handlers for a QMK feature (using the default `channel_id`) with a command handler for a keyboard specific feature. For example, a firmware author could use the built-in UI for RGB Matrix on channel `id_qmk_rgb_matrix_channel = 4`, and implement `via_custom_value_command_kb()` to only handle commands on channel `id_custom_channel = 0`. 478 | 479 | In the rare case of needing to subvert/extend/replace the default custom value handling of a QMK feature, `via_custom_value_command()` itself can be overridden and reimplemented in keyboard level code, handling the `channel_id` for QMK features. 480 | 481 | The following is an example of implementing `via_custom_value_command_kb()`. It routes the three commands to functions to handle each command, this avoids nested switch/case statements and improves readability. 482 | 483 | ```c 484 | void via_custom_value_command_kb(uint8_t *data, uint8_t length) { 485 | // data = [ command_id, channel_id, value_id, value_data ] 486 | uint8_t *command_id = &(data[0]); 487 | uint8_t *channel_id = &(data[1]); 488 | uint8_t *value_id_and_data = &(data[2]); 489 | 490 | if ( *channel_id == id_custom_channel ) { 491 | switch ( *command_id ) 492 | { 493 | case id_custom_set_value: 494 | { 495 | buttglow_config_set_value(value_id_and_data); 496 | break; 497 | } 498 | case id_custom_get_value: 499 | { 500 | buttglow_config_get_value(value_id_and_data); 501 | break; 502 | } 503 | case id_custom_save: 504 | { 505 | buttglow_config_save(); 506 | break; 507 | } 508 | default: 509 | { 510 | // Unhandled message. 511 | *command_id = id_unhandled; 512 | break; 513 | } 514 | } 515 | return; 516 | } 517 | 518 | // Return the unhandled state 519 | *command_id = id_unhandled; 520 | 521 | // DO NOT call raw_hid_send(data,length) here, let caller do this 522 | } 523 | ``` 524 | 525 | The following is an example of implementing the set/get command handlers specific to a feature - switch on possible values and set/get the values to/from a global struct which stores the state being used by the feature. Triggering update functions on state change can be optionally added. 526 | 527 | ```c 528 | void buttglow_config_set_value( uint8_t *data ) 529 | { 530 | // data = [ value_id, value_data ] 531 | uint8_t *value_id = &(data[0]); 532 | uint8_t *value_data = &(data[1]); 533 | 534 | switch ( *value_id ) 535 | { 536 | case id_buttglow_brightness: 537 | { 538 | g_buttglow_config.brightness = *value_data; 539 | break; 540 | } 541 | ... 542 | } 543 | } 544 | 545 | void buttglow_config_get_value( uint8_t *data ) 546 | { 547 | // data = [ value_id, value_data ] 548 | uint8_t *value_id = &(data[0]); 549 | uint8_t *value_data = &(data[1]); 550 | 551 | switch ( *value_id ) 552 | { 553 | case id_buttglow_brightness: 554 | { 555 | *value_data = g_buttglow_config.brightness; 556 | break; 557 | } 558 | ... 559 | } 560 | } 561 | 562 | void buttglow_config_save(void) 563 | { 564 | eeprom_update_block( &g_buttglow_config, 565 | ((void*)BUTTGLOW_CONFIG_EEPROM_ADDR), 566 | sizeof(buttglow_config) ); 567 | } 568 | ``` 569 | 570 | ### Saving Values 571 | 572 | The `id_custom_save` command is sent after one or more `id_custom_set_value` commands have been sent, and after a small delay. It is used to allow the firmware to defer writing to EEPROM and respond to set value commands quickly. This also reduces the number of redundant writes to EEPROM, especially when users are changing values quickly in VIA, like when using a color picker. The `channel_id` of the `id_custom_save` command will be the same value as used in the `id_custom_set_value` commands which preceeded it, thus a handler to write all current values to EEPROM for a given feature can be called and bound per channel. 573 | 574 | ### Handling 16-bit Values 575 | 576 | The keycode control will send/receive 16-bit values. Likewise, the range control will send/receive 16-bit values if the range maximum is greater than 255. The order of bytes is `[high byte, low byte]`. 577 | 578 | In the following example, `g_buttglow_config.audacity` is `uint16_t` and the range control is configured to use a range of 0 to 1023. 579 | 580 | ```c 581 | void buttglow_config_set_value( uint8_t *data ) 582 | { 583 | // data = [ value_id, value_data ] 584 | uint8_t *value_id = &(data[0]); 585 | uint8_t *value_data = &(data[1]); 586 | 587 | switch ( *value_id ) 588 | { 589 | case id_buttglow_audacity: 590 | { 591 | g_buttglow_config.audacity = value_data[0] << 8 | value_data[1]; 592 | break; 593 | } 594 | ... 595 | } 596 | } 597 | 598 | void buttglow_config_get_value( uint8_t *data ) 599 | { 600 | // data = [ value_id, value_data ] 601 | uint8_t *value_id = &(data[0]); 602 | uint8_t *value_data = &(data[1]); 603 | 604 | switch ( *value_id ) 605 | { 606 | case id_buttglow_audacity: 607 | { 608 | value_data[0] = g_buttglow_config.audacity >> 8; 609 | value_data[1] = g_buttglow_config.audacity & 0xFF; 610 | break; 611 | } 612 | ... 613 | } 614 | } 615 | ``` 616 | 617 | ### Handling Array Values 618 | 619 | The following is an example of a custom UI control using an array value, the array index is after the `value_id`, thus it is in `value_data[0]` and the actual value starts at `value_data[1]`, whereas for non-array values, the value starts at `value_data[0]`. 620 | 621 | ```c 622 | void buttglow_config_set_value( uint8_t *data ) 623 | { 624 | // data = [ value_id, value_data ] 625 | uint8_t *value_id = &(data[0]); 626 | uint8_t *value_data = &(data[1]); 627 | 628 | switch ( *value_id ) 629 | { 630 | case id_buttglow_color: // == 4 631 | { 632 | uint8_t index = value_data[0]; // == 0,1,2 633 | if ( index >= 0 && index < 3 ) 634 | { 635 | g_buttglow_config.color[index].h = value_data[1]; 636 | g_buttglow_config.color[index].s = value_data[2]; 637 | } 638 | } 639 | ... 640 | } 641 | } 642 | ``` 643 | 644 | See [Array Values](#array-values) 645 | -------------------------------------------------------------------------------- /docs/layouts.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: layouts 3 | title: Layouts 4 | sidebar_label: Layouts 5 | --- 6 | 7 | ## Overview 8 | 9 | VIA requires a definition of both the physical arrangement of keys and the mapping of those keys to the switch matrix. It optionally requires definition of layout options - alternative physical arrangements of keys, such as different bottom rows, split right shift, etc. 10 | 11 | Everything inside the `keymap` property is KLE JSON data, which can be edited using Keyboard Layout Editor. This contains the switch matrix coordinates for each key, and optionally information about layout options. 12 | 13 | The `labels` property is used to name the layout options. 14 | 15 | Keyboard Layout Editor will not load the `.json` that VIA uses, only the KLE JSON within the `keymap` property. The user can copy the value of the `keymap` property into the "Raw data" tab of Keyboard Layout Editor, i.e. everything inside the outer `[` and `]`. Unfortunately, copying and pasting the other way does not work. (KLE's "Raw data" tab contains JSON with missing " around property names.) In KLE, save as a JSON file and then copy the contents of the JSON file into the `keymap` property of the `.json` 16 | 17 | ## KLE JSON Rules 18 | 19 | The KLE JSON should follow these rules: 20 | 21 | * Horizontal and vertical gaps are allowed (for separation of rows, columns, blockers, etc.) 22 | * Do not use stepped keys. 23 | * Rotated keys are allowed but layout options for rotated keys is not supported. 24 | * Use key color `#cccccc` for alphas, `#aaaaaa` for modifier keys and `#777777` for accents (i.e. Esc, Enter, arrows, etc). 25 | * Use legend color `#000000` for all legends 26 | 27 | Note: The key colors used in the KLE will be used by VIA to map alphas/modifiers/accents to a color theme, thus all keys which are the "modifier" color in a standard keycap set should be set to `#aaaaaa`. Some color themes may have the same color for alphas and modifiers. 28 | 29 | ## Switch Matrix Co-ordinates 30 | 31 | The mapping from physical layout to switch matrix layout is defined by the top-left legend of the key, using `row,col` format. 32 | 33 | Thus, the mapping that is usually done by a `LAYOUT_*()` macro in QMK is instead stored in the key objects in the KLE JSON. 34 | 35 | Most `LAYOUT_*()` macros in QMK use some `row,col` naming convention so translation into the KLE JSON should be straight-forward. 36 | 37 | KLE Example: 38 | 39 | ![Switch Matrix Co-ordinates](/img/switch_matrix_coordinates.png) 40 | 41 | QMK Layout Macro Example: 42 | 43 | ``` 44 | #define LAYOUT_60_all( \ 45 | K00, K01, K02, K03, K04, ... 46 | K10, K11, K12, K13, K14, ... 47 | K20, K21, K22, K23, K24, ... 48 | ... 49 | 50 | ``` 51 | 52 | ## Rotary Encoders 53 | 54 | You can setup your VIA layout to display rotary encorders right in the UI. To do this you need to a few things setup properly in QMK. 55 | 56 | Required setup in QMK: 57 | * Enable encoder maps as per QMK 58 | * Add ENCODER_ENABLE = yes to rules.mk 59 | * Add ENCODER_MAP_ENABLE = yes to keymaps/via/rules.mk 60 | * Add an encoder map to keymaps/via/keymap.c 61 | * The encoder map should be defined for the same number of layers as configured for VIA (default 4) 62 | * Add the encoder to the VIA keyboard definition 63 | 64 | ### Encoders without push switch (Just twist, no push) 65 | ![Just Encoder](/img/just-encoder.png) 66 | 67 | Add a "key" to the KLE JSON with e0, e1, etc. as the center label. The number will match the encoder ID used in the encoder map. 68 | 69 | ### Rotary encoder with a push switch 70 | ![Encoder with Switch](/img/encoder-with-push.png) 71 | 72 | Define the switch matrix co-ordinates like other switches and add e0, e1, etc. to the center label of the switch 73 | 74 | ### Optional Rotary Encoder (combined switch/rotary encoder footprint) 75 | ![Optional Encoder](/img/optional-encoder.png) 76 | 77 | Use VIA Layout Options like other switches. VIA can render either a knob or switch or empty space. 78 | 79 | ### Here's what it looks like 80 | ![Result](/img/result.png) 81 | 82 | ## Layout Options 83 | 84 | If a keyboard supports multiple physical layout of keys, then the KLE JSON definition will contain the "default" layout as well as all the layout options. 85 | 86 | The layout option and layout option choices are defined by the bottom-right legend of the key, using `option,choice` format. 87 | 88 | A "layout option" is defined as an area of the keyboard which can change into more than one arrangement. 89 | 90 | A "layout option choice" is one arrangement of a layout option. 91 | 92 | Each layout option is defined by a number, the first number in the bottom-right legend. The second number defines which "choice" it belongs to, within that layout option. 93 | 94 | The "default layout" (what is presented in VIA by default) is defined as all keys without the `option,choice` in the bottom-right label, and all keys which have `option,0` in the bottom-right label (i.e. the "default" choice for all the layout options). VIA will use the bounding box of all the key in the "default layout" as the extent of the "keyboard", so layout option choices can be positioned above, below, left or right of this bounding box. 95 | 96 | Layout option choices must all have the same coverage, i.e. they overlap exactly in shape, but can vary in keycap sizes and arrangement. Layout option choices must be aligned either vertically or horizontally with the "default" layout option. They must all contain the switch matrix co-ordinates in the top-left label. Note that setting the switch matrix co-ordinates may require testing real hardware. For example, the non-split (center) switch of a split shift or backspace may be connected in parallel to the switch to the left or right. One can put different keycodes in a split key scenarion and test which keycode event is sent when the center switch is pressed or shorted. 97 | 98 | Layout options should be at the finest granularity possible. For example, ANSI/ISO should be defined as three separate layout options, ANSI/ISO Enter, Split Left Shift, Split Right Shift. 99 | 100 | Layout options can use "decal" keys to represent optional blockers, i.e. HHKB or WKL. 101 | 102 | VIA will present the layout options to the user, and store the state of the choices in the device, so it persists between configuration. 103 | 104 | Example: 105 | 106 | ![Split Backspace](/img/split_backspace.png) 107 | 108 | This example defines the layout option "Split Backspace". 109 | 110 | It shows: 111 | 112 | * the 2U backspace legend is `0,0` meaning it belongs to layout option #0, layout option choice #0 113 | * the 2U backspace is the default (because it is `-,0`) 114 | * the 2U backspace is positioned as it should be relative to other keys that are constant, *because it is the default*. 115 | * the split backspace keys have legends `0,1` meaning they belong to layout option #0, layout option choice #1 116 | * the split backspace keys have the same bounding box (i.e. cover the same area) as the 2U backspace 117 | * the split backspace keys bounding box is aligned vertically with the 2U backspace 118 | * all keys have switch matrix coordinates in the top-left legends 119 | 120 | Let's consider another example, the WT60-D layout: 121 | 122 | ![WT60-D Layout Options](/img/wt60_d_layout_options.png) 123 | 124 | This shows split backspace as the first of many layout options, and some other possibilities, such as: 125 | * aligning layout option choices to the left, right and below the "default layout" 126 | * layout options with more than two choices 127 | * layout options incorporating "blockers" (keys with `Decal` checked) 128 | 129 | ## Layout Option Labels 130 | 131 | Layout options are assigned labels from the `labels` property. 132 | 133 | Example: 134 | 135 | ```json 136 | { 137 | ... 138 | "layouts": { 139 | ... 140 | "labels": [ 141 | "Split Backspace", 142 | "ISO Enter", 143 | "Split Left Shift", 144 | "Split Right Shift", 145 | ["Bottom Row", "ANSI", "7U", "HHKB", "WKL"] 146 | ], 147 | ... 148 | } 149 | ... 150 | } 151 | ``` 152 | 153 | The `labels` property is an optional array of `string` or `string[]` and defines the labels for the layout controls. 154 | 155 | The order of the labels is important as the implicit index is used to map to the group number e.g. `Split Backspace` corresponds to layout option #0, `ISO` corresponds to layout option #1, etc. 156 | 157 | If an item in the `labels` array is a `string`, it is presented as a toggle button, the off state maps to layout option choice #0 (the default), the on state maps to layout option choice #1. 158 | 159 | If an item in the `labels` array is a `string[]`, it maps to a select control with the first item in the array being used as the label for the control and the following items being used as labels of layout option choices #0, #1, #2, etc. In the example above, the `Bottom Row` is the label, `ANSI` maps to layout option choice #0, `7U` maps to layout option choice #1, etc. 160 | -------------------------------------------------------------------------------- /docs/mdx.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: mdx 3 | title: Powered by MDX 4 | --- 5 | 6 | You can write JSX and use React components within your Markdown thanks to [MDX](https://mdxjs.com/). 7 | 8 | export const Highlight = ({children, color}) => ( {children} ); 14 | 15 | Docusaurus green and Facebook blue are my favorite colors. 16 | 17 | I can write **Markdown** alongside my _JSX_! 18 | -------------------------------------------------------------------------------- /docs/specification.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: specification 3 | title: Specification 4 | sidebar_label: Specification 5 | --- 6 | 7 | # Specification 8 | 9 | In order for VIA to configure a keyboard, it requires a definition of the keyboard - the physical layout of keys, any layout options, and other configurable elements like rotary encoders (knobs), lighting, etc. 10 | 11 | These things are defined in a "keyboard definition" - a file in JSON format that is stored in the VIA Github repository and hosted by the VIA website for VIA to download and use when that keyboard is connected. 12 | 13 | People adding VIA support to their keyboards can add their keyboard definition to the Github repository by creating a pull request here: https://github.com/the-via/keyboards 14 | 15 | Here is a great video by Joe Scotto giving an overview of the process: 16 | 17 | 18 | 19 | ## Keyboard Definition 20 | 21 | Keyboard definitions are in JSON format. Valid properties are described below. 22 | 23 | ## Name 24 | 25 | ```json 26 | "name": "Macropad", 27 | ``` 28 | 29 | The `name` property denotes the name of the keyboard being defined. 30 | 31 | ## Vendor & Product ID 32 | 33 | ```json 34 | "vendorId": "0x5241", 35 | "productId": "0x1234", 36 | ``` 37 | 38 | The `productId` property corresponds to the usb product id. This combined with the `vendorId` is what is used by VIA to identify the keyboard when it is plugged in. 39 | 40 | ## Matrix 41 | 42 | ```json 43 | "matrix": {"rows": 1, "cols": 6}, 44 | ``` 45 | 46 | The `matrix` property defines how many rows and columns the PCB's switch matrix uses. This must match the `MATRIX_ROWS` and `MATRIX_COLS` symbols in the QMK firmware. 47 | 48 | ## Layouts 49 | 50 | ```json 51 | "layouts": { 52 | ... 53 | "keymap": [ 54 | [{"c": "#505557", "t": "#d9d7d7", "a": 7}, "0,0", "0,1", "0,2"], 55 | ["0,3", "0,4", "0,5"] 56 | ] 57 | ... 58 | } 59 | ``` 60 | 61 | The `keymap` property corresponds to the KLE json exported by [KLE](http://keyboard-layout-editor.com) and has the switch row, col defined in the top-left legends and optionally the group number, option number defined in the bottom-right legends. The KLE can support up to 3 different colored keys which is used to identify the alpha, modifier and accent keys which VIA will automatically apply a theme to. 62 | 63 | ```json 64 | "layouts": { 65 | ... 66 | "labels": [ 67 | "Split Backspace", 68 | "ISO Enter", 69 | "Split Left Shift", 70 | "Split Right Shift", 71 | ["Bottom Row", "ANSI", "7U", "HHKB", "WKL"] 72 | ], 73 | ... 74 | } 75 | ``` 76 | 77 | The `labels` property is an optional array of `string` or `string[]` and defines the labels for the layout controls. 78 | 79 | The order of the labels is important as the implicit index is used to map to the group number e.g. `Split Backspace` corresponds to layout option #0, `ISO` corresponds to layout option #1, etc. 80 | 81 | If an item in the `labels` array is a `string`, it is presented as a toggle button, the off state maps to layout option choice #0 (the default), the on state maps to layout option choice #1. 82 | 83 | If an item in the `labels` array is a `string[]`, it maps to a select control with the first item in the array being used as the label for the control and the following items being used as labels of layout option choices #0, #1, #2, etc. In the example above, the `Bottom Row` is the label, `ANSI` maps to layout option choice #0, `7U` maps to layout option choice #1, etc. 84 | 85 | Documentation explaining how layout options work is [here](layouts). 86 | 87 | ## Menus 88 | 89 | The `menus` element is used to define more menus in VIA. It can contain **one or more** of the following built-in UI definitions: 90 | 91 | - `"qmk_backlight"` 92 | - `"qmk_rgblight"` 93 | - `"qmk_backlight_rgblight"` 94 | - `"qmk_rgb_matrix"` 95 | - `"qmk_audio"` 96 | 97 | **and/or** a definition of custom UI, i.e. explicitly defining all the UI controls required. 98 | 99 | For example, a definition enabling the built-in UI for QMK RGB Matrix could be done like so: 100 | 101 | ```json 102 | "menus": ["qmk_rgb_matrix" ] 103 | ``` 104 | 105 | **or alternatively** defined explicitly using custom UI definitions, like so: 106 | 107 | ```json 108 | ... 109 | "menus": [ 110 | { 111 | "label": "Lighting", 112 | "content": [ 113 | { 114 | "label": "Backlight", 115 | "content": [ 116 | { 117 | "label": "Brightness", 118 | "type": "range", 119 | "options": [0, 255], 120 | "content": ["id_qmk_rgb_matrix_brightness", 3, 1] 121 | }, 122 | ... 123 | ] 124 | } 125 | ] 126 | } 127 | ] 128 | ``` 129 | 130 | The complete documentation for custom UI is [here](custom_ui). 131 | 132 | If the firmware is using the stock implementation of a feature, i.e. it is enabled in the `info.json` or the `rules.mk` and not customized, then using one of the built-in UI definitions is all that is needed. 133 | 134 | The built-in UI definitions are defined the same way as custom UI definitions (i.e. JSON format) and for reference are located here: https://github.com/the-via/keyboards/tree/master/common-menus. They can be used as examples to create custom UI definitions. 135 | 136 | ## Keycodes 137 | 138 | If the definition is for a keyboard that uses QMK lighting, you can optionally enable the lighting keycodes. 139 | 140 | ```json 141 | "keycodes": ["qmk_lighting"], 142 | "menus": ["qmk_rgblight"], 143 | ``` 144 | -------------------------------------------------------------------------------- /docs/supported_keyboards.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | id: supported_keyboards 3 | title: Supported Keyboards 4 | sidebar_label: Supported Keyboards 5 | --- 6 | 7 | | Compatible as of 3/3/2025 | 8 | | ----------------------------------- | 9 | | _33 Rev1 | 10 | | _33 Rev2 | 11 | | [1 x 4] + 1 Macropad | 12 | | 0-Sixty by ven0mtr0n | 13 | | 0xCB 1337 | 14 | | 0xCB Static | 15 | | 10bleoledhub | 16 | | 1up Slider8 | 17 | | 1up_pi60_rgb_v2 | 18 | | 1up60hse | 19 | | 1up60hte | 20 | | 1up60rgb | 21 | | 1upocarina | 22 | | 3dortho14u | 23 | | 3dp660 | 24 | | 61Key by 0xC7 | 25 | | 65%_Y&R | 26 | | 67mk_E | 27 | | 6key | 28 | | 75 Pixels | 29 | | 7c8 Framework | 30 | | 7sKB | 31 | | 7splus | 32 | | 7V Hotswap | 33 | | aanzee | 34 | | Absinthe | 35 | | Absolute Designs 65 | 36 | | Ace of Spades TKL | 37 | | Acheron Athena | 38 | | Acheron Athena rev. Beta | 39 | | Acheron Austin | 40 | | Acheron Project Elongate | 41 | | Acheron Shark | 42 | | Acheron Themis 87H rev. Alpha | 43 | | Acheron Themis 87HTSC rev. Alpha | 44 | | Acheron Themis 88H-T-SC rev. Alpha | 45 | | AcheronProject Apollo87H Rev. Delta | 46 | | AcheronProject Apollo87H-T-SC Rev. Alpha | 47 | | AcheronProject Apollo88H-T-SC Rev. Alpha | 48 | | Adafruit MacroPad RP2040 | 49 | | Adam64 | 50 | | AddOn | 51 | | Adelais En Ciel Rev.3 | 52 | | Adelais en Ciel' | 53 | | Adelais en Ciel' Rev.2 | 54 | | Adelais Mechlovin' | 55 | | Adelais Rev. 4 | 56 | | Adelais Rev.3 | 57 | | Adelheid | 58 | | Adelie | 59 | | AEboards AEGIS | 60 | | AEBoards CONSTELLATION | 61 | | AEBoards Constellation Rev3 | 62 | | AEBoards EXT65 Rev 1 | 63 | | AEBoards EXT65 Rev 2 | 64 | | AEBoards EXT65 Rev 3 | 65 | | AEK II | 66 | | AEKISO60 Rev A | 67 | | AEKISO60 Rev B | 68 | | AELITH | 69 | | Aella | 70 | | aeroboard | 71 | | Ahgase | 72 | | akb/ogr | 73 | | akb/ogrn | 74 | | akb/vero | 75 | | AkemiPad | 76 | | AKIRA | 77 | | Akko 5108 | 78 | | Akko ACR87 | 79 | | Akko Top40 | 80 | | AL1 | 81 | | Alas | 82 | | Albacore | 83 | | aleth42 | 84 | | Alexa | 85 | | Alexa Solder | 86 | | ALF X1.1 | 87 | | AliceKK | 88 | | Alisaie | 89 | | Alish40 | 90 | | alix40 Rev.1 | 91 | | Allaro | 92 | | Allison | 93 | | Allison Numpad | 94 | | Alpaca Keyboards HotDox | 95 | | Alpaca WFEclipse | 96 | | Alpine65 | 97 | | Altair | 98 | | Altair-X | 99 | | Alveus | 100 | | Amber80 Solder | 101 | | AN-C | 102 | | Andromeda | 103 | | ANGLE65 | 104 | | AngleR2 | 105 | | AnomalyKB A65I | 106 | | Anvil Native | 107 | | Anvil Native | 108 | | Aozora | 109 | | Aperture | 110 | | arc60 | 111 | | arc60h | 112 | | Argo Works Ishi 80 Mk0 | 113 | | Argyle | 114 | | ARISU | 115 | | Arya | 116 | | Ashwing66 | 117 | | Aster Ergo | 118 | | Astro65 | 119 | | Atelier_Haven Haven60 | 120 | | Atelier_Haven Haven65 | 121 | | Atelier_Haven Haven80_Hotswap | 122 | | Atelier_Haven Haven80_Solder | 123 | | Atlantis PS17 | 124 | | Atlas | 125 | | atlas_65 | 126 | | Atreus | 127 | | Atreus62 | 128 | | Atxkb 1894 | 129 | | Aumz Work Hotswap | 130 | | Aumz Work Soldered | 131 | | Aurora 65 | 132 | | AVA | 133 | | Avalon | 134 | | b.face | 135 | | Bachoo Crin | 136 | | BAGUETTE66_RGB | 137 | | BAGUETTE66_SOLDERED | 138 | | Bahrnob65 | 139 | | Baion 808 | 140 | | Bakeneko 60 | 141 | | Bakeneko 65 V2 | 142 | | Bakeneko 65 V3 | 143 | | Bakeneko60 ISO HS | 144 | | Bakeneko65 ISO HS | 145 | | Balance | 146 | | BAMFK-1 | 147 | | BAMFK-1 | 148 | | Bananasplit | 149 | | Bantam-44 R2 PCB | 150 | | Barleycorn | 151 | | Barleycorn SMD | 152 | | barracuda | 153 | | Basketweave | 154 | | Bastion60 | 155 | | Bastion65 | 156 | | Bastion75 | 157 | | BastionTKL | 158 | | bat43 | 159 | | BDN9 Rev. 1 | 160 | | BDN9 Rev. 2 | 161 | | Bear 65 Ergo | 162 | | Bear65 | 163 | | Beatervan | 164 | | Bebol | 165 | | Beegboy | 166 | | Beiwagon | 167 | | Bella | 168 | | BELLA_RGB | 169 | | BELLA_RGB_ISO | 170 | | Bemeier BMEK | 171 | | Best | 172 | | bevi | 173 | | BIG DILL EXTENDED - Lefty | 174 | | BIG DILL EXTENDED - Rev2 | 175 | | BIG DILL EXTENDED - Righty | 176 | | Big Smooth Knob | 177 | | Big Switch | 178 | | Big Switch Seat | 179 | | Binepad BNK8 | 180 | | Binepad PIXIE | 181 | | BIOI F60 | 182 | | BIOI G60 | 183 | | BIOI G60 BLE | 184 | | BIOI MORGAN65 BLE | 185 | | BIOI S65 | 186 | | BKS65 | 187 | | BKS65 Solder | 188 | | Blackplum | 189 | | BLASTER75 | 190 | | Blocked65 | 191 | | Bloop65 | 192 | | blue_team_pad | 193 | | Blueberry | 194 | | BM60V2 | 195 | | BM60v2_EC | 196 | | BM60v2_poker | 197 | | BM65HSRGB ISO | 198 | | BN003 | 199 | | BN006 | 200 | | BN009 | 201 | | BNK9 | 202 | | Boardrun Bizarre | 203 | | Boardrun Classic | 204 | | Boardsource 3x4 | 205 | | Boardsource 4x12 | 206 | | Boardsource 5x12 | 207 | | Boardsource Lulu | 208 | | Boardwalk | 209 | | bobPad | 210 | | Bolsa65 | 211 | | bonce75_hotswap | 212 | | bonce75_soldered | 213 | | Bootleg Rev A | 214 | | bop | 215 | | Borsdorf | 216 | | BOUNCE PAD | 217 | | Bourgeau | 218 | | BOX75 | 219 | | bradpad | 220 | | Breeze | 221 | | Brick65 | 222 | | Brutal v2 1800 | 223 | | Brutal v2 60 | 224 | | Brutal V2 65 | 225 | | bt66tech60 | 226 | | Bubble Studio Bubble75 | 227 | | BumbleBee | 228 | | CA66 | 229 | | Caerdroia | 230 | | Calice | 231 | | CANARY60RGB V1 | 232 | | Candybar lefty | 233 | | Candybar righty | 234 | | Candybar_Ortho | 235 | | CannonKeys DB60 | 236 | | CannonKeys DB60 Hotswap | 237 | | CannonKeys DB60v2 | 238 | | CANOE | 239 | | Cans12erV2 | 240 | | Capsule65 | 241 | | CapsUnlocked CU65 | 242 | | CapsUnlocked CU80 v2 ANSI | 243 | | CapsUnlocked CU80 v2 ANSI RGB | 244 | | CapsUnlocked CU80 v2 ISO | 245 | | CapsUnlocked CU80 v2 ISO RGB | 246 | | Carbo65 | 247 | | Carpolly | 248 | | Cascade | 249 | | Cassette8 | 250 | | Cassini | 251 | | Caticorn Hotswap | 252 | | Caticorn Solder | 253 | | Cepstrum Rev. 1 | 254 | | Chalice | 255 | | Chaos65 | 256 | | Chapter 1 | 257 | | Charon | 258 | | Charybdis | 259 | | Charybdis Mini | 260 | | Charybdis Nano | 261 | | Cherish 75 | 262 | | CherryB Works CB65 | 263 | | CherryB.Studio CB1800 | 264 | | CherryB.Studio CB87 | 265 | | CherryB.Studio CB87RGB | 266 | | CherryB.Studio CB87v2 | 267 | | Chevron | 268 | | Chili | 269 | | Chimera65 | 270 | | Chimera65 HS | 271 | | Chiri CE Rev. 1 | 272 | | chlx lfn.merro60 | 273 | | chlx merro60 | 274 | | chlx ppr.merro60 | 275 | | chlx str.merro60 | 276 | | Choc Taro | 277 | | Chocolate Bar | 278 | | Choconum Rev. 1 | 279 | | Chocopad Rev. 1 | 280 | | Chocopad Rev. 2 | 281 | | CHOSFOX CF81 | 282 | | Chroma | 283 | | Ciel | 284 | | Ciel65 | 285 | | Cipulot 60XT | 286 | | CK Meetup Pad 2023 | 287 | | CK60 | 288 | | CK65 | 289 | | Claw44 | 290 | | Cloudline | 291 | | Clueboard 66% rev1 | 292 | | Clueboard 66% rev2 | 293 | | Clueboard 66% rev3 | 294 | | Clueboard 66% rev4 | 295 | | Clunker | 296 | | CMM.Studio_Fuji65 | 297 | | CMM.Studio_Saka68 | 298 | | CMM.Studio_Saka68 | 299 | | Coarse60 | 300 | | Coban Pad 3A | 301 | | Coban Pad 9A | 302 | | Compensator | 303 | | Compound | 304 | | Conde60 | 305 | | Conone65 | 306 | | Constellation EC | 307 | | Contra | 308 | | Controller Works city42 | 309 | | Controller Works mini36 | 310 | | Controller Works mini42 | 311 | | Convolution Rev. 1 | 312 | | cor | 313 | | Cor TKL | 314 | | Cordillera | 315 | | Cornelius | 316 | | Cosmo65 | 317 | | Cospad | 318 | | CowFish | 319 | | craftwalk | 320 | | Creator Micro | 321 | | Creek 70 | 322 | | Crin | 323 | | Crkbd | 324 | | croxsplit44 | 325 | | Crypt Macro | 326 | | CT87 | 327 | | ctrl-M | 328 | | Cupar19 Giant Macro Pad | 329 | | Curiosity Cheshire | 330 | | customMK cmk11 | 331 | | customMK ErgoStrafer | 332 | | customMK ErgoStrafer RGB | 333 | | customMK EVO70 | 334 | | customMK EVO70 R2 | 335 | | customMK Genesis | 336 | | customMK Genesis Rev2 | 337 | | CX60 | 338 | | CyberGear Macro25 | 339 | | Cyberstar | 340 | | cycle8 | 341 | | Cypher | 342 | | D45V2 | 343 | | Dactyl Lightcycle | 344 | | Dactyl Manuform (4x6) | 345 | | Dactyl Manuform (5x6-5) | 346 | | Dactyl Manuform (5x7) | 347 | | Dactyl Maximus | 348 | | Daily60 | 349 | | Daisy 40 | 350 | | Daji Seis Cinco | 351 | | Damapad | 352 | | Dango40 | 353 | | DAWN60 | 354 | | De60fs | 355 | | DE80 | 356 | | decadepad | 357 | | Deck-8 | 358 | | Deck-8 RGB | 359 | | Degenpad | 360 | | Delilah | 361 | | Delphine rev.1 | 362 | | Delphine RGB rev.1 | 363 | | Demiurge | 364 | | desire65 | 365 | | DeskDaily Alter | 366 | | DevastatingTKL | 367 | | Devil68 Pro | 368 | | Dharma | 369 | | Diablo | 370 | | DigiCarp65 | 371 | | DigiCarpice | 372 | | Dilemma Max | 373 | | Dilemma v2 | 374 | | DimplePlus | 375 | | Disarray Ortholinear | 376 | | Disarray Staggered | 377 | | Discipad | 378 | | Discipline | 379 | | DIVINE | 380 | | Djinn | 381 | | DK Saver Redux | 382 | | Dm9Records Tartan | 383 | | dnworks 997.3 | 384 | | dnworks FRLTKL | 385 | | dnworks Numpad rev1 | 386 | | dnworks SBL | 387 | | DOIO | 388 | | DOIO KB04-01 | 389 | | DOIO KB09-01 | 390 | | DOIO KB12-01 | 391 | | DOIO KB19-01 | 392 | | DOIO KB38-01 | 393 | | DOIO KB3x | 394 | | doksin | 395 | | Dolice EC | 396 | | DonutCables ScrabblePad | 397 | | Doro67 Multi | 398 | | Doro67 Regular | 399 | | Doro67 RGB | 400 | | Dozen0 | 401 | | dp3000 | 402 | | dp3000 rev2 | 403 | | DP60 | 404 | | Drink Me | 405 | | Drop ALT | 406 | | Drop ALT V2 | 407 | | Drop CSTM65 | 408 | | Drop CSTM80 | 409 | | Drop CTRL | 410 | | Drop CTRL V2 | 411 | | Drop SHIFT V2 | 412 | | DSP40 Rev. 1 | 413 | | Duck Eagle Viper V2 | 414 | | duckboard R2 | 415 | | duckyPad | 416 | | Dude09 | 417 | | dumbpad | 418 | | DUO_S | 419 | | DURGOD Galaxy | 420 | | DURGOD Hades | 421 | | DURGOD Hades | 422 | | DURGOD Taurus K310 | 423 | | DURGOD Taurus K320 | 424 | | DURGOD Venus | 425 | | DYMIUM65 | 426 | | dynamis | 427 | | dyz.tkl | 428 | | dyz40 | 429 | | dyz60 | 430 | | dyz60-hs | 431 | | DZ60 | 432 | | DZ60RGB ANSI V1 | 433 | | DZ60RGB ANSI V2 | 434 | | DZ60RGB V1 | 435 | | DZ60RGB V2 | 436 | | DZ60RGB WKL V1 | 437 | | DZ60RGB WKL V2 | 438 | | DZ60V2 | 439 | | DZ64RGB V1 | 440 | | DZ65RGB V1 | 441 | | DZ65RGB V2 | 442 | | DZ65RGB V3 | 443 | | DZ96 | 444 | | E6-V2 LE BMC rev 2.32 | 445 | | E6-V2 OE BMC rev 2.31 | 446 | | E6.5 | 447 | | E7-V1 | 448 | | E8.5 Hotswap | 449 | | E8.5 Soldered | 450 | | E8ghty | 451 | | E8ghtyNeo | 452 | | Eagle Viper Rep, Rev A | 453 | | Eagle Viper Rep, Rev B | 454 | | eau75_Y&R | 455 | | ebastler E80-1800 | 456 | | EC 23U | 457 | | EC 60 | 458 | | EC 60X | 459 | | EC 65X | 460 | | EC 660C | 461 | | EC 980C | 462 | | EC Alveus 1.0.0 | 463 | | EC Alveus 1.2.0 | 464 | | EC Menhir | 465 | | EC Pro 2 | 466 | | EC Pro X ANSI/ISO | 467 | | EC Pro X JIS | 468 | | EC Theca | 469 | | EC TKL | 470 | | EC TKL X | 471 | | EC Type-B | 472 | | EC1-AT | 473 | | ecila | 474 | | Eclipse60 | 475 | | Edc40 | 476 | | Eden | 477 | | EE-AT | 478 | | Efreet | 479 | | egg58 | 480 | | Element G67 Hotswap | 481 | | Ellipse | 482 | | Ellipse HS | 483 | | Ellora65 | 484 | | Emery65 | 485 | | Emu | 486 | | Emu Hotswap | 487 | | Enclave-1 | 488 | | endless80 | 489 | | Eniigma Keyboards ek60 | 490 | | Eniigma Keyboards ek65 | 491 | | Eniigma Keyboards ek87 | 492 | | enter67 | 493 | | ENTER80 | 494 | | Epoch 80 | 495 | | Equator | 496 | | EQUATOR | 497 | | Equinox | 498 | | Equinox XL | 499 | | ERA65 | 500 | | Erdnuss 65 | 501 | | ErgoArrows | 502 | | ErgoDone | 503 | | ErgoDox EZ | 504 | | ErgoTravel | 505 | | Eros | 506 | | Eternal Keypad | 507 | | EVE Meteor | 508 | | Event Horizon | 509 | | Evolv75 CE | 510 | | Evyd13 Eon40 | 511 | | Evyd13 Eon65 | 512 | | Evyd13 Eon75 | 513 | | Evyd13 Eon87 | 514 | | Evyd13 Eon95 | 515 | | Evyd13 GH80-1800 | 516 | | Evyd13 GH80-3700 | 517 | | Evyd13 Gud70 | 518 | | Evyd13 nt210 | 519 | | Evyd13 nt650 | 520 | | Evyd13 nt660 | 521 | | Evyd13 nt750 | 522 | | Evyd13 nt980 | 523 | | Evyd13 Plain60 | 524 | | Evyd13 Quackfire | 525 | | Evyd13 ta-65 | 526 | | Evyd13 Wasdat | 527 | | Evyd13 Wasdat Code | 528 | | Evyd13 Wonderland | 529 | | Exent 65% | 530 | | F.Me Macropad | 531 | | FancyAlice66 | 532 | | FAve 65H | 533 | | FAve 84H | 534 | | FAve 87H | 535 | | FAve65S | 536 | | FC660C | 537 | | FC980C | 538 | | Feels65 | 539 | | Ferris Sweep | 540 | | fine!40 | 541 | | FJLabs TF60 ANSI | 542 | | FJLabs TF60 RGB V2 | 543 | | FJLabs TF65 RGB V2 | 544 | | Flame 60 | 545 | | Flowerpad | 546 | | FLX Virgo | 547 | | FM2U 1 Key Macropad | 548 | | FnRow v1 | 549 | | FoldKB Rev. 1 | 550 | | FoldKB Rev. 1a | 551 | | Forever65 | 552 | | Foundation | 553 | | Foundation Gamma | 554 | | FreebirdTKL | 555 | | Friedrich | 556 | | FRL84 | 557 | | Frog Pad | 558 | | Frooastboard Nano | 559 | | Frooastboard Walnut | 560 | | Frusta Fundamental | 561 | | Fuyu | 562 | | Fuyu Hotswap | 563 | | G_IDB60 | 564 | | G-Boy | 565 | | G60R-H | 566 | | G60R-S | 567 | | GA15.0 | 568 | | Galatea Rev1 | 569 | | Galatea Rev2 | 570 | | Galatea Rev3 | 571 | | Gamdias Hermes 7 Colors | 572 | | Gas75 | 573 | | Geekboards Macropad v2 | 574 | | Geistmaschine Geist | 575 | | Geistmaschine Macropod | 576 | | Geminate60 | 577 | | Gen One G1_65 | 578 | | Gentleman 65 | 579 | | Gentoo | 580 | | Gentoo HS | 581 | | GeonWorks Frog Mini FM-H | 582 | | GeonWorks Frog Mini FM-S | 583 | | gg86 | 584 | | GH60 Rev C | 585 | | GH60 Satan | 586 | | Ghoul | 587 | | GHS.JEM | 588 | | GHS.JEM | 589 | | GHS.RAR | 590 | | GHS.XLS | 591 | | Gin V2 | 592 | | Gingham | 593 | | ginkgo65 | 594 | | ginkgo65hot | 595 | | Gizmo Engineering GK6 | 596 | | GKB-M16 | 597 | | Glacier | 598 | | glacier80 | 599 | | Glitch | 600 | | GMMK Numpad | 601 | | GMMK Pro | 602 | | GMMK V2 65 ANSI | 603 | | GMMK V2 65 ISO | 604 | | GMMK V2 96 ANSI | 605 | | GMMK V2 96 ISO | 606 | | GodSpeed75 | 607 | | gok TypeK | 608 | | GoN NERD TKL | 609 | | GoN NerD60 | 610 | | GPAD8-2R | 611 | | GrayStudio Aero75 Hotswap | 612 | | Graystudio COD67 | 613 | | Graystudio HB85 | 614 | | Graystudio Space65 | 615 | | GrayStudio Space65 R3 | 616 | | Graystudio Think6.5 | 617 | | Graystudio Think6.5 Hotswap | 618 | | Graystudio Think6.5 V3 | 619 | | GreatPad | 620 | | GREATSWORD80 | 621 | | GSKT-00 | 622 | | h08 | 623 | | h10 | 624 | | h101 | 625 | | H50 | 626 | | h60 | 627 | | h65 | 628 | | h65_hotswap | 629 | | h660s | 630 | | h75 - Singa V3 | 631 | | h87_g2 | 632 | | h87a | 633 | | h88 | 634 | | had60 | 635 | | Halfkey | 636 | | han60 | 637 | | Hand 88 | 638 | | HAND Engineering Fidelity | 639 | | handwire | 640 | | Handwired K552 Kumara | 641 | | Hannah60 RGB | 642 | | Hannah60 RGB V2 | 643 | | Hannah65 | 644 | | Hannah65-Mechlovin9 | 645 | | Hannah910 Rev.1 | 646 | | Hannah910 Rev.2 | 647 | | Hannah910 Rev.3 | 648 | | Hasu Alps64 | 649 | | hbcp | 650 | | Helios | 651 | | heliotrope | 652 | | Helix rev3 4rows | 653 | | Helix rev3 5rows | 654 | | Helpo | 655 | | Hercules80_Y&R | 656 | | Herringbone | 657 | | Herringbone Pro | 658 | | Hex ARC | 659 | | Hex.4B | 660 | | Hex.6C | 661 | | HHKB | 662 | | HHKB JP | 663 | | HHKB Lite 2 | 664 | | Hoodrow-G | 665 | | hotdox76-v2 | 666 | | hotDuck | 667 | | hp69 | 668 | | HS60 ANSI | 669 | | HS60 HHKB | 670 | | HS60 ISO | 671 | | Hub16 | 672 | | Hub20 | 673 | | hubble | 674 | | I/O Keyboards Aves 60 | 675 | | I/O Keyboards Aves65 | 676 | | ianklug grooveboard | 677 | | IBE60 Rev A | 678 | | ibis | 679 | | IBIS 80 | 680 | | IBM 122M | 681 | | idb 60 | 682 | | IDOBAO ID42 | 683 | | IDOBAO ID61 | 684 | | IDOBAO ID63 | 685 | | IDOBAO ID67 | 686 | | IDOBAO ID67 | 687 | | IDOBAO ID75 | 688 | | IDOBAO ID80 | 689 | | IDOBAO ID80 ISO | 690 | | IDOBAO ID80v3 | 691 | | IDOBAO ID87 | 692 | | IDOBAO ID87v2 | 693 | | IDOBAO ID96 | 694 | | IDOBAO Montex RGB | 695 | | IDOBAO Montex V2 | 696 | | IDOBAO Montex27 | 697 | | Idobao x YMDK ID75 | 698 | | IF875 Rev. 1 | 699 | | Igloo | 700 | | IK75 | 701 | | ikki68 | 702 | | ikki68 AURORA | 703 | | imi60 | 704 | | Infinity 87 | 705 | | Infinity 87 | 706 | | Infinity 87 Rev.2 | 707 | | Infinity 88 | 708 | | Infinity CE | 709 | | Instant60 | 710 | | Instant65 | 711 | | Irene | 712 | | Iris CE Rev. 1 | 713 | | Iris LM-G Rev. 1 | 714 | | Iris LM-K Rev. 1 | 715 | | Iris Rev. 2 | 716 | | Iris Rev. 3 | 717 | | Iris Rev. 4 | 718 | | Iris Rev. 5 | 719 | | Iris Rev. 5a | 720 | | Iris Rev. 6 | 721 | | Iris Rev. 6a | 722 | | Iris Rev. 6b | 723 | | Iris Rev. 7 | 724 | | Iris Rev. 8 | 725 | | Irispad Rev. 8 | 726 | | IrisRev0 | 727 | | Iron165 | 728 | | is0 | 729 | | is0GR | 730 | | Iskar | 731 | | ISO Macro | 732 | | itstleo40 | 733 | | itstleo9 | 734 | | Jabberwocky | 735 | | Jabberwocky v2 | 736 | | Jay60 Rev.1 | 737 | | JD45 | 738 | | Jelly Epoch | 739 | | Jelly Epoch Hotswap | 740 | | Jelly Evolv Hotswap_6.25U | 741 | | Jelly Evolv Hotswap_7U | 742 | | Jelly Evolv solder | 743 | | Jels60 | 744 | | Jels88 | 745 | | JetVan | 746 | | Ji-Eun | 747 | | Jian rev2 | 748 | | Jiran | 749 | | jisplit89 | 750 | | JK01 | 751 | | JK60 | 752 | | JK60 RGB | 753 | | JK65 | 754 | | JKB65 RGB | 755 | | JNAO | 756 | | Joker | 757 | | Jorne | 758 | | Joypad | 759 | | JP60 | 760 | | Junco | 761 | | K3 QMK | 762 | | Kabe Don 78S | 763 | | Kabe Don 980 | 764 | | KabeDon 98e | 765 | | kafkaSplit | 766 | | Kalice | 767 | | Kallos | 768 | | Kamigakushi | 769 | | Kangaroo Rev1 | 770 | | Kanu Mechlovin | 771 | | Kapl | 772 | | Katana60 v2 | 773 | | Kawayo | 774 | | Kay60 Rev.1 | 775 | | Kay65 | 776 | | KB Paradise v60 Type R | 777 | | KB16-01 | 778 | | KB83 | 779 | | KBD19x | 780 | | KBD67 Hotswap | 781 | | KBD67 MkII (Soldered) | 782 | | KBD67 MkII RGB V1 | 783 | | KBD67 MkII RGB V2 | 784 | | KBD67 Rev1 | 785 | | KBD67 Rev2 | 786 | | KBD67MKIIRGB-ISO | 787 | | KBD67MKIIRGBV3 | 788 | | KBD6x | 789 | | KBD75 Rev1 | 790 | | KBD75 Rev2 | 791 | | KBD75HS | 792 | | KBD75RGB | 793 | | KBD8X HS | 794 | | KBD8X-MKII | 795 | | KBDPad MK3 | 796 | | KBDPad MKII | 797 | | KBO-5000 Rev. 1 | 798 | | KBO-5000 Rev. 1a | 799 | | KC60 | 800 | | kd83a_bfg_edition | 801 | | kd87a_bfg_edition | 802 | | Keeb.io BFO-9000 | 803 | | Keebcats Denis | 804 | | Keebcats Dougal | 805 | | Keebio Viterbi Rev2 | 806 | | KeebsForAll Freebird60 | 807 | | KeebsForAll Freebird75 | 808 | | KeebsForAll FreebirdNP Lite | 809 | | KeebsForAll FreebirdNP Pro | 810 | | Keebwerk MEGA ANSI | 811 | | kelowna RGB64 | 812 | | Kepler | 813 | | Key 65 Hotswap | 814 | | Key 65 Universal | 815 | | KeyBee65 | 816 | | Keyboardio Atreus | 817 | | Keychron C1 Pro ANSI RGB | 818 | | Keychron C1 Pro ANSI White | 819 | | Keychron C2 Pro ANSI RGB | 820 | | Keychron C2 Pro ANSI White | 821 | | Keychron C3 Pro ANSI Red | 822 | | Keychron C3 Pro ANSI RGB | 823 | | Keychron Q0 | 824 | | Keychron Q0 Plus | 825 | | Keychron Q10 ANSI Knob | 826 | | Keychron Q10 ISO Knob | 827 | | Keychron Q11 ANSI Knob | 828 | | Keychron Q11 ISO Knob | 829 | | Keychron Q12 ANSI Knob | 830 | | Keychron Q12 ISO Knob | 831 | | Keychron Q1V1 ANSI | 832 | | Keychron Q1V1 ANSI Knob | 833 | | Keychron Q1V1 ISO | 834 | | Keychron Q1V1 ISO Knob | 835 | | Keychron Q1V2 ANSI | 836 | | Keychron Q1V2 ANSI Knob | 837 | | Keychron Q1V2 ISO | 838 | | Keychron Q1V2 ISO Knob | 839 | | Keychron Q1V2 JIS | 840 | | Keychron Q1V2 JIS Knob | 841 | | Keychron Q2 ANSI | 842 | | Keychron Q2 ANSI Knob | 843 | | Keychron Q2 ISO | 844 | | Keychron Q2 ISO Knob | 845 | | Keychron Q2 JIS | 846 | | Keychron Q2 JIS Knob | 847 | | Keychron Q3 ANSI | 848 | | Keychron Q3 ANSI Knob | 849 | | Keychron Q3 ISO | 850 | | Keychron Q3 ISO Knob | 851 | | Keychron Q3 JIS | 852 | | Keychron Q3 JIS Knob | 853 | | Keychron Q4 ANSI | 854 | | Keychron Q4 ISO | 855 | | Keychron Q5 ANSI | 856 | | Keychron Q5 ANSI Knob | 857 | | Keychron Q5 ISO | 858 | | Keychron Q5 ISO Knob | 859 | | Keychron Q6 ANSI | 860 | | Keychron Q6 ANSI Knob | 861 | | Keychron Q6 ISO | 862 | | Keychron Q6 ISO Knob | 863 | | Keychron Q60 | 864 | | Keychron Q65 | 865 | | Keychron Q7 ANSI | 866 | | Keychron Q7 ISO | 867 | | Keychron Q8 ANSI | 868 | | Keychron Q8 ANSI Knob | 869 | | Keychron Q8 ISO | 870 | | Keychron Q8 ISO Knob | 871 | | Keychron Q9 ANSI | 872 | | Keychron Q9 ANSI Knob | 873 | | Keychron Q9 ISO | 874 | | Keychron Q9 ISO Knob | 875 | | Keychron Q9 Plus ANSI Knob | 876 | | Keychron S1 ANSI RGB | 877 | | Keychron S1 ANSI White | 878 | | Keychron V1 ANSI | 879 | | Keychron V1 ANSI Knob | 880 | | Keychron V1 ISO | 881 | | Keychron V1 ISO Knob | 882 | | Keychron V1 JIS | 883 | | Keychron V1 JIS Knob | 884 | | Keychron V10 ANSI Knob | 885 | | Keychron V10 ISO Knob | 886 | | Keychron V2 | 887 | | Keychron V2 ANSI Knob | 888 | | Keychron V2 ISO | 889 | | Keychron V2 ISO Knob | 890 | | Keychron V2 JIS | 891 | | Keychron V2 JIS Knob | 892 | | Keychron V3 ANSI | 893 | | Keychron V3 ANSI Knob | 894 | | Keychron V3 ISO | 895 | | Keychron V3 ISO Knob | 896 | | Keychron V3 JIS | 897 | | Keychron V3 JIS Knob | 898 | | Keychron V4 ANSI | 899 | | Keychron V4 ISO | 900 | | Keychron V5 ANSI | 901 | | Keychron V5 ANSI Knob | 902 | | Keychron V5 ISO | 903 | | Keychron V5 ISO Knob | 904 | | Keychron V6 ANSI | 905 | | Keychron V6 ANSI Knob | 906 | | Keychron V6 ISO | 907 | | Keychron V6 ISO Knob | 908 | | Keychron V7 ANSI | 909 | | Keychron V7 ISO | 910 | | Keychron V8 ANSI | 911 | | Keychron V8 ANSI Knob | 912 | | Keychron V8 ISO | 913 | | Keychron V8 ISO Knob | 914 | | Keycult 1800 | 915 | | Keycult 65 | 916 | | Keycult TKL | 917 | | KeyDeck8 | 918 | | Keygem KG60 ANSI | 919 | | Keygem KG65 RGB V2 | 920 | | Keyspensory KP60 | 921 | | KF87 | 922 | | Kikkou | 923 | | Kintsugi | 924 | | Kira80 | 925 | | KiwiKey Borderland | 926 | | KiwiKey Kawii9 | 927 | | KiwiKey Wanderland | 928 | | KK65 | 929 | | kk980 | 930 | | KL-90 | 931 | | KLC Dolice | 932 | | Klein_HS | 933 | | Klein_SD | 934 | | KM113 | 935 | | KMAC | 936 | | Knight | 937 | | Knight-Plus | 938 | | Knob Goblin | 939 | | Koalafications | 940 | | Koolertron AMAG23 | 941 | | Kousa-TKL | 942 | | KP Republic BM60 Poker | 943 | | KP Republic BM60 RGB | 944 | | KPRepublic bm16-a | 945 | | KPrepublic bm16-s | 946 | | KPRepublic BM40 RGB | 947 | | KPrepublic BM68 RGB | 948 | | KPrepublic BM68 RGB Rev2 | 949 | | KPrepublic BM80 | 950 | | KPrepublic BM80v2 | 951 | | KPrepublic BM980 | 952 | | KPrepublic JJ40 | 953 | | KPrepublic JJ4x4 | 954 | | KPrepublic JJ50 | 955 | | KPrepublic XD75 | 956 | | Krado66 | 957 | | Krush60 Solder | 958 | | Krush65 Hotswap | 959 | | Krush65 Solder | 960 | | kt3700 | 961 | | kt60-M | 962 | | kt60HS-T | 963 | | kuku65 | 964 | | KY-01 | 965 | | Kyuu Hotswap | 966 | | L+M 60N | 967 | | labyrinth75 | 968 | | LagomStudio Plane60 | 969 | | Lain | 970 | | latin17rgb | 971 | | latin47ble | 972 | | latin60RGB | 973 | | latin64ble | 974 | | latinpad | 975 | | latinpadble | 976 | | Launch Pad | 977 | | LAZYDESIGERS Bolt | 978 | | LAZYDESIGERS Dimple | 979 | | LAZYDESIGERS THE40 | 980 | | LAZYDESIGNERS THE60Rev2 | 981 | | LB75 | 982 | | LCK75 | 983 | | LDK65 | 984 | | Le Chiffre | 985 | | Leaf 60 Hotswap | 986 | | Leaf 60 Universal | 987 | | let's split | 988 | | Let's Split v3 | 989 | | Leviatan | 990 | | Levinson Rev. 2 | 991 | | Levinson Rev. 3 | 992 | | LFK78 | 993 | | LFKPad | 994 | | LGBTKL | 995 | | LightWeight65 | 996 | | Lily | 997 | | Lily58 | 998 | | Lily58 R2G | 999 | | Liminal | 1000 | | LINE FRIENDS TKL | 1001 | | Linworks EM.8 | 1002 | | Linworks Fave 104 | 1003 | | Linworks Fave 60 | 1004 | | Linworks Fave 60A | 1005 | | Linworks Fave 87 | 1006 | | Linworks Fave PadA | 1007 | | Linworks Whale 75 | 1008 | | Lisa | 1009 | | Lodestone | 1010 | | Loki65 | 1011 | | Loop Pad | 1012 | | Lumberjack | 1013 | | Lunakey Mini | 1014 | | Lunar | 1015 | | Lunar II | 1016 | | Lune | 1017 | | LvL Type-01/80 | 1018 | | LW67 | 1019 | | LXXT | 1020 | | Lyra | 1021 | | LZ Physix | 1022 | | LZ-Erghost | 1023 | | M0lly | 1024 | | m3n3van | 1025 | | M60H | 1026 | | M60H | 1027 | | M60S | 1028 | | M63 RGB | 1029 | | M64 RGB | 1030 | | M80V2 H | 1031 | | M80V2 S | 1032 | | Mach 3 | 1033 | | MACRO1 | 1034 | | MacroCat Keyboard | 1035 | | MacroPad12 | 1036 | | Macropad5x4 | 1037 | | Macrowo Pad | 1038 | | MAJA | 1039 | | MAJA_SOLDERED | 1040 | | Majestouch Redux | 1041 | | Malicious Ergo | 1042 | | mammoth20x | 1043 | | mammoth75x | 1044 | | Manibus | 1045 | | Masonry | 1046 | | Masterworks Classy TKL | 1047 | | Matrix 1.2og | 1048 | | Matrix Falcon | 1049 | | Maypad | 1050 | | MC-76K | 1051 | | Mech Studio Dawn | 1052 | | Mechanical Keyboards, LLC MK61-RGB-ANSI | 1053 | | Mechbrewery MB-65H | 1054 | | Mechbrewery MB-65S | 1055 | | Mechmini V2 | 1056 | | MechWild BB65 | 1057 | | MechWild Mercutio | 1058 | | MechWild Mokulua | 1059 | | MechWild Mokulua | 1060 | | MechWild MurphPad | 1061 | | MechWild OBE | 1062 | | MechWild Waka60 | 1063 | | meishi2 | 1064 | | Mekanisk Edda | 1065 | | MelGeek Mach80 rev1 | 1066 | | MelGeek MJ61 REV1 | 1067 | | MelGeek MJ63 REV1 | 1068 | | MelGeek MJ64 REV1 | 1069 | | MelGeek MJ65 REV3 | 1070 | | MelGeek MoJo68 rev1 | 1071 | | MelGeek MOJO75 REV1 | 1072 | | MelGeek tegic rev1 | 1073 | | MelGeek Z70 Ultra Rev1 | 1074 | | meow65 | 1075 | | Meow65 | 1076 | | Mercury | 1077 | | Meridian | 1078 | | Meridian RGB | 1079 | | Mesa TKL | 1080 | | MF17 | 1081 | | MF34 | 1082 | | MF68 | 1083 | | Microdox | 1084 | | Midway60 | 1085 | | Mikeneko 65 | 1086 | | Mine | 1087 | | Minerva LX | 1088 | | Mini Ashen 40 | 1089 | | Mini Winni | 1090 | | Minivan | 1091 | | Minne | 1092 | | Minne - Topre | 1093 | | Mino (Hotswap) | 1094 | | Mino Plus | 1095 | | Minshara Marauder | 1096 | | Mixi | 1097 | | MJ6XY | 1098 | | MK47 | 1099 | | MMK_3 | 1100 | | MMKZOO65 | 1101 | | MNK 60 EC | 1102 | | MNK 65 EC | 1103 | | MNK1800s | 1104 | | MNK50 | 1105 | | MNK60_STM32 | 1106 | | MNK65 | 1107 | | MNK65_STM32 | 1108 | | MNK88 | 1109 | | Mode Eighty M80H | 1110 | | Mode Eighty M80S | 1111 | | Mode M256W-H Alpha | 1112 | | Mode M256W-S Alpha | 1113 | | Mode SeventyFive H | 1114 | | Mode SeventyFive S | 1115 | | Mode SixtyFive HA Alpha | 1116 | | Mode SixtyFive HI Alpha | 1117 | | Mode SixtyFive M65S | 1118 | | model-v | 1119 | | mokey63 | 1120 | | mokey64 | 1121 | | Moment | 1122 | | Moment HS | 1123 | | Momoka Ergo | 1124 | | Momokai Aurora | 1125 | | Momokai Tap Duo | 1126 | | Momokai Tap Trio | 1127 | | Mona | 1128 | | Mona | 1129 | | Mona | 1130 | | Monarch | 1131 | | Monoflex 60 | 1132 | | MonsGeek M1 | 1133 | | MonsGeek M5 | 1134 | | MonsGeek M6 | 1135 | | Monstargear XO87 | 1136 | | Monstargear XO87 Soldered | 1137 | | Moondrop Dash75 | 1138 | | Moonlander Mark I (Unsupported by ZSA) | 1139 | | MOTHWING | 1140 | | Mountainblocks MB17 | 1141 | | murcielago | 1142 | | MW65 | 1143 | | MW65 | 1144 | | MW660 | 1145 | | MW75 | 1146 | | MW75 | 1147 | | MW80 | 1148 | | MxSS | 1149 | | Mysterium | 1150 | | N86 | 1151 | | N87 | 1152 | | N8X | 1153 | | naked48 | 1154 | | naked60 | 1155 | | Nano Pad | 1156 | | Nascent | 1157 | | Nasu | 1158 | | Nature | 1159 | | Navi60 | 1160 | | Nayeon | 1161 | | NCR-80 | 1162 | | NCR-80 Hotswap | 1163 | | NEBULA12 | 1164 | | NEBULA12B | 1165 | | NEBULA68 | 1166 | | NEBULA68B | 1167 | | nein | 1168 | | Nemui | 1169 | | nemui65 | 1170 | | Neson Design 700E | 1171 | | Neson Design 810E | 1172 | | Neson Design N6 | 1173 | | Neson Design Nico | 1174 | | Neuron | 1175 | | NIBBLE | 1176 | | nibell/micropad4x4 | 1177 | | Nightly Boards [n]2 | 1178 | | Nightly Boards [n]40-o | 1179 | | Nightly Boards [n]60-S | 1180 | | Nightly Boards [n]87 | 1181 | | Nightly Boards Adellein | 1182 | | Nightly Boards Octopad | 1183 | | nightmare | 1184 | | nightstar75_Y&R | 1185 | | Ninjin | 1186 | | niu_mini | 1187 | | NK_ Classic TKL | 1188 | | NK_ Classic TKL ISO | 1189 | | NK+ | 1190 | | NK+ Solder | 1191 | | NK1 | 1192 | | NK20 | 1193 | | NK65 | 1194 | | NK65B | 1195 | | NK87 | 1196 | | NK87B | 1197 | | NKNL7EN | 1198 | | NKNL7JP | 1199 | | Noah | 1200 | | Nodu | 1201 | | Noon | 1202 | | NOP60 | 1203 | | Nordic60 Rev A | 1204 | | Nordic65 Rev A | 1205 | | NormiePad | 1206 | | Novus | 1207 | | Noxary 220 | 1208 | | Noxary 260 | 1209 | | Noxary 268 | 1210 | | Noxary 268.2 | 1211 | | Noxary 268.2 | 1212 | | Noxary 268.2 RGB | 1213 | | Noxary 280 | 1214 | | Noxary 378 | 1215 | | Noxary x268 | 1216 | | NP-64 | 1217 | | NP-hhkb | 1218 | | NP-minila | 1219 | | np12 | 1220 | | Nue | 1221 | | Numpad | 1222 | | Numpad | 1223 | | Nyhxis NFR-70 | 1224 | | Nyquist Rev. 2 | 1225 | | Nyquist Rev. 3 | 1226 | | Nyquist Rev. 4 | 1227 | | Nyquist Rev. 5 | 1228 | | Nyquistpad Rev. 1 | 1229 | | NZ64_Y&R | 1230 | | NZ67V2_Y&R | 1231 | | Obi | 1232 | | Obliterated75 | 1233 | | Oceanographer | 1234 | | OctagonV2 | 1235 | | Octopad+ | 1236 | | Odelia | 1237 | | odin_rgb | 1238 | | odin_soldered | 1239 | | ODIN65 ANSI | 1240 | | ODIN65 ISO | 1241 | | ODIN75 | 1242 | | odinmini | 1243 | | ok60 | 1244 | | Okayu | 1245 | | OLKB Planck rev4 | 1246 | | OLKB PLANCK REV6.1 | 1247 | | OLKB Preonic Rev3 | 1248 | | olli.works Neito | 1249 | | Olly BB | 1250 | | Olly JF | 1251 | | Olly Octagon | 1252 | | Olly Orion | 1253 | | OM60 | 1254 | | Onyx | 1255 | | OR87 | 1256 | | ORBA | 1257 | | Orbit-X | 1258 | | original konbini ok-1 | 1259 | | Ortho48 | 1260 | | Ortho48v2 | 1261 | | Ortho60 | 1262 | | Ortho60v2 | 1263 | | orthocode | 1264 | | OSA | 1265 | | OSA V2 | 1266 | | OSAv2 | 1267 | | OSAv2 - Topre | 1268 | | OSAv2 Numpad | 1269 | | OSAv2 Numpad - Topre | 1270 | | owl8 | 1271 | | OXALYS80 | 1272 | | P.01 | 1273 | | p01 ultra | 1274 | | Pachi | 1275 | | Pachi RGB Rev1 | 1276 | | Pachi RGB Rev2 | 1277 | | Paladin64 | 1278 | | PaladinPad | 1279 | | Palette G67 Hotswap | 1280 | | Palette G67 Soldered | 1281 | | Pandamic | 1282 | | Pandora - By Koobaczech | 1283 | | Paragon | 1284 | | Parallel 65% Hotswap PCB | 1285 | | Parallel 65% PCB | 1286 | | Paraluman | 1287 | | Part.1-75-HS | 1288 | | Paws 60 | 1289 | | PDXKBC Macropad | 1290 | | Peac Design - PLX | 1291 | | Peaker | 1292 | | Pearl 40% - By Koobaczech | 1293 | | Percent Canoe Gen2 | 1294 | | Percent Skog Lite | 1295 | | Perk60 ISO Rev A | 1296 | | Petrichor | 1297 | | PH Arisu | 1298 | | Phantom | 1299 | | Phantom | 1300 | | PhaseOne | 1301 | | Phoenix | 1302 | | Phoenix Project No 1 | 1303 | | Phoenix45_Ortho | 1304 | | pi40 | 1305 | | pi40 | 1306 | | pi60 | 1307 | | pi60_hse | 1308 | | pi60_rgb | 1309 | | pianoforte | 1310 | | pianoforte hotswap | 1311 | | Pierce | 1312 | | Piggy60 | 1313 | | Pimoroni Keybow 2040 | 1314 | | Pink Labs - Bliss | 1315 | | Pinky3 | 1316 | | Pinky4 | 1317 | | pisces | 1318 | | Pisces | 1319 | | Pisces | 1320 | | pistachio | 1321 | | Pix | 1322 | | Pizza Keyboards Pizza65 | 1323 | | PizzaPad | 1324 | | Plaid | 1325 | | Plaid-Pad | 1326 | | PLAQUE80 | 1327 | | Plexus75 | 1328 | | Plexus75_HE | 1329 | | Ploopy Adept Trackball (Madromys) | 1330 | | PloopyCo Mouse | 1331 | | PloopyCo Trackball | 1332 | | PloopyCo Trackball Mini | 1333 | | PloopyCo Trackball Thumb | 1334 | | Plume65 | 1335 | | PLUTO | 1336 | | ply8x | 1337 | | POKER-87C | 1338 | | POKER-87D | 1339 | | Polaris | 1340 | | Polaris Ex | 1341 | | Polaris HS and Solder | 1342 | | Polarity Works CRBN | 1343 | | polilla | 1344 | | POLLY 40 | 1345 | | Portal 66 | 1346 | | Portal 66 Hotswap | 1347 | | Portico | 1348 | | Portico68 v2 | 1349 | | Portico75 | 1350 | | posey_split_v4 | 1351 | | posey_split_v5 | 1352 | | Potato65 Hotswap | 1353 | | Potato65 Solderable | 1354 | | Practice60 | 1355 | | Preonic Rev2 | 1356 | | PRIME_E | 1357 | | PRIME_E RGB | 1358 | | Prime_EXL | 1359 | | Prime_EXL Plus | 1360 | | Prime_L | 1361 | | Prime_L V2 | 1362 | | Prime_M | 1363 | | primus75 | 1364 | | printedpad | 1365 | | Program Yoink! | 1366 | | ProjectD 65% ANSI | 1367 | | ProjectD 75% ANSI | 1368 | | ProjectKB Alice | 1369 | | ProjectKB Signature87 | 1370 | | Promenade | 1371 | | Promenade RP24S | 1372 | | Promise 87 | 1373 | | Promise 87 | 1374 | | Prophet | 1375 | | Proteus67 | 1376 | | Proto[Typist] PT-60 | 1377 | | Proto[Typist] PT-80 | 1378 | | Prototypist J-01 | 1379 | | Pteron36 | 1380 | | Pumpkinpad | 1381 | | punk75 | 1382 | | Pursuit40 | 1383 | | PW88 | 1384 | | QAZ | 1385 | | qk100 ansi | 1386 | | qk100 Solder | 1387 | | QK65 Hotswap | 1388 | | QK65 Solder | 1389 | | QuadrumLabs Delta | 1390 | | Quantrik Kyuu | 1391 | | Quark | 1392 | | Quark_LP | 1393 | | Quark_Plus | 1394 | | Quark² | 1395 | | Quefrency Rev. 1 | 1396 | | Quefrency Rev. 2 | 1397 | | Quefrency Rev. 3 | 1398 | | Quefrency Rev. 3 | 1399 | | Quefrency Rev. 4 | 1400 | | Quefrency Rev. 4 | 1401 | | Quefrency Rev. 5 | 1402 | | Quefrency Rev. 5 | 1403 | | Quefrency Rev. 6 | 1404 | | Quick7 | 1405 | | QVEX Lynepad | 1406 | | Qwertyqop 60% Hotswap | 1407 | | rainkeeb | 1408 | | RAMA WORKS KARA | 1409 | | RAMA WORKS KOYU | 1410 | | RAMA WORKS M10-A | 1411 | | RAMA WORKS M10-B | 1412 | | RAMA WORKS M10-C | 1413 | | RAMA WORKS M4-A | 1414 | | RAMA WORKS M50-A | 1415 | | RAMA WORKS M50-AX | 1416 | | RAMA WORKS M6-A | 1417 | | RAMA WORKS M6-B | 1418 | | RAMA WORKS M60-A | 1419 | | RAMA WORKS M65-B | 1420 | | RAMA WORKS M65-BX | 1421 | | RAMA WORKS U80-A | 1422 | | Ranger | 1423 | | Rapid Capture Plan | 1424 | | RART45 | 1425 | | RART4X4 | 1426 | | RART60 | 1427 | | RART67 | 1428 | | RART67M | 1429 | | RART75 | 1430 | | RART75 Hotswap | 1431 | | RART75M | 1432 | | RART80 | 1433 | | RARTAND | 1434 | | RARTLAND | 1435 | | RARTLICE | 1436 | | RARTLITE | 1437 | | RARTPAD | 1438 | | Rati(o)60 Hotswap Rev A | 1439 | | Ratio65 Rev A | 1440 | | Ratio65 Rev A HS | 1441 | | RE65 | 1442 | | Ready100 | 1443 | | Rebound Rev. 4 | 1444 | | recompile keys Choco60 | 1445 | | recompile keys MIO | 1446 | | recompile keys Nomu30 | 1447 | | Red Herring | 1448 | | Redox | 1449 | | Redox-W | 1450 | | Redragon K667 | 1451 | | Rekt1800 | 1452 | | Rena | 1453 | | Retro66 | 1454 | | Retropad | 1455 | | Reverb | 1456 | | reviung34 | 1457 | | Reviung41 | 1458 | | REVPAD | 1459 | | RF R1 8-9Xu | 1460 | | Riotpad | 1461 | | Ripple | 1462 | | Ripple HS | 1463 | | Rocketboard 16 | 1464 | | Rogue87 | 1465 | | RoMac | 1466 | | RoMac+ | 1467 | | Romeo | 1468 | | Rooboard65 | 1469 | | RooPad | 1470 | | Rosa | 1471 | | Rotor | 1472 | | Rouge87 | 1473 | | RPK-001 | 1474 | | RS60 | 1475 | | Rubi | 1476 | | Runes Skjoldr | 1477 | | Runes Vaengr | 1478 | | ryanbaekr rb18 | 1479 | | ryanbaekr rb69 | 1480 | | ryanbaekr rb86 | 1481 | | ryanbaekr rb87 | 1482 | | Ryujin | 1483 | | S6xty | 1484 | | S6xty5Neo Rev.2 | 1485 | | S7 Elephant Rev2 | 1486 | | Sabre | 1487 | | Sagittarius | 1488 | | SakuraWorkshop Fuji75 Hotswap | 1489 | | SakuraWorkshop Fuji75 Solder | 1490 | | Sam_S80 | 1491 | | sandbox | 1492 | | sandbox rev2 | 1493 | | Satellite Rev1 | 1494 | | Satisfaction75 | 1495 | | Satisfaction75 HS | 1496 | | Satisfaction75 Rev 2 | 1497 | | Satxri6key | 1498 | | Sauce - Mild | 1499 | | Savage65 | 1500 | | Scarlet | 1501 | | Scorpio | 1502 | | SCRAMBLE | 1503 | | Scylla | 1504 | | Sebelas | 1505 | | Seigaiha | 1506 | | selka40 | 1507 | | SENSE75 | 1508 | | Serenity | 1509 | | serneity65 | 1510 | | Serpent65 | 1511 | | Serratus Rev. 1 | 1512 | | Sesame | 1513 | | Sessanta | 1514 | | sf2040 | 1515 | | SHADOW80 | 1516 | | SheuBox Fallacy | 1517 | | Shisaku | 1518 | | shu89 | 1519 | | sick68 | 1520 | | Silhouette | 1521 | | Simpler61 | 1522 | | Simpler64 | 1523 | | Sinanju | 1524 | | Sinanju WK | 1525 | | Sinc Rev. 1 | 1526 | | Sinc Rev. 1a | 1527 | | Sinc Rev. 2 | 1528 | | Sinc Rev. 2a | 1529 | | Sinc Rev. 3 | 1530 | | Sinc Rev. 4 | 1531 | | Singa | 1532 | | SINGA Kohaku | 1533 | | Singa x TGR Unikorn | 1534 | | Siris | 1535 | | Six Pack | 1536 | | SIXKEYBOARD | 1537 | | Skeletn87 | 1538 | | Skeletn87 Hotswap | 1539 | | Skelett 40 | 1540 | | Skelett 60 | 1541 | | Skeletyl | 1542 | | SKErgo | 1543 | | SKILLER SGK50 S2 | 1544 | | SKILLER SGK50 S3 | 1545 | | SKILLER SGK50 S4 | 1546 | | SKME Zeno 60% Ergo | 1547 | | SKMT 15k | 1548 | | SKYLINE | 1549 | | Skyloong DT40 | 1550 | | Skyloong Gk61 Pro | 1551 | | Skyloong Gk61 Pro_48 | 1552 | | Skyloong Gk61 V1 | 1553 | | Skyloong qk21 V1 | 1554 | | Slamz | 1555 | | Slice Rev 1 | 1556 | | Slice RGB rev1 | 1557 | | slice65 | 1558 | | Slime88 | 1559 | | sm68 | 1560 | | smAllice | 1561 | | smallkeyboard | 1562 | | Smith and Rune I160-H | 1563 | | Smith and Rune I160-S | 1564 | | Smith and Rune Iron165 R2 | 1565 | | Smith and Rune IRON180 | 1566 | | Smith and Rune Magnus | 1567 | | SMK65v2 RevF | 1568 | | Smolka | 1569 | | Snagpad | 1570 | | SNAP | 1571 | | Sneakbox Alice Clone | 1572 | | Sneakbox Alice Clone | 1573 | | SNOP60 | 1574 | | SnR Magnus M75H | 1575 | | sodium62 | 1576 | | Sofle Choc | 1577 | | Sofle v1 | 1578 | | Sofle v2 RGB | 1579 | | Solanis | 1580 | | Soulstone | 1581 | | soup10 | 1582 | | Southern Breeze | 1583 | | SouthPad v2 | 1584 | | Southpaw Fullsize | 1585 | | Southpaw66 | 1586 | | Southpaw75 | 1587 | | Soy20 | 1588 | | Soyuz | 1589 | | Soyuz | 1590 | | SoyuzXL | 1591 | | SP-111 | 1592 | | SP-111 | 1593 | | SpaccBoard | 1594 | | space80: apollo | 1595 | | spaceman_2_milk | 1596 | | spaceman_pancake | 1597 | | Spacey | 1598 | | Span | 1599 | | SPIN Macropad | 1600 | | Split67 | 1601 | | SplitKB Kyria | 1602 | | SplitKB Zima | 1603 | | Spring | 1604 | | Square.X | 1605 | | Squishy65 | 1606 | | SquishyFRL | 1607 | | SquishyTKL | 1608 | | Sriwedari70 | 1609 | | Star75 | 1610 | | Stealth | 1611 | | Steezy60 Rev A | 1612 | | Steezy60 Rev B | 1613 | | Stello65 | 1614 | | Stello65 | 1615 | | Stelo65 | 1616 | | stickey4 | 1617 | | Stratos | 1618 | | Stream Cheap 2x4 | 1619 | | stream15 | 1620 | | Styrka - Topre | 1621 | | Sugar Glider | 1622 | | suika27melo | 1623 | | suika85ergo | 1624 | | Suit80 ANSI | 1625 | | Suit80 ISO | 1626 | | Summer Breeze | 1627 | | Sunsetter | 1628 | | Sunsetter R2 | 1629 | | Super16 | 1630 | | Super16 V2 | 1631 | | Super16 V3 | 1632 | | Superhuman SHK9 | 1633 | | SuperLyra | 1634 | | Superuser EXT | 1635 | | Superuser FRL | 1636 | | Superuser TKL | 1637 | | Sus | 1638 | | Swagkeys Eave | 1639 | | Swagkeys Integral | 1640 | | Sweeq | 1641 | | sweet16 v1 | 1642 | | sweet16 v2 | 1643 | | Swift 65 Hotswap | 1644 | | Swift 65 Solder | 1645 | | Swiss | 1646 | | Switchplate 910 | 1647 | | Swordfish | 1648 | | SX60 | 1649 | | SyenaKeyboards Aswagata | 1650 | | SyenaKeyboards Elaruus | 1651 | | Synth Labs 060 | 1652 | | Synth Labs Solo | 1653 | | Synthesis60 rev2 | 1654 | | TAC-K1 | 1655 | | Tada68 | 1656 | | Taleguers75 | 1657 | | TAN67R2 | 1658 | | Tata80 | 1659 | | Tata80 | 1660 | | TBK Mini | 1661 | | TC-V3 | 1662 | | TeaQueen | 1663 | | TechnicPad | 1664 | | Technik-O | 1665 | | Technik-S | 1666 | | TENKI | 1667 | | TG4x | 1668 | | TG67 | 1669 | | TG67_Y&R | 1670 | | TGR 910 CE | 1671 | | TGR Jane V2 | 1672 | | TGR Jane V2 CE | 1673 | | TGR LENA | 1674 | | TGR-910 | 1675 | | TH1800 | 1676 | | The Galleon | 1677 | | The Mark: 65 | 1678 | | The Pegasus Hoof | 1679 | | The Q | 1680 | | The Stick Rev. 1 | 1681 | | The Tiger Lily | 1682 | | The Vector | 1683 | | The_Black_Hellebore | 1684 | | THE30 | 1685 | | things are going well | 1686 | | Thirty | 1687 | | TIDBIT | 1688 | | TIGER80 | 1689 | | tiger910 | 1690 | | Timber Wolf | 1691 | | Tinny50 RGB | 1692 | | tinyneko | 1693 | | Titan 60 | 1694 | | Titan65 | 1695 | | Titan65 (soldered) | 1696 | | TKC California | 1697 | | TKC TKL A/B87 | 1698 | | TKC1800 | 1699 | | TKL-FF | 1700 | | TKL-FF | 1701 | | TKLFRLNRLMLAO | 1702 | | tlprt NumPad | 1703 | | TMKL | 1704 | | tmo50 | 1705 | | TMOv2 | 1706 | | TOFU_II | 1707 | | TOFU_JR | 1708 | | TOFU60 | 1709 | | Tokki | 1710 | | Tokyo60 Rev.1 | 1711 | | Tomak | 1712 | | Tomo - MNK75 | 1713 | | Torn | 1714 | | trainPad | 1715 | | Transition TKL | 1716 | | Treasure TYPE-9 Series II | 1717 | | Treasure TYPE-9 Series III | 1718 | | Trifecta | 1719 | | TRINITY XT TKL | 1720 | | Tris | 1721 | | TS60 | 1722 | | Tsukuyomi | 1723 | | TutelPad | 1724 | | TW40 | 1725 | | Twelvekey | 1726 | | Twilight | 1727 | | Txuu | 1728 | | Typ65+ | 1729 | | Type B | 1730 | | Type-K EC | 1731 | | Type-K EC | 1732 | | Tyson60s | 1733 | | UC-1 | 1734 | | UD40_Ortho_Alt | 1735 | | UM-70 | 1736 | | UM-80 | 1737 | | UM-A | 1738 | | Undead 60M | 1739 | | Unextended Standard Rev A | 1740 | | Ungodly Design Launch Pad | 1741 | | Uni660 | 1742 | | Uni660 V2 | 1743 | | Unicorne | 1744 | | UnSplit | 1745 | | ut472 | 1746 | | Valhalla | 1747 | | Valhalla V2 | 1748 | | VALOR | 1749 | | VALOR FRL TKL | 1750 | | VALOR REV 2 | 1751 | | Varanidae | 1752 | | VCL65 by VCL x SawnsProjects | 1753 | | Vector | 1754 | | Vega | 1755 | | Velvet Hotswap | 1756 | | Velvet Solder | 1757 | | Vermillion's Ergo - Armored Edition | 1758 | | Vero EC | 1759 | | Vertex | 1760 | | Vicious40 | 1761 | | Viendi8L | 1762 | | Viktus Styrka | 1763 | | Virgo EC | 1764 | | Vision | 1765 | | Vitamins Included | 1766 | | VN | 1767 | | Voice65 | 1768 | | Voice65 Hotswap | 1769 | | VOID65H | 1770 | | VOLCANO660 | 1771 | | Voyager60-Alps | 1772 | | VRYNBOARD | 1773 | | Vulcan | 1774 | | W1-AT | 1775 | | waffling60 Rev A | 1776 | | waffling60 Rev B | 1777 | | waffling60 Rev C | 1778 | | waffling60 Rev D | 1779 | | waffling60 Rev D ANSI | 1780 | | waffling60 Rev D ISO | 1781 | | waffling60 Rev E | 1782 | | waffling60 Rev E ANSI | 1783 | | waffling80 Rev A | 1784 | | waffling80 Rev B | 1785 | | waffling80 Rev B ANSI HS | 1786 | | Waldo 60 | 1787 | | Walter | 1788 | | Wampus | 1789 | | Wang Ergo | 1790 | | Wang V2 | 1791 | | wave75_Y&R | 1792 | | Wazowski 23-19 rev0 | 1793 | | WE27 | 1794 | | wendy | 1795 | | werk.technica's One | 1796 | | Wete | 1797 | | Wete R2 | 1798 | | WH66 | 1799 | | wilba.tech WT45-G | 1800 | | wilba.tech WT45-H1 | 1801 | | wilba.tech WT6-KH | 1802 | | wilba.tech WT60-A | 1803 | | wilba.tech WT60-B | 1804 | | wilba.tech WT60-BX | 1805 | | wilba.tech WT60-C | 1806 | | wilba.tech WT60-D | 1807 | | wilba.tech WT60-E | 1808 | | wilba.tech WT60-G | 1809 | | wilba.tech WT60-G2 | 1810 | | wilba.tech WT60-H1 | 1811 | | wilba.tech WT60-H2 | 1812 | | wilba.tech WT60-H3 | 1813 | | wilba.tech WT60-KH1 | 1814 | | wilba.tech WT60-KH2 | 1815 | | wilba.tech WT60-LH1 | 1816 | | wilba.tech WT60-XT | 1817 | | wilba.tech WT60-XTH | 1818 | | wilba.tech WT65-A | 1819 | | wilba.tech WT65-B | 1820 | | wilba.tech WT65-C | 1821 | | wilba.tech WT65-CX | 1822 | | wilba.tech WT65-D | 1823 | | wilba.tech WT65-F | 1824 | | wilba.tech WT65-FX | 1825 | | wilba.tech WT65-G | 1826 | | wilba.tech WT65-G2 | 1827 | | wilba.tech WT65-G3 | 1828 | | wilba.tech WT65-H1 | 1829 | | wilba.tech WT65-H2 | 1830 | | wilba.tech WT65-H3 | 1831 | | wilba.tech WT65-H4 | 1832 | | wilba.tech WT65-XT | 1833 | | wilba.tech WT65-XTX | 1834 | | wilba.tech WT69-A | 1835 | | wilba.tech WT70-JB | 1836 | | wilba.tech WT75-A | 1837 | | wilba.tech WT75-B | 1838 | | wilba.tech WT75-C | 1839 | | wilba.tech WT8-A | 1840 | | wilba.tech WT8-KH | 1841 | | wilba.tech WT80-A | 1842 | | wilba.tech WT80-BC | 1843 | | wilba.tech WT80-G | 1844 | | wilba.tech WT80-H1 | 1845 | | wilba.tech WT90-A | 1846 | | Willou.com Keypad | 1847 | | Wings | 1848 | | Wings Hotswap | 1849 | | wings42 | 1850 | | wings42 extkeys | 1851 | | Winry315 | 1852 | | WITF | 1853 | | Work Board | 1854 | | WT20-H1 | 1855 | | WTF60 Rev. 1 | 1856 | | Wyvern | 1857 | | XD60 rev 2 | 1858 | | XD60 rev 3 | 1859 | | XD68 | 1860 | | XD84 Pro | 1861 | | XD87 | 1862 | | xd96 | 1863 | | Xelus LA+ | 1864 | | Xelus Snap96 | 1865 | | XOX70 | 1866 | | XR63GL | 1867 | | XS108 | 1868 | | XS60 Hotswap | 1869 | | XS60 Soldered | 1870 | | XT60 | 1871 | | XT60_SINGAKBD | 1872 | | XT65 | 1873 | | XT87 | 1874 | | XT8x | 1875 | | Yakiimo Rev A | 1876 | | Yampad | 1877 | | Yasui | 1878 | | YDKB Grape | 1879 | | Yeehaw | 1880 | | Yeti | 1881 | | Yeti RGB | 1882 | | YMD 75 VIA | 1883 | | YMDK Bface | 1884 | | YMDK Melody 96 | 1885 | | YMDK NP21 | 1886 | | YMDK SP64 | 1887 | | YMDK YD60MQ | 1888 | | YMDK YMD09 | 1889 | | YMDK YMD40 v2 | 1890 | | YR6095_Y&R | 1891 | | YR80_Y&R | 1892 | | Yuri | 1893 | | Z40 Ortho | 1894 | | Z60 Hotswap | 1895 | | Z60 Solder | 1896 | | Z67 Hotswap | 1897 | | Z67 Solder | 1898 | | ZEAL60 | 1899 | | ZEAL65 | 1900 | | Zed60 Rev.1 | 1901 | | Zed65 Mono LED - Dolch65 | 1902 | | Zed65 Rev.1 | 1903 | | Zed65-Cor65 | 1904 | | zhou65_Y&R | 1905 | | Ziggurat | 1906 | | Ziggurat | 1907 | | Zinc | 1908 | | ziyoulang k3 mod | 1909 | | ZLABKEEB 15PAD | 1910 | | ZLABKEEB 6PAD | 1911 | | Zodiark | 1912 | | Zoom 87 | 1913 | | zoom65 | 1914 | | zoom65 | 1915 | | zoom75 | 1916 | | Zwag75 | 1917 | | ZX60 | 1918 | -------------------------------------------------------------------------------- /docs/v3_changes.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: v3_changes 3 | title: VIA Version 3 Changes 4 | sidebar_label: VIA Version 3 Changes 5 | --- 6 | 7 | ## Introduction 8 | 9 | In VIA Version 1,the UI and the keyboard definitions were entirely self-contained (i.e. hard-coded). Adding new keyboards requires changing code and rebuilding/releasing the app. 10 | 11 | VIA Version 2 moved the keyboard definitions into externally defined files, which are stored in a GitHub repository. The keyboard definitions are served to the VIA client at run-time. This allowed anyone to add new keyboards to VIA without requiring changing the source and rebuilding/releasing the app. 12 | 13 | VIA Version 2 keyboard definitions include layout options and control of lighting, but definitions were restricted to the existing UI elements. 14 | 15 | VIA Version 3 is a refactoring of how the UI works in VIA, to allow fully customized UI within VIA to control firmware parameters like lighting, but also **any custom feature** implemented in the firmware, either in QMK Core or at the keyboard level. It works by defining what UI elements VIA should show, and binding those UI elements to IDs, which VIA will use in communication with the firmware. 16 | 17 | ## Keyboard Definition Changes for VIA V2 to V3 18 | 19 | This describes the changes made between V2 and V3. 20 | 21 | ### Lighting 22 | 23 | The `lighting` element is deprecated and replaced by specifying **one or more** of the following in the `menus` element: 24 | 25 | - `"qmk_backlight"` 26 | - `"qmk_rgblight"` 27 | - `"qmk_backlight_rgblight"` 28 | - `"qmk_rgb_matrix"` 29 | 30 | **and/or** defining the custom UI in the `menus` element. 31 | 32 | Example: 33 | 34 | ```json 35 | "menus": [ "qmk_rgb_matrix" ] 36 | ``` 37 | 38 | Additionally, `"qmk_lighting"` can be added to the `keycodes` element to explicitly enable the QMK keycodes for lighting. 39 | 40 | Example: 41 | 42 | ```json 43 | "keycodes": [ "qmk_lighting" ] 44 | ``` 45 | 46 | The above additions are all that is required to enable the UI for controlling the stock lighting features of QMK. 47 | 48 | ### Menus 49 | 50 | The `menus` element is new in V3, and used to define the UI (aka. menus) in VIA. It replaces how lighting control is defined, and allows for defining other run-time parameters of a keyboard firmware. 51 | 52 | For example, a keyboard definition for a keyboard that uses the QMK RGB Matrix feature would have the following `menus` element: 53 | 54 | ```json 55 | "menus": [ "qmk_rgb_matrix" ] 56 | ``` 57 | 58 | However, the `menus` element can contain a complete definition of custom UI, allowing full customization of the lighting page, or other custom feature requiring control by VIA. 59 | 60 | For example, the item `"qmk_rgb_matrix"` in the `menus` element can be replaced with the equivalent custom UI definition to control the QMK RGB Matrix feature, such as: 61 | 62 | ```json 63 | "menus": [ 64 | { 65 | "label": "Lighting", 66 | "content": [ 67 | { 68 | "label": "Backlight", 69 | "content": [ 70 | { 71 | "label": "Brightness", 72 | "type": "range", 73 | "options": [0, 255], 74 | "content": ["id_qmk_rgb_matrix_brightness", 3, 1] 75 | }, 76 | ... 77 | ``` 78 | 79 | The use of `"qmk_backlight"`, `"qmk_rgblight"`, `"qmk_backlight_rgblight"` and `"qmk_rgb_matrix"` in the `menus` element causes VIA to use the default UI definition that matches the firmware that is built when enabling these features. Firmware authors can replace these with custom UI definitions that are identical, and then change them to match changes made to the firmware. 80 | 81 | The built-in UI definitions are located in the repository [here](https://github.com/the-via/keyboards/tree/master/common-menus). 82 | 83 | The complete documentation for custom UI is [here](custom_ui). 84 | 85 | ### Firmware Version 86 | 87 | ```json 88 | "firmwareVersion": 0 89 | ``` 90 | 91 | `firmwareVersion` is a way to version custom UI definitions. This new element ensures that VIA and the firmware are both using the same definition of custom UI (i.e. the `menus` element). If a feature is added or changed in the keyboard firmware, VIA will be able to detect when it is communicating with firmware built before this. 92 | 93 | Firmware authors can increment the `VIA_FIRMWARE_VERSION` symbol in the QMK source code and the `firmwareVersion` in the VIA keyboard definition at the same time. `firmwareVersion` is optional, and will default to 0 if not present, matching the default `VIA_FIRMWARE_VERSION` in QMK. As such, most firmware authors may never need to set this element if they never change the features of the firmware. 94 | 95 | Note that `firmwareVersion` is different to the VIA protocol version (`VIA_PROTOCOL_VERSION` in QMK), which ensures that VIA and the firmware are both using the same definition of command IDs and command paramters. For example. the change from V2 to V3 definitions is an example of how the VIA protocol version is used. 96 | 97 | ## QMK Changes for VIA V2 to V3 98 | 99 | VIA V2 definitions are used for QMK firmware built with VIA Protocol 10 or less. 100 | VIA V3 definitions are used for QMK firmware built with VIA Protocol 11 or greater. 101 | 102 | VIA will continue to function with existing firmware that was built with VIA Protocol 10 or less, by using the VIA V2 definition. 103 | 104 | All V2 definitions were converted to equivalent V3 definitions in the repository, so that firmware built using VIA Protocol 11 will function as expected. 105 | 106 | The following describes the changes in QMK between VIA Protocol 10 and 11. 107 | 108 | ### Commands 109 | 110 | The commands for setting/getting lighting values have been replaced with commands for setting/getting "custom" values. Custom values can be for lighting or any other feature. 111 | 112 | This in VIA Protocol 10: 113 | ```c 114 | enum via_command_id { 115 | ... 116 | id_lighting_set_value = 0x07, 117 | id_lighting_get_value = 0x08, 118 | id_lighting_save = 0x09, 119 | ... 120 | } 121 | ``` 122 | Is now this in VIA Protocol 11: 123 | ```c 124 | enum via_command_id { 125 | ... 126 | id_custom_set_value = 0x07, 127 | id_custom_get_value = 0x08, 128 | id_custom_save = 0x09, 129 | ... 130 | } 131 | ``` 132 | 133 | The "arguments" for these commands have changed between VIA Protocol 10 and VIA Protocol 11. 134 | 135 | In VIA Protocol 10, the `id_lighting_set_value` and `id_lighting_get_value` commands were followed by the ID of the value to set/get (which could be of enum `via_lighting_value`), then followed by the value data. 136 | 137 | In VIA Protocol 11, the `id_custom_set_value` and `id_custom_get_value` commands are followed by a `channel_id`, then followed by the ID of the value to set/get, which could be of: 138 | 139 | - enum `via_qmk_backlight_value` 140 | - enum `via_qmk_rgblight_value` 141 | - enum `via_qmk_rgb_matrix_value` 142 | - enum `via_qmk_audio_value` 143 | - enums for other features in QMK 144 | - enums defined at the keyboard level 145 | 146 | `channel_id` serves two main purposes. 147 | 148 | First, it acts as a qualifier to `value_id`, allowing multiple enums with overlapping integer ranges to be used, rather than a single enum that must be the superset of all values for all features, which was a limitation of VIA Protocol 10. This makes it modular and extendable. When a new feature is added to QMK which could be controlled by VIA, a new default `channel_id` value can be defined, a new enum of possible `value_id` can be defined, set/get value command handlers implemented, and default UI defined in VIA, all without affecting the existing ID ranges and command handlers. 149 | 150 | Secondly, it supports easy routing of set/get value commands for a feature to appropriate handlers for that feature. This allows firmware authors to easily use any of the default handlers with no extra coding required, and optionally use `channel_id` value to route some commands to the default handler, and some commands to a custom handler at the keyboard level. For example, a keyboard with RGB lighting and an OLED display can use the default handler for QMK RGBLIGHT, and route commands for OLED control to a custom handler at the keyboard level. 151 | 152 | In the VIA keyboard definition, when defining UI controls in the `menu` element, each UI control has a `content` element which binds that control to a `channel_id` and `value_id`. 153 | 154 | ```json 155 | "label": "Backlight", 156 | "content": [ 157 | { 158 | "label": "Brightness", 159 | "type": "range", 160 | "options": [0, 255], 161 | "content": ["id_qmk_rgb_matrix_brightness", 3, 1] 162 | }, 163 | ``` 164 | 165 | In this example, `3` is the `channel_id` (which matches the channel in QMK) and `1` matches enum value `id_qmk_rgb_matrix_brightness` in enum `via_qmk_rgb_matrix_value`. The string `"id_qmk_rgb_matrix_brightness"` is the `value_key`, used by VIA as a unique key. 166 | 167 | ### Keyboard Values 168 | 169 | Keyboard values are used for getting/setting core VIA features like layout options. In VIA Protocol 11, two new values were added: 170 | 171 | ```c 172 | enum via_keyboard_value_id { 173 | ... 174 | id_firmware_version = 0x04, 175 | id_device_indication = 0x05 176 | }; 177 | ``` 178 | 179 | `id_firmware_version` is used to get the firmware version, see #Firmware Versioning. It returns `VIA_FIRMWARE_VERSION` to VIA, for use in ensuring a match between the VIA keyboard definition and the firmware's handling of custom UI (aka. the `menus` element). 180 | 181 | `id_device_indication` is set by VIA to allow the device to indicate that it is being configured. This is a refactoring of how VIA V2 would cause a keyboard with RGB backlighting to flash on/off when it became the keyboard being configured, which was done by sending `id_lighting_set_value` commands. This feature was refactored to be device agnostic. The default handler `via_set_device_indication()` will toggle any enabled QMK lighting feature and/or trigger audio playback. It can be overridden and customized at the keyboard level. 182 | -------------------------------------------------------------------------------- /docs/whats_new.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: whats_new 3 | title: What's New 4 | --- 5 | 6 | # VIA Nº3 7 | 8 | ![cubey](/img/whats_new/cubey.png) 9 | 10 | The VIA team is pleased to announce a new release of VIA. 11 | 12 | ## New UI 13 | 14 | ### 3D Mode 15 | 16 | Olivia, Binary Artisan and queen of rose gold, has refactored the entire UI engine to deliver keyboard configuration in glorious 3D. 17 | 18 | ![VIA 3D](/img/whats_new/via_3d.png) 19 | 20 | ### 2D Mode 21 | 22 | Such is Olivia's benevolence, she has also blessed the potato-users who dwell among us with a new 2D mode that is as attractive as it is performant. 23 | 24 | ![VIA 2D](/img/whats_new/via_2d.png) 25 | 26 | ### Themes 27 | 28 | You can now choose a visual theme to suit your unique aesthetic. More themes to follow! 29 | 30 | ## Better macro support 31 | 32 | ### Macro recording 33 | 34 | Just as a treat, Olivia has implemented a new macro recording feature that records what you type. 35 | 36 | ![Macro recording](/img/whats_new/macro_recorder.png) 37 | 38 | ### Delays 39 | 40 | Now you can add delays to macros. Either choose "record delays" when recording a macro, or insert using the script editor. 41 | 42 | Note: using delays in macros requires compatible firmware. You may need to install the latest firmware on your keyboard to use this feature. 43 | 44 | ### Visualise your macro memory 45 | 46 | A handy indicator now actually tells you how much of your macro memory you're consuming. 47 | 48 | ## Beep boops 49 | 50 | One of the unfortunate side-effects of porting VIA to the web was the heart-breaking loss of sounds in the key tester. 51 | 52 | No longer will your key testing be a silent, joyless experience. We've recovered the beeps and we've embiggened the boops. Why buy a heavy, expensive vintage Moog when you can just fire up VIA and use your marginally lighter and marginally cheaper custom keyboard instead? 53 | 54 | ![Beep boop](/img/whats_new/key_tester.png) 55 | 56 | ## Designers 57 | 58 | ### Persistent draft definitions 59 | 60 | Draft definitions loaded using the design tab now persist across sessions, so you no longer need to load your draft definition every time you hit the site while developing your new keyboard. 61 | 62 | ### V3 Definitions 63 | 64 | V3 VIA definitions give designers the flexibility to create a custom UI to control their keyboard's custom features. 65 | 66 | [See the full list of V3 definition changes](v3_changes) 67 | 68 | ## Discord 69 | 70 | [We have a new Discord server!](https://discord.gg/NStTR5YaPB) 71 | -------------------------------------------------------------------------------- /docusaurus.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: "VIA", 3 | tagline: "Your keyboard's best friend", 4 | url: "https://caniusevia.com", 5 | baseUrl: "/", 6 | organizationName: "the-via", // Usually your GitHub org/user name. 7 | projectName: "keyboards", // Usually your repo name. 8 | themeConfig: { 9 | twitterImage: "img/icon.png", 10 | ogImage: "img/icon.png", 11 | navbar: { 12 | title: "VIA", 13 | logo: { 14 | alt: "VIA", 15 | src: "img/icon.png", 16 | }, 17 | items: [ 18 | { 19 | href: "https://www.usevia.app", 20 | label: "Try Now!", 21 | position: "left", 22 | }, 23 | { to: "docs/whats_new", label: "What's New", position: "left" }, 24 | { 25 | to: "docs/supported_keyboards", 26 | label: "Supported Keyboards", 27 | position: "left", 28 | }, 29 | { to: "docs/specification", label: "Docs", position: "left" }, 30 | { to: "docs/download_firmware", label: "Firmware", position: "left" }, 31 | { 32 | href: "https://discord.gg/NStTR5YaPB", 33 | label: "Discord", 34 | position: "right", 35 | }, 36 | { 37 | href: "https://github.com/the-via", 38 | label: "GitHub", 39 | position: "right", 40 | }, 41 | ], 42 | }, 43 | footer: { 44 | style: "dark", 45 | links: [], 46 | copyright: "Built with ❤️ from the VIA team.", 47 | }, 48 | }, 49 | presets: [ 50 | [ 51 | "@docusaurus/preset-classic", 52 | { 53 | docs: { 54 | sidebarPath: require.resolve("./sidebars.js"), 55 | }, 56 | theme: { 57 | customCss: require.resolve("./src/css/custom.css"), 58 | }, 59 | }, 60 | ], 61 | ], 62 | }; 63 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "caniusevia", 3 | "version": "0.1.0", 4 | "private": true, 5 | "engines": { 6 | "node": ">=18" 7 | }, 8 | "scripts": { 9 | "start": "docusaurus start", 10 | "build": "node scripts/generate-dynamic-content.js && docusaurus build && via-keyboards build", 11 | "swizzle": "docusaurus swizzle", 12 | "deploy": "docusaurus deploy", 13 | "build-azure": "npm uninstall via-keyboards && npm i --save-dev https://github.com/the-via/keyboards.git && npm run build" 14 | }, 15 | "dependencies": { 16 | "@docusaurus/core": "^2.3.1", 17 | "@docusaurus/preset-classic": "^2.3.1", 18 | "@the-via/reader": "^1.6.0", 19 | "classnames": "^2.3.2", 20 | "js-file-download": "^0.4.12", 21 | "json-stringify-pretty-compact": "^4.0.0", 22 | "react": "^17.0.0", 23 | "react-dom": "^17.0.0", 24 | "via-keyboards": "github:the-via/keyboards" 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | }, 38 | "devDependencies": { 39 | "handlebars": "^4.7.7", 40 | "node-fetch": "^2.6.9" 41 | }, 42 | "packageManager": "yarn@4.7.0" 43 | } 44 | -------------------------------------------------------------------------------- /scripts/generate-dynamic-content.js: -------------------------------------------------------------------------------- 1 | const fetch = require("node-fetch"); 2 | const fs = require("fs"); 3 | const Handlebars = require("handlebars"); 4 | 5 | const transformFirmware = (fw) => 6 | fw.tree.filter(({ path }) => /\.(bin|hex|uf2)/.test(path)); 7 | 8 | const transformKeyboards = (kbs) => 9 | kbs.sort((a, b) => 10 | a.localeCompare(b, "en", undefined, { sensitivity: "base" }) 11 | ); 12 | 13 | const generateContent = async (url, transform, fileName) => { 14 | const content = await (await fetch(url)).json(); 15 | const templatedContent = Handlebars.compile( 16 | fs.readFileSync(`templates/${fileName}.hbs`, "utf-8") 17 | )({ date: new Date().toLocaleDateString(), content: transform(content) }); 18 | fs.writeFileSync(`docs/${fileName}.mdx`, templatedContent); 19 | }; 20 | 21 | [ 22 | [ 23 | "https://api.github.com/repos/the-via/firmware/git/trees/master", 24 | transformFirmware, 25 | "download_firmware", 26 | ], 27 | [ 28 | "https://www.usevia.app/definitions/keyboard_names.json", 29 | transformKeyboards, 30 | "supported_keyboards", 31 | ], 32 | ].forEach((args) => generateContent(...args)); 33 | -------------------------------------------------------------------------------- /sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | module.exports = { 9 | someSidebar: { 10 | Specification: [ 11 | "specification", 12 | "configuring_qmk", 13 | "layouts", 14 | { "Custom UI": ["custom_ui", "built_in_menus"] }, 15 | ], 16 | Appendix: ["supported_keyboards", "download_firmware"], 17 | "VIA Version 3": ["v3_changes"], 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #c398a8; 10 | --ifm-color-primary-dark: #b68295; 11 | --ifm-color-primary-darker: #b0778c; 12 | --ifm-color-primary-darkest: #995971; 13 | --ifm-color-primary-light: #d0aebb; 14 | --ifm-color-primary-lighter: #d6b9c4; 15 | --ifm-color-primary-lightest: #e9dae0; 16 | --ifm-code-font-size: 95%; 17 | --ifm-footer-padding-vertical: 0.5rem; 18 | --ifm-code-background: var(--ifm-color-gray-300); 19 | } 20 | 21 | [data-theme="dark"] { 22 | --ifm-code-background: var(--ifm-color-gray-800); 23 | } 24 | 25 | .docusaurus-highlight-code-line { 26 | background-color: rgb(72, 77, 91); 27 | display: block; 28 | margin: 0 calc(-1 * var(--ifm-pre-padding)); 29 | padding: 0 var(--ifm-pre-padding); 30 | } 31 | -------------------------------------------------------------------------------- /src/keyboard-names.json: -------------------------------------------------------------------------------- 1 | [ 2 | "aanzee", 3 | "AEboards AEGIS", 4 | "AEboards Ext65", 5 | "Snagpad", 6 | "PLAIN60", 7 | "Noxary 268.2", 8 | "PRIME_E", 9 | "RAMA WORKS M6-A", 10 | "RAMA WORKS M6-B", 11 | "RAMA WORKS M10-B", 12 | "RAMA WORKS M60-A", 13 | "RAMA WORKS M65-B", 14 | "RAMA WORKS U80-A", 15 | "RAMA WORKS KOYU", 16 | "romac", 17 | "OSA", 18 | "Uni660", 19 | "ZEAL60", 20 | "ZEAL65", 21 | "IDB 60", 22 | "Leaf 60", 23 | "WT8-A", 24 | "WT60-A", 25 | "WT60-D", 26 | "WT65-A", 27 | "WT65-B", 28 | "WT69-A", 29 | "WT75-A", 30 | "WT75-B", 31 | "WT75-C", 32 | "WT80-A", 33 | "BIOI G60", 34 | "HS60 ISO", 35 | "HS60 ANSI", 36 | "HS60 HHKB", 37 | "NK65", 38 | "Lunar", 39 | "Equinox", 40 | "is0", 41 | "Instant60", 42 | "Satisfaction75", 43 | "AN-C", 44 | "Chimera65", 45 | "IRIS", 46 | "E6.5" 47 | ] -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import classnames from "classnames"; 3 | import Layout from "@theme/Layout"; 4 | import Link from "@docusaurus/Link"; 5 | import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; 6 | import useBaseUrl from "@docusaurus/useBaseUrl"; 7 | import styles from "./styles.module.css"; 8 | import Head from "@docusaurus/Head"; 9 | 10 | function VIALogo(props) { 11 | return ( 12 | 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | ); 30 | } 31 | 32 | const features = [ 33 | { 34 | title: <>Simple, 35 | imageUrl: "img/undraw_walking_around.svg", 36 | description: <>Plug in your keyboard. It's that easy., 37 | callToAction: "Start Now", 38 | callToActionUrl: "https://www.usevia.app", 39 | }, 40 | { 41 | title: <>Friendly, 42 | imageUrl: "img/undraw_different_love.svg", 43 | description: ( 44 | <> 45 | Compatible with 1400+ keyboards and easily added to other QMK keyboards. 46 | 47 | ), 48 | callToAction: "Check compatibility", 49 | callToActionUrl: "/docs/supported_keyboards", 50 | }, 51 | { 52 | title: <>Helpful, 53 | imageUrl: "img/undraw_game_world.svg", 54 | description: ( 55 | <> 56 | Configure, test and design in one place - VIA is the last application 57 | you'll need for your keyboard. 58 | 59 | ), 60 | callToAction: "Read the docs", 61 | callToActionUrl: "/docs/specification", 62 | }, 63 | ]; 64 | 65 | function Feature({ 66 | imageUrl, 67 | title, 68 | description, 69 | callToAction, 70 | callToActionUrl, 71 | }) { 72 | const imgUrl = useBaseUrl(imageUrl); 73 | return ( 74 |
75 | {imgUrl && ( 76 |
77 | {title} 78 |
79 | )} 80 |

{title}

81 |

{description}

82 |
83 | 90 | {callToAction} 91 | 92 |
93 |
94 | ); 95 | } 96 | 97 | function Home() { 98 | const context = useDocusaurusContext(); 99 | const { siteConfig = {} } = context; 100 | const seoURL = "https://caniusevia.com/img/icon.png"; 101 | return ( 102 | <> 103 | 104 | 105 | 106 | 111 | 117 | 123 | 124 | 125 | 126 | 127 | 128 | 132 |
133 |
134 | 135 |

{siteConfig.tagline}

136 |
137 |
138 |
139 | {features && features.length && ( 140 |
141 |
142 |
143 | {features.map((props, idx) => ( 144 | 145 | ))} 146 |
147 |
148 |
149 | )} 150 |
151 |
152 | 153 | ); 154 | } 155 | 156 | export default Home; 157 | -------------------------------------------------------------------------------- /src/pages/styles.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | } 12 | 13 | @media screen and (max-width: 966px) { 14 | .heroBanner { 15 | padding: 2rem; 16 | } 17 | } 18 | 19 | :global(.hero__title) { 20 | font-weight: 400; 21 | font-size: 5rem !important; 22 | } 23 | 24 | :global(.hero__title) span { 25 | font-style: oblique; 26 | } 27 | 28 | .buttons { 29 | display: flex; 30 | align-items: center; 31 | justify-content: center; 32 | } 33 | 34 | .features { 35 | display: flex; 36 | align-items: center; 37 | padding: 2rem 0; 38 | width: 100%; 39 | } 40 | 41 | .featureImage { 42 | height: 150px; 43 | width: 175px; 44 | } 45 | 46 | .featureButton { 47 | display: flex; 48 | justify-content: center; 49 | margin-bottom: calc(var(--ifm-paragraph-margin-bottom) * 1.5); 50 | } 51 | -------------------------------------------------------------------------------- /static/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/android-chrome-192x192.png -------------------------------------------------------------------------------- /static/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/android-chrome-512x512.png -------------------------------------------------------------------------------- /static/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/apple-touch-icon.png -------------------------------------------------------------------------------- /static/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/favicon-16x16.png -------------------------------------------------------------------------------- /static/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/favicon-32x32.png -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/favicon.ico -------------------------------------------------------------------------------- /static/img/custom_ui_button_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/custom_ui_button_control.png -------------------------------------------------------------------------------- /static/img/custom_ui_color_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/custom_ui_color_control.png -------------------------------------------------------------------------------- /static/img/custom_ui_dropdown_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/custom_ui_dropdown_control.png -------------------------------------------------------------------------------- /static/img/custom_ui_keycode_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/custom_ui_keycode_control.png -------------------------------------------------------------------------------- /static/img/custom_ui_range_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/custom_ui_range_control.png -------------------------------------------------------------------------------- /static/img/custom_ui_toggle_control.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/custom_ui_toggle_control.png -------------------------------------------------------------------------------- /static/img/custom_ui_top_level_menus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/custom_ui_top_level_menus.png -------------------------------------------------------------------------------- /static/img/encoder-with-push.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/encoder-with-push.png -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/favicon.ico -------------------------------------------------------------------------------- /static/img/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/icon.png -------------------------------------------------------------------------------- /static/img/just-encoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/just-encoder.png -------------------------------------------------------------------------------- /static/img/optional-encoder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/optional-encoder.png -------------------------------------------------------------------------------- /static/img/result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/result.png -------------------------------------------------------------------------------- /static/img/split_backspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/split_backspace.png -------------------------------------------------------------------------------- /static/img/switch_matrix_coordinates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/switch_matrix_coordinates.png -------------------------------------------------------------------------------- /static/img/undraw_different_love.svg: -------------------------------------------------------------------------------- 1 | different love -------------------------------------------------------------------------------- /static/img/undraw_game_world.svg: -------------------------------------------------------------------------------- 1 | game_world -------------------------------------------------------------------------------- /static/img/undraw_walking_around.svg: -------------------------------------------------------------------------------- 1 | walking around -------------------------------------------------------------------------------- /static/img/whats_new/cubey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/whats_new/cubey.png -------------------------------------------------------------------------------- /static/img/whats_new/key_tester.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/whats_new/key_tester.png -------------------------------------------------------------------------------- /static/img/whats_new/macro_recorder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/whats_new/macro_recorder.png -------------------------------------------------------------------------------- /static/img/whats_new/via_2d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/whats_new/via_2d.png -------------------------------------------------------------------------------- /static/img/whats_new/via_3d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/whats_new/via_3d.png -------------------------------------------------------------------------------- /static/img/wt60_d_layout_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/img/wt60_d_layout_options.png -------------------------------------------------------------------------------- /static/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/mstile-144x144.png -------------------------------------------------------------------------------- /static/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/mstile-150x150.png -------------------------------------------------------------------------------- /static/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/mstile-310x150.png -------------------------------------------------------------------------------- /static/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/mstile-310x310.png -------------------------------------------------------------------------------- /static/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/the-via/website/c816784b7788a2122ebcbc0046fbe0ffa0a07878/static/mstile-70x70.png -------------------------------------------------------------------------------- /static/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /static/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /staticwebapp.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "routes": [ 3 | { 4 | "route": "/keyboard_names.json", 5 | "headers": { 6 | "cache-control": "public, max-age=604800" 7 | } 8 | }, 9 | { 10 | "route": "/*.js", 11 | "headers": { 12 | "cache-control": "public, max-age=604800" 13 | } 14 | }, 15 | { 16 | "route": "/*.css", 17 | "headers": { 18 | "cache-control": "public, max-age=604800" 19 | } 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /templates/download_firmware.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | id: download_firmware 3 | title: Firmware Downloads 4 | sidebar_label: Firmware Downloads 5 | description: Precompiled QMK firmware for VIA-supported keyboards 6 | keywords: 7 | - via 8 | - qmk 9 | - firmware 10 | --- 11 | 12 | import * as fileDownload from "js-file-download"; 13 | const downloadText = (url, filename) => 14 | fetch(url) 15 | .then((response) => response.text()) 16 | .then((text) => fileDownload(text, filename)); 17 | 18 | export const Download = ({ filename }) => { 19 | const url = `https://raw.githubusercontent.com/the-via/firmware/master/${filename}`; 20 | const isHex = filename.endsWith(".hex"); 21 | const href = isHex ? "#0" : url; 22 | const handleClick = isHex ? () => downloadText(url, filename) : undefined; 23 | return ( 24 |
  • 25 | 26 | {filename} 27 | 28 |
  • 29 | ); 30 | }; 31 | 32 | Last updated: {{date}} 33 | 34 |
      35 | {{#content}} 36 | 37 | {{/content}} 38 |
    -------------------------------------------------------------------------------- /templates/supported_keyboards.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | id: supported_keyboards 3 | title: Supported Keyboards 4 | sidebar_label: Supported Keyboards 5 | --- 6 | 7 | | Compatible as of {{date}} | 8 | | ----------------------------------- | 9 | {{#content}} 10 | | {{this}} | 11 | {{/content}} --------------------------------------------------------------------------------