├── .gitattributes ├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.sh ├── src ├── _example.json ├── asus-gamepad.json ├── gamecube.json ├── hyperkin-duke.json ├── nintendo-joy-con.json ├── nintendo-switch-pro.json ├── playstation-3.json ├── playstation-4.json ├── playstation-5.json ├── saturn-digital-pad.json ├── steam-deck.json ├── xbox-360.json └── xbox-one.json ├── symbols.json └── www ├── _button.html.hbs ├── bean-left.svg ├── bean-right.svg ├── build.js ├── bumper-left.svg ├── bumper-right.svg ├── circle-inner.svg ├── circle-medium.svg ├── circle.svg ├── index.html.hbs ├── long-triangle-right.svg ├── lozenge-curved-horizontal.svg ├── lozenge-curved-vertical.svg ├── lozenge-horizontal.svg ├── lozenge-vertical.svg ├── package-lock.json ├── package.json ├── playstation.svg ├── radiate.svg ├── rectangle.svg ├── square.svg ├── stick-down.svg ├── triangle.svg ├── trigger-left.svg ├── trigger-right.svg ├── view.svg ├── xbox-original.svg └── xbox-swish.svg /.gitattributes: -------------------------------------------------------------------------------- 1 | *.json linguist-detectable 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: "autobuild" 2 | 3 | on: 4 | push: 5 | branches: 6 | - trunk 7 | 8 | jobs: 9 | build: 10 | name: Build 11 | 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Build 19 | run: | 20 | ./build.sh 21 | - name: Create release 22 | uses: marvinpinto/action-automatic-releases@latest 23 | with: 24 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 25 | automatic_release_tag: "latest" 26 | prerelease: false 27 | title: "Latest Build" 28 | files: dist/* 29 | - name: Create page 30 | run: | 31 | cd www 32 | npm i 33 | node build.js 34 | rm -rf node_modules 35 | - name: Upload pages artifact 36 | uses: actions/upload-pages-artifact@v1 37 | with: 38 | path: 'www' 39 | deploy: 40 | name: Deploy pages 41 | 42 | needs: build 43 | 44 | permissions: 45 | pages: write 46 | id-token: write 47 | 48 | environment: 49 | name: github-pages 50 | url: ${{ steps.deployment.outputs.page_url }} 51 | 52 | runs-on: ubuntu-latest 53 | steps: 54 | - name: Deploy pages 55 | uses: actions/deploy-pages@v1.2.1 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /www/index.html 3 | /www/node_modules 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | zlib License 2 | 3 | (C) 2022 Una Thompson (unascribed) 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 2. Altered source versions must be plainly marked as such, and must not be 18 | misrepresented as being the original software. 19 | 3. This notice may not be removed or altered from any source distribution. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Symbolic Controller DB 2 | 3 | The [SDL controller DB](https://github.com/gabomdq/SDL_GameControllerDB) 4 | provides useful abstract descriptions of *where* buttons are and how 5 | controllers behave, but hammers them all into the terminology of an Xbox 6 | 360 controller. 7 | 8 | Showing users inputs on their controller using only the SDL DB is a 9 | poor and messy experience for users and developers alike. 10 | 11 | What if we had a free database of what controllers *look* like, in 12 | addition to how they're shaped and interfaced with? 13 | 14 | This database is offered under the same permissive license as the 15 | SDL controller DB it's designed to be used alongside; the zlib 16 | license. Your obligations using this database are the same as using the 17 | SDL database. 18 | 19 | ## Contributing 20 | 21 | You will need to know the SDL GUIDs of your controller, such as 05000000050b00000045000040000000. 22 | Create a file at e.g. `src/asus-gamepad.json` describing the controller. The 23 | filename is not included in the release JSON; it's just an identifier during 24 | authoring. Check `src/_example.json` for the general structure. 25 | 26 | See [symbols.json](symbols.json) for an iteration of all currently defined 27 | symbolic colors and buttons, and their default values. 28 | 29 | Pull requests very welcome. A database like this is only as useful as the 30 | number of controllers it describes. 31 | 32 | Not sure how to write the needed JSON file? Open an issue with the SDL GUID 33 | of your controller and a picture of it from the relevant angles; from in front 34 | and above, on most controllers. If the controller is designed for some 35 | specific software or console, also include information on how its buttons 36 | are displayed there. 37 | 38 | ## Usage 39 | 40 | Unlike the SDL DB, this DB is not tied to a particular software project; 41 | the "reference library" is the implementation of this in unvkit, my 2D 42 | Java game engine that uses GLFW. But this is not the "one true library". 43 | Also available is `www/build.js` in this repo, which creates the 44 | [demo web page](https://unascribed.github.io/SymbolicControllerDB/). 45 | 46 | Under Releases, a merged JSON file containing an array of every defined 47 | controller with comments removed is offered. The structure is, roughly: 48 | 49 | ```js 50 | { 51 | "controllers": [ 52 | { 53 | // controller definition like those in src 54 | "name": "Foo Bar Inc. Gameius Padius", 55 | "guids": [ 56 | "01234567890123456789012345678901", 57 | "12345678901234567890123456789012" 58 | ], 59 | "conventions": { 60 | // key is arbitrary, value is SDL name 61 | "accept": "a", 62 | "back": "b" 63 | }, 64 | "buttons": { 65 | // key is SDL name 66 | "a": { 67 | // all values are as defined in symbols 68 | "type": "A", 69 | "bg": "white", 70 | "fg": "purple" 71 | } 72 | // ... 73 | } 74 | // _comment keys are removed and string buttons are resolved 75 | } 76 | ], 77 | "symbols": { 78 | // the contents of symbols.json with _comment keys removed, e.g. 79 | "power": { 80 | "shape": "circle", 81 | "icon": "power", 82 | "text": "⏻", 83 | "text_basic": "Power" 84 | } 85 | } 86 | } 87 | ``` 88 | 89 | ## Prior Art 90 | 91 | I am aware of [cxong/SDL_JoystickButtonNames](https://github.com/cxong/SDL_JoystickButtonNames), 92 | but it has few controllers and I disagree with its design decisions. The 93 | choice to always describe buttons textually rather than symbolically causes 94 | confusion between e.g. X and Cross buttons, and doesn't provide room for 95 | icons. Additionally, its explicit RGB values are hard to make mesh with 96 | a dark design. 97 | 98 | It also does not explain whether the colors are the color of the button, or 99 | the legend. This database describes everything symbolically, giving the UI 100 | designer complete freedom of how to draw the icons, and the freedom to 101 | choose colors that mesh best with their design. 102 | 103 | Additionally, the SDL DB format is hard to read, is very poor for authoring, 104 | and is highly prone to merge conflicts. This repo chooses one JSON file per 105 | controller as an authoring format. 106 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p dist 4 | ( 5 | echo '{"controllers":[' 6 | first=1 7 | for j in src/*.json; do 8 | b="$(basename "$j" .json)" 9 | if [ "$b" == "_example" ]; then 10 | continue 11 | fi 12 | 13 | if [ "$first" == "1" ]; then 14 | first=0 15 | else 16 | echo ',' 17 | fi 18 | jq -M '.name as $name|.guids as $guids|.conventions as $conventions|[.bg as $defBg|.fg as $defFg|.buttons|keys[] as $k|.[$k] as {$type,$bg,$fg} ?// $type|{key:($k),value:{type:($type),bg:($bg // $defBg),fg:($fg // $defFg)}}]|from_entries|{name:$name,guids:$guids,conventions:$conventions,buttons:.}' "$j" 19 | done 20 | echo '],"symbols":' 21 | cat symbols.json 22 | echo '}' 23 | ) | jq -acM 'del(..|.["_comment"]?)' > dist/symboliccontrollerdb.json 24 | -------------------------------------------------------------------------------- /src/_example.json: -------------------------------------------------------------------------------- 1 | { 2 | "_comment": "The name a user would expect this controller to be referred to as - usually duplicates the SDL controller DB", 3 | "name": "ASUS Gamepad", 4 | 5 | "_comment": "Every matching SDL Controller DB GUID. One controller generally has different GUIDs on different platforms.", 6 | "guids": [ 7 | "03000000050b00000045000031000000", 8 | "05000000050b00000045000031000000", 9 | "05000000050b00000045000040000000" 10 | ], 11 | 12 | "_comment": "The default bg/fg color for buttons that don't define it. Not present in the release JSON file.", 13 | "bg": "black", 14 | "fg": "white", 15 | 16 | "_comment": "This specifies the most commonly used accept and back/cancel buttons for this controller, using SDL names.", 17 | "conventions": { 18 | "accept": "a", 19 | "back": "b" 20 | }, 21 | 22 | "_comment": [ 23 | "Visual descriptions of the SDL buttons. Keys are the SDL button name.", 24 | "Values can either be a string or an object. A string is equivalent to an object that only defines 'type'.", 25 | "Strings will never be seen in the release JSON files — they're resolved by the build script." 26 | ], 27 | "buttons": { 28 | "_comment": [ 29 | "The ASUS Gamepad uses a typical Xbox 360-like layout for its primary button cluster.", 30 | "However, unlike the Xbox 360 controller, the buttons are black with colored legends.", 31 | "The 360 controller has colored buttons with embossed legends." 32 | ], 33 | "a": { 34 | "_comment": [ 35 | "See symbols.json for the valid choices here.", 36 | "bg is the color of the button itself, fg is the color of the legend.", 37 | "All of these are symbolic names to allow customization." 38 | ], 39 | "type": "A", 40 | "bg": "black", 41 | "fg": "green" 42 | }, 43 | "b": { 44 | "type": "B", 45 | "bg": "black", 46 | "fg": "red" 47 | }, 48 | "x": { 49 | "type": "X", 50 | "bg": "black", 51 | "fg": "blue" 52 | }, 53 | "y": { 54 | "type": "Y", 55 | "bg": "black", 56 | "fg": "yellow" 57 | }, 58 | 59 | "_comment": [ 60 | "The ASUS Gamepad's bumpers and triggers are completely unlabelled.", 61 | "They're equivalent to the 360 buttons, however, so we map them as such." 62 | ], 63 | "leftshoulder": "LB", 64 | "rightshoulder": "RB", 65 | "lefttrigger": "LT", 66 | "righttrigger": "RT", 67 | "leftstick": "LS", 68 | "rightstick": "RS", 69 | 70 | "_comment": "The D-Pad looks like a PlayStation gamepad. See symbols.json for a further description.", 71 | "dpup": "dpad_inward_up", 72 | "dpdown": "dpad_inward_down", 73 | "dpleft": "dpad_inward_left", 74 | "dpright": "dpad_inward_right", 75 | 76 | "guide": "power", 77 | "back": "arrow_left", 78 | "start": "circle" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/asus-gamepad.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ASUS Gamepad", 3 | "guids": [ 4 | "03000000050b00000045000031000000", 5 | "05000000050b00000045000031000000", 6 | "05000000050b00000045000040000000" 7 | ], 8 | "bg": "black", 9 | "fg": "white", 10 | "conventions": { 11 | "accept": "a", 12 | "back": "b" 13 | }, 14 | "buttons": { 15 | "a": { 16 | "type": "A", 17 | "bg": "black", 18 | "fg": "green" 19 | }, 20 | "b": { 21 | "type": "B", 22 | "bg": "black", 23 | "fg": "red" 24 | }, 25 | "x": { 26 | "type": "X", 27 | "bg": "black", 28 | "fg": "blue" 29 | }, 30 | "y": { 31 | "type": "Y", 32 | "bg": "black", 33 | "fg": "yellow" 34 | }, 35 | "leftshoulder": "LB", 36 | "rightshoulder": "RB", 37 | "lefttrigger": "LT", 38 | "righttrigger": "RT", 39 | "dpup": "dpad_inward_up", 40 | "dpdown": "dpad_inward_down", 41 | "dpleft": "dpad_inward_left", 42 | "dpright": "dpad_inward_right", 43 | "leftstick": "LS", 44 | "rightstick": "RS", 45 | "guide": "power", 46 | "back": "arrow_left", 47 | "start": "circle" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/gamecube.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Nintendo GameCube Controller", 3 | "guids": [ 4 | "03000000260900008888000000000000", 5 | "03000000260900002625000000000000", 6 | "03000000341a000005f7000000000000", 7 | "03000000430b00000500000000000000", 8 | "03000000790000004718000000000000", 9 | "03000000790000004618000000000000", 10 | "03000000790000004418000000000000", 11 | "03000000790000004318000000000000", 12 | "03000000790000004518000000000000", 13 | "03000000260900008888000088020000", 14 | "03000000790000004618000000010000", 15 | "03000000790000004318000000010000", 16 | "03000000790000004418000000010000", 17 | "03000000260900008888000000010000", 18 | "03000000341a000005f7000010010000", 19 | "03000000790000004318000010010000", 20 | "03000000790000004418000010010000", 21 | "03000000790000004518000010010000", 22 | "030000007e0500003703000000016800", 23 | "03000000790000004618000010010000", 24 | "6d6179666c617368206c696d69746564" 25 | ], 26 | "bg": "gray", 27 | "fg": "white", 28 | "conventions": { 29 | "accept": "a", 30 | "back": "x" 31 | }, 32 | "buttons": { 33 | "a": { 34 | "type": "A", 35 | "bg": "green", 36 | "fg": "green" 37 | }, 38 | "x": { 39 | "type": "gcn_B", 40 | "bg": "red", 41 | "fg": "red" 42 | }, 43 | "b": "gcn_X", 44 | "y": "gcn_Y", 45 | "rightshoulder": { 46 | "type": "gcn_Z", 47 | "bg": "purple", 48 | "fg": "pink" 49 | }, 50 | "lefttrigger": "gcn_L", 51 | "righttrigger": "gcn_R", 52 | "dpup": "dpad_cross_up", 53 | "dpdown": "dpad_cross_down", 54 | "dpleft": "dpad_cross_left", 55 | "dpright": "dpad_cross_right", 56 | "leftstick": "gcn_stick", 57 | "rightstick": { 58 | "type": "gcn_C", 59 | "bg": "orange", 60 | "fg": "yellow" 61 | }, 62 | "start": { 63 | "type": "gcn_start", 64 | "bg": "red", 65 | "fg": "white" 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/hyperkin-duke.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hyperkin Duke", 3 | "guids": [ 4 | "03000000242e00001816000001010000", 5 | "03000000242e00005206000001010000" 6 | ], 7 | "bg": "black", 8 | "fg": "white", 9 | "conventions": { 10 | "accept": "a", 11 | "back": "b" 12 | }, 13 | "buttons": { 14 | "a": { 15 | "type": "xb0_A", 16 | "bg": "green", 17 | "fg": "green" 18 | }, 19 | "b": { 20 | "type": "xb0_B", 21 | "bg": "red", 22 | "fg": "red" 23 | }, 24 | "x": { 25 | "type": "xb0_X", 26 | "bg": "blue", 27 | "fg": "blue" 28 | }, 29 | "y": { 30 | "type": "xb0_Y", 31 | "bg": "orange", 32 | "fg": "yellow" 33 | }, 34 | "leftshoulder": { 35 | "type": "xb0_white", 36 | "bg": "white", 37 | "fg": "black" 38 | }, 39 | "rightshoulder": { 40 | "type": "xb0_black", 41 | "bg": "black", 42 | "fg": "white" 43 | }, 44 | "lefttrigger": "LT", 45 | "righttrigger": "RT", 46 | "dpup": "dpad_up", 47 | "dpdown": "dpad_down", 48 | "dpleft": "dpad_left", 49 | "dpright": "dpad_right", 50 | "leftstick": "LS", 51 | "rightstick": "RS", 52 | "guide": { 53 | "type": "xb0_jewel", 54 | "bg": "black", 55 | "fg": "green" 56 | }, 57 | "back": "xb0_view", 58 | "start": "xb0_menu" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/nintendo-joy-con.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Nintendo Switch Joy-Con", 3 | "guids": [ 4 | "030000007e0500000620000000000000", 5 | "030000007e0500000720000000000000", 6 | "030000007e0500000620000001000000", 7 | "030000007e0500000720000001000000", 8 | "050000007e0500000620000001000000", 9 | "050000007e0500000720000001000000", 10 | "060000007e0500000620000000000000", 11 | "060000007e0500000820000000000000", 12 | "050000007e0500000620000001800000", 13 | "050000007e0500000720000001800000", 14 | "65346535636333663931613264643164", 15 | "33346566643039343630376565326335", 16 | "35313531613435623366313835326238", 17 | "4a6f792d436f6e20284c290000000000", 18 | "38383665633039363066383334653465", 19 | "39363561613936303237333537383931", 20 | "4a6f792d436f6e202852290000000000", 21 | "050000007e050000062000004f060000", 22 | "050000007e0500000e200000df070000", 23 | "050000007e050000072000004f060000" 24 | ], 25 | "bg": "black", 26 | "fg": "white", 27 | "conventions": { 28 | "accept": "b", 29 | "back": "a" 30 | }, 31 | "buttons": { 32 | "a": "B", 33 | "b": "A", 34 | "x": "Y", 35 | "y": "X", 36 | "leftshoulder": "nx_L", 37 | "rightshoulder": "nx_R", 38 | "lefttrigger": "nx_ZL", 39 | "righttrigger": "nx_ZR", 40 | "dpup": "dpad_circle_up", 41 | "dpdown": "dpad_circle_down", 42 | "dpleft": "dpad_circle_left", 43 | "dpright": "dpad_circle_right", 44 | "leftstick": "nx_LS", 45 | "rightstick": "nx_RS", 46 | "guide": "home", 47 | "back": "nx_minus", 48 | "start": "nx_plus" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/nintendo-switch-pro.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Nintendo Switch Pro Controller", 3 | "guids": [ 4 | "030000007e0500000920000000000000", 5 | "030000007e0500000920000001000000", 6 | "030000007e0500000920000011810000", 7 | "050000007e0500000920000001000000", 8 | "050000007e0500000920000001800000", 9 | "050000007e05000009200000ffff0f00", 10 | "34323437396534643531326161633738", 11 | "50726f20436f6e74726f6c6c65720000", 12 | "050000007e05000009200000ff870000" 13 | ], 14 | "bg": "black", 15 | "fg": "white", 16 | "conventions": { 17 | "accept": "b", 18 | "back": "a" 19 | }, 20 | "buttons": { 21 | "a": "B", 22 | "b": "A", 23 | "x": "Y", 24 | "y": "X", 25 | "leftshoulder": "nx_L", 26 | "rightshoulder": "nx_R", 27 | "lefttrigger": "nx_ZL", 28 | "righttrigger": "nx_ZR", 29 | "dpup": "dpad_cross_up", 30 | "dpdown": "dpad_cross_down", 31 | "dpleft": "dpad_cross_left", 32 | "dpright": "dpad_cross_right", 33 | "leftstick": "nx_LS", 34 | "rightstick": "nx_RS", 35 | "guide": "home", 36 | "back": "minus", 37 | "start": "plus" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/playstation-3.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PlayStation 3 Controller", 3 | "guids": [ 4 | "03000000317300000100000000000000", 5 | "030000004c0500006802000000000000", 6 | "030000004c0500006802000000010000", 7 | "030000004c0500006802000011810000", 8 | "030000004c050000cc09000011810000" 9 | ], 10 | "bg": "black", 11 | "fg": "white", 12 | "conventions": { 13 | "_comment": "This is swapped in Japan for the PS3 (they unified for PS4+) - games that use the DB should probably offer a 'Swap Accept/Back' option", 14 | "accept": "a", 15 | "back": "b" 16 | }, 17 | "buttons": { 18 | "a": { 19 | "type": "cross", 20 | "bg": "black", 21 | "fg": "blue" 22 | }, 23 | "b": { 24 | "type": "circle", 25 | "bg": "black", 26 | "fg": "pink" 27 | }, 28 | "x": { 29 | "type": "square", 30 | "bg": "black", 31 | "fg": "purple" 32 | }, 33 | "y": { 34 | "type": "triangle", 35 | "bg": "black", 36 | "fg": "green" 37 | }, 38 | "leftshoulder": "L1", 39 | "rightshoulder": "R1", 40 | "lefttrigger": "L2", 41 | "righttrigger": "R2", 42 | "dpup": "dpad_inward_up", 43 | "dpdown": "dpad_inward_down", 44 | "dpleft": "dpad_inward_left", 45 | "dpright": "dpad_inward_right", 46 | "leftstick": "L3", 47 | "rightstick": "R3", 48 | "guide": "PS", 49 | "back": "ps_back", 50 | "start": "ps_start" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/playstation-4.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PlayStation 4 Controller", 3 | "guids": [ 4 | "030000004c050000a00b000000000000", 5 | "030000004c050000cc09000000000000", 6 | "050000004c050000cc09000001000000", 7 | "03000000120c00000807000000000000", 8 | "03000000120c0000111e000000000000", 9 | "03000000120c0000121e000000000000", 10 | "03000000120c0000130e000000000000", 11 | "03000000120c0000150e000000000000", 12 | "03000000120c0000180e000000000000", 13 | "03000000120c0000181e000000000000", 14 | "03000000120c0000191e000000000000", 15 | "03000000120c00001e0e000000000000", 16 | "03000000120c0000a957000000000000", 17 | "03000000120c0000aa57000000000000", 18 | "03000000120c0000f21c000000000000", 19 | "03000000120c0000f31c000000000000", 20 | "03000000120c0000f41c000000000000", 21 | "03000000120c0000f51c000000000000", 22 | "03000000120c0000f70e000000000000", 23 | "03000000120e0000120c000000000000", 24 | "03000000160e0000120c000000000000", 25 | "030000001a1e0000120c000000000000", 26 | "030000004c050000a00b000000010000", 27 | "030000004c050000c405000000000000", 28 | "030000004c050000c405000000010000", 29 | "030000004c050000cc09000000010000", 30 | "030000004c050000a00b000011010000", 31 | "030000004c050000a00b000011810000", 32 | "030000004c050000c405000011010000", 33 | "030000004c050000c405000011810000", 34 | "030000004c050000cc09000011010000", 35 | "03000000c01100000140000011010000", 36 | "050000004c050000c405000000010000", 37 | "050000004c050000c405000000810000", 38 | "050000004c050000c405000001800000", 39 | "050000004c050000cc09000000010000", 40 | "050000004c050000cc09000000810000", 41 | "050000004c050000cc09000001800000", 42 | "050000004c050000c405000000783f00", 43 | "050000004c050000c4050000fffe3f00", 44 | "050000004c050000c4050000ffff3f00", 45 | "050000004c050000cc090000fffe3f00", 46 | "050000004c050000cc090000ffff3f00", 47 | "30303839663330346632363232623138", 48 | "31326235383662333266633463653332", 49 | "31373231336561636235613666323035", 50 | "31663838336334393132303338353963", 51 | "34613139376634626133336530386430", 52 | "35643031303033326130316330353564", 53 | "37626233336235343937333961353732", 54 | "38393161636261653636653532386639", 55 | "536f6e7920496e746572616374697665", 56 | "576972656c65737320436f6e74726f6c", 57 | "63313733393535663339656564343962", 58 | "63393662363836383439353064663939", 59 | "65366465656364636137653363376531", 60 | "66613532303965383534396638613230", 61 | "050000004c050000cc090000df070000", 62 | "050000004c050000cc090000df870001", 63 | "050000004c050000cc090000ff070000", 64 | "050000004c050000cc090000ff870001", 65 | "050000004c050000cc090000ff876d01" 66 | ], 67 | "bg": "black", 68 | "fg": "white", 69 | "conventions": { 70 | "accept": "a", 71 | "back": "b" 72 | }, 73 | "buttons": { 74 | "a": { 75 | "type": "cross", 76 | "bg": "black", 77 | "fg": "blue" 78 | }, 79 | "b": { 80 | "type": "circle", 81 | "bg": "black", 82 | "fg": "pink" 83 | }, 84 | "x": { 85 | "type": "square", 86 | "bg": "black", 87 | "fg": "purple" 88 | }, 89 | "y": { 90 | "type": "triangle", 91 | "bg": "black", 92 | "fg": "green" 93 | }, 94 | "leftshoulder": "L1", 95 | "rightshoulder": "R1", 96 | "lefttrigger": "L2", 97 | "righttrigger": "R2", 98 | "dpup": "dpad_inward_up", 99 | "dpdown": "dpad_inward_down", 100 | "dpleft": "dpad_inward_left", 101 | "dpright": "dpad_inward_right", 102 | "leftstick": "L3", 103 | "rightstick": "R3", 104 | "guide": "PS", 105 | "back": "ps4_share", 106 | "start": "ps4_options" 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/playstation-5.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PlayStation 5 Controller", 3 | "guids": [ 4 | "030000004c050000e60c000000000000", 5 | "030000004c050000e60c000000010000", 6 | "050000004c050000e60c000000010000", 7 | "030000004c050000e60c000011010000", 8 | "030000004c050000e60c000011810000", 9 | "050000004c050000e60c000000810000", 10 | "050000004c050000e60c0000fffe3f00", 11 | "32346465346533616263386539323932", 12 | "32633532643734376632656664383733", 13 | "37363764353731323963323639666565", 14 | "61303162353165316365336436343139", 15 | "050000004c050000e60c0000df870000", 16 | "050000004c050000e60c0000ff870000" 17 | ], 18 | "bg": "black", 19 | "fg": "white", 20 | "conventions": { 21 | "accept": "a", 22 | "back": "b" 23 | }, 24 | "buttons": { 25 | "a": { 26 | "type": "cross", 27 | "bg": "black", 28 | "fg": "blue" 29 | }, 30 | "b": { 31 | "type": "circle", 32 | "bg": "black", 33 | "fg": "pink" 34 | }, 35 | "x": { 36 | "type": "square", 37 | "bg": "black", 38 | "fg": "purple" 39 | }, 40 | "y": { 41 | "type": "triangle", 42 | "bg": "black", 43 | "fg": "green" 44 | }, 45 | "leftshoulder": "L1", 46 | "rightshoulder": "R1", 47 | "lefttrigger": "L2", 48 | "righttrigger": "R2", 49 | "dpup": "dpad_inward_up", 50 | "dpdown": "dpad_inward_down", 51 | "dpleft": "dpad_inward_left", 52 | "dpright": "dpad_inward_right", 53 | "leftstick": "L3", 54 | "rightstick": "R3", 55 | "guide": { 56 | "type": "ps5_PS", 57 | "bg": "gray", 58 | "fg": "white" 59 | }, 60 | "back": "ps5_create", 61 | "start": "ps5_options" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/saturn-digital-pad.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Sega Saturn Digital Pad", 3 | "guids": ["03000000b40400000a01000000010000"], 4 | 5 | "bg": "gray", 6 | "fg": "white", 7 | 8 | "conventions": { 9 | "accept": "a", 10 | "back": "b" 11 | }, 12 | 13 | "buttons": { 14 | "a": { 15 | "type": "A", 16 | "bg": "green", 17 | "fg": "green" 18 | }, 19 | "b": { 20 | "type": "B", 21 | "bg": "orange", 22 | "fg": "yellow" 23 | }, 24 | "x": "X", 25 | "y": "Y", 26 | 27 | "_comment": [ 28 | "Blatantly stolen straight from the Sega diagram at", 29 | "https://github.com/gabomdq/SDL_GameControllerDB#mapping-guide", 30 | "Is this seriously what they went with? Ugh fine" 31 | ], 32 | "leftshoulder": { 33 | "type": "saturn_L", 34 | "bg": "pink", 35 | "fg": "white" 36 | }, 37 | "lefttrigger": { 38 | "type": "saturn_R", 39 | "bg": "pink", 40 | "fg": "white" 41 | }, 42 | "righttrigger": { 43 | "type": "C", 44 | "bg": "blue", 45 | "fg": "blue" 46 | }, 47 | "rightshoulder": "Z", 48 | 49 | "start": { 50 | "type": "saturn_start", 51 | "bg": "pink", 52 | "fg": "white" 53 | }, 54 | 55 | "dpup": "dpad_cross_up", 56 | "dpdown": "dpad_cross_down", 57 | "dpleft": "dpad_cross_left", 58 | "dpright": "dpad_cross_right" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/steam-deck.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Steam Deck", 3 | "guids": [ 4 | "03000000de2800000512000010010000" 5 | ], 6 | "bg": "black", 7 | "fg": "white", 8 | "conventions": { 9 | "accept": "a", 10 | "back": "b" 11 | }, 12 | "buttons": { 13 | "a": "A", 14 | "b": "B", 15 | "x": "X", 16 | "y": "Y", 17 | "leftshoulder": "L1", 18 | "rightshoulder": "R1", 19 | "lefttrigger": "L2", 20 | "righttrigger": "R2", 21 | "dpup": "dpad_cross_up", 22 | "dpdown": "dpad_cross_down", 23 | "dpleft": "dpad_cross_left", 24 | "dpright": "dpad_cross_right", 25 | "leftstick": "L3", 26 | "rightstick": "R3", 27 | "guide": "steam", 28 | "back": "deck_view", 29 | "start": "deck_options" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/xbox-360.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Xbox 360 Controller", 3 | "guids": [ 4 | "030000002e160000efbe000000000000", 5 | "03000000380700001647000000000000", 6 | "03000000380700002045000000000000", 7 | "03000000380700002644000000000000", 8 | "03000000380700002647000000000000", 9 | "030000003807000026b7000000000000", 10 | "03000000380700003647000000000000", 11 | "030000005e0400001907000000000000", 12 | "030000005e0400008e02000000000000", 13 | "030000005e0400009102000000000000", 14 | "03000000ad1b000000fd000000000000", 15 | "03000000ad1b000001fd000000000000", 16 | "03000000ad1b000016f0000000000000", 17 | "03000000ad1b00008e02000000000000", 18 | "03000000c62400000053000000000000", 19 | "03000000c6240000fdfa000000000000", 20 | "030000005e040000a102000000000000", 21 | "030000006f0e00000104000000000000", 22 | "03000000c6240000045d000000000000", 23 | "0000000058626f782033363020576900", 24 | "030000005e0400001907000000010000", 25 | "030000005e0400008e02000010010000", 26 | "030000005e0400008e02000014010000", 27 | "030000005e0400009102000007010000", 28 | "030000005e040000a102000000010000", 29 | "030000005e040000a102000007010000", 30 | "030000005e040000a102000014010000" 31 | ], 32 | "bg": "white", 33 | "fg": "gray", 34 | "conventions": { 35 | "accept": "a", 36 | "back": "b" 37 | }, 38 | "buttons": { 39 | "a": { 40 | "type": "A", 41 | "bg": "green", 42 | "fg": "green" 43 | }, 44 | "b": { 45 | "type": "B", 46 | "bg": "red", 47 | "fg": "red" 48 | }, 49 | "x": { 50 | "type": "X", 51 | "bg": "blue", 52 | "fg": "blue" 53 | }, 54 | "y": { 55 | "type": "Y", 56 | "bg": "orange", 57 | "fg": "yellow" 58 | }, 59 | "leftshoulder": "LB", 60 | "rightshoulder": "RB", 61 | "lefttrigger": "LT", 62 | "righttrigger": "RT", 63 | "dpup": "dpad_cross_up", 64 | "dpdown": "dpad_cross_down", 65 | "dpleft": "dpad_cross_left", 66 | "dpright": "dpad_cross_right", 67 | "leftstick": { 68 | "type": "LS", 69 | "bg": "gray", 70 | "fg": "white" 71 | }, 72 | "rightstick": { 73 | "type": "RS", 74 | "bg": "gray", 75 | "fg": "white" 76 | }, 77 | "guide": { 78 | "type": "xb_guide", 79 | "bg": "gray", 80 | "fg": "lime" 81 | }, 82 | "back": "xb_back", 83 | "start": "xb_start" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/xbox-one.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Xbox One Controller", 3 | "guids": [ 4 | "030000000d0f00006300000000000000", 5 | "030000005e0400000c0b000000000000", 6 | "030000005e040000d102000000000000", 7 | "030000005e040000dd02000000000000", 8 | "030000005e040000e002000000000000", 9 | "030000005e040000e302000000000000", 10 | "030000005e040000ea02000000000000", 11 | "030000005e040000fd02000000000000", 12 | "030000005e040000ff02000000000000", 13 | "030000006f0e0000a802000000000000", 14 | "030000006f0e0000c802000000000000", 15 | "03000000c62400003a54000000000000", 16 | "030000005e040000130b000011050000", 17 | "030000005e040000200b000011050000", 18 | "030000005e040000e002000003090000", 19 | "030000005e040000fd02000003090000", 20 | "030000005e0400000a0b000005040000", 21 | "030000005e040000120b000009050000", 22 | "030000005e040000d102000002010000", 23 | "030000005e040000ea02000001030000", 24 | "050000005e040000e002000003090000", 25 | "050000005e040000fd02000003090000", 26 | "050000005e040000fd02000030110000", 27 | "060000005e040000120b000007050000", 28 | "050000005e04000091020000ff073f00", 29 | "050000005e040000e00200000ffe3f00", 30 | "050000005e040000e0020000ffff3f00", 31 | "050000005e040000fd020000ffff3f00", 32 | "33356661323266333733373865656366", 33 | "34356136633366613530316338376136", 34 | "35623965373264386238353433656138", 35 | "36616131643361333337396261666433", 36 | "58626f7820576972656c65737320436f", 37 | "050000005e040000e0020000df070000", 38 | "050000005e040000e0020000ff070000" 39 | ], 40 | "bg": "black", 41 | "fg": "white", 42 | "conventions": { 43 | "accept": "a", 44 | "back": "b" 45 | }, 46 | "buttons": { 47 | "a": { 48 | "type": "A", 49 | "bg": "black", 50 | "fg": "green" 51 | }, 52 | "b": { 53 | "type": "B", 54 | "bg": "black", 55 | "fg": "red" 56 | }, 57 | "x": { 58 | "type": "X", 59 | "bg": "black", 60 | "fg": "blue" 61 | }, 62 | "y": { 63 | "type": "Y", 64 | "bg": "black", 65 | "fg": "yellow" 66 | }, 67 | "leftshoulder": "LB", 68 | "rightshoulder": "RB", 69 | "lefttrigger": "LT", 70 | "righttrigger": "RT", 71 | "dpup": "dpad_cross_up", 72 | "dpdown": "dpad_cross_down", 73 | "dpleft": "dpad_cross_left", 74 | "dpright": "dpad_cross_right", 75 | "leftstick": "LS", 76 | "rightstick": "RS", 77 | "guide": { 78 | "type": "xbox", 79 | "bg": "white", 80 | "fg": "black" 81 | }, 82 | "back": "xb_view", 83 | "start": "xb_menu" 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /symbols.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors": { 3 | "_comment": "The first entry in the array is the color when this is used as a bg - the second is the color when used as an fg. These are only suggestions, games are free to replace these", 4 | "red": ["D32F2F", "EF9A9A"], 5 | "pink": ["E91E63", "F06292"], 6 | "purple": ["9C27B0", "BA68C8"], 7 | "blue": ["3F51B5", "4FC3F7"], 8 | "cyan": ["00BCD4", "4DD0E1"], 9 | "teal": ["009688", "4DB6AC"], 10 | "green": ["388E3C", "81C784"], 11 | "lime": ["8BC34A", "D4E157"], 12 | "yellow": ["FDD835", "FFF176"], 13 | "orange": ["FF9800", "FFB74D"], 14 | "brown": ["795548", "A1887F"], 15 | "white": ["E0E0E0", "FAFAFA"], 16 | "black": ["212121", "424242"], 17 | "gray": ["607D8B", "263238"] 18 | }, 19 | "buttons": { 20 | "_comment": [ 21 | "These describe the various kinds of buttons found on controllers in the database.", 22 | "shape is the shape of the button itself", 23 | "icon (may be absent) is the symbolic name of the button's legend", 24 | "text is a best-effort Unicode representation of the legend", 25 | "text_basic (may be absent if text is all ASCII) is a best effort ASCII representation of the legend", 26 | "shape_is_button is defined and true if the shape is itself the button, and an additional icon or text would be redundant.", 27 | "The idea is a new button of an old shape can be drawn by games using the database even without explicit support by invoking a text renderer with Unicode support." 28 | ], 29 | 30 | "_comment": "First up, the Xbox 360 style buttons native to the SDL controller DB.", 31 | "A": { 32 | "shape": "circle", 33 | "text": "A" 34 | }, 35 | "B": { 36 | "shape": "circle", 37 | "text": "B" 38 | }, 39 | "X": { 40 | "shape": "circle", 41 | "text": "X" 42 | }, 43 | "Y": { 44 | "shape": "circle", 45 | "text": "Y" 46 | }, 47 | "LS": { 48 | "shape": "circle", 49 | "text": "LS" 50 | }, 51 | "RS": { 52 | "shape": "circle", 53 | "text": "RS" 54 | }, 55 | "LB": { 56 | "shape": "bumper_left", 57 | "text": "LB" 58 | }, 59 | "RB": { 60 | "shape": "bumper_right", 61 | "text": "RB" 62 | }, 63 | "LT": { 64 | "shape": "trigger_left", 65 | "text": "LT" 66 | }, 67 | "RT": { 68 | "shape": "trigger_right", 69 | "text": "RT" 70 | }, 71 | "xb_guide": { 72 | "shape": "circle", 73 | "icon": "xbox", 74 | "text": "Guide" 75 | }, 76 | "xbox": { 77 | "shape": "circle", 78 | "icon": "xbox", 79 | "text": "Xbox" 80 | }, 81 | "xb_back": { 82 | "shape": "pill", 83 | "icon": "triangle_left", 84 | "text": "◀", 85 | "text_basic": "Back" 86 | }, 87 | "xb_start": { 88 | "shape": "pill", 89 | "icon": "triangle_right", 90 | "text": "▶", 91 | "text_basic": "Start" 92 | }, 93 | "xb_view": { 94 | "shape": "circle", 95 | "icon": "view", 96 | "text": "⧉", 97 | "text_basic": "View" 98 | }, 99 | "xb_menu": { 100 | "shape": "circle", 101 | "icon": "menu", 102 | "text": "≡", 103 | "text_basic": "Menu" 104 | }, 105 | 106 | "_comment": "More generic letter buttons", 107 | "Z": { 108 | "shape": "circle", 109 | "text": "Z" 110 | }, 111 | "C": { 112 | "shape": "circle", 113 | "text": "C" 114 | }, 115 | 116 | "_comment": "PlayStation buttons", 117 | "L3": { 118 | "shape": "circle", 119 | "text": "L3" 120 | }, 121 | "R3": { 122 | "shape": "circle", 123 | "text": "R3" 124 | }, 125 | "L1": { 126 | "shape": "bumper_left", 127 | "text": "L1" 128 | }, 129 | "R1": { 130 | "shape": "bumper_right", 131 | "text": "R1" 132 | }, 133 | "L2": { 134 | "shape": "trigger_left", 135 | "text": "L2" 136 | }, 137 | "R2": { 138 | "shape": "trigger_right", 139 | "text": "R2" 140 | }, 141 | "PS": { 142 | "shape": "circle", 143 | "icon": "playstation", 144 | "text": "PS" 145 | }, 146 | "ps5_PS": { 147 | "shape": "playstation", 148 | "shape_is_button": true, 149 | "text": "PS" 150 | }, 151 | "ps4_share": { 152 | "shape": "lozenge_vertical", 153 | "text": "Share" 154 | }, 155 | "ps4_options": { 156 | "shape": "lozenge_vertical", 157 | "text": "Options" 158 | }, 159 | "ps5_create": { 160 | "shape": "lozenge_vertical", 161 | "icon": "radiate", 162 | "text": "🗤", 163 | "text_basic": "Create" 164 | }, 165 | "ps5_options": { 166 | "shape": "lozenge_vertical", 167 | "icon": "menu", 168 | "text": "≡", 169 | "text_basic": "Options" 170 | }, 171 | 172 | "_comment": "Original Xbox (Xbox Zero, xb0, because Microsoft reused 'Xbox One')", 173 | "xb0_A": { 174 | "shape": "bean_left", 175 | "text": "A" 176 | }, 177 | "xb0_B": { 178 | "shape": "bean_left", 179 | "text": "B" 180 | }, 181 | "xb0_X": { 182 | "shape": "bean_left", 183 | "text": "X" 184 | }, 185 | "xb0_Y": { 186 | "shape": "bean_left", 187 | "text": "Y" 188 | }, 189 | "xb0_black": { 190 | "shape": "bean_left", 191 | "shape_is_button": true, 192 | "text": "Black" 193 | }, 194 | "xb0_white": { 195 | "shape": "bean_left", 196 | "shape_is_button": true, 197 | "text": "White" 198 | }, 199 | "xb0_jewel": { 200 | "shape": "circle", 201 | "icon": "xbox_original", 202 | "text": "Xbox" 203 | }, 204 | "_comment": "Pill-shaped Xbox One view/menu buttons seen on the Hyperkin Duke original Xbox controller remake", 205 | "xb0_view": { 206 | "shape": "pill", 207 | "icon": "view", 208 | "text": "⧉", 209 | "text_basic": "View" 210 | }, 211 | "xb0_menu": { 212 | "shape": "pill", 213 | "icon": "menu", 214 | "text": "≡", 215 | "text_basic": "Menu" 216 | }, 217 | 218 | "_comment": "Nintendo naming of the sticks/shoulders", 219 | "nx_LS": { 220 | "shape": "stick_down", 221 | "text": "L" 222 | }, 223 | "nx_RS": { 224 | "shape": "stick_down", 225 | "text": "R" 226 | }, 227 | "nx_L": { 228 | "shape": "bumper_left", 229 | "text": "L" 230 | }, 231 | "nx_R": { 232 | "shape": "bumper_right", 233 | "text": "R" 234 | }, 235 | "nx_ZL": { 236 | "shape": "trigger_left", 237 | "text": "ZL" 238 | }, 239 | "nx_ZR": { 240 | "shape": "trigger_right", 241 | "text": "ZR" 242 | }, 243 | "minus": { 244 | "shape": "circle", 245 | "icon": "minus", 246 | "text": "-" 247 | }, 248 | "plus": { 249 | "shape": "circle", 250 | "icon": "plus", 251 | "text": "+" 252 | }, 253 | 254 | "_comment": "GameCube", 255 | "gcn_stick": { 256 | "shape": "circle", 257 | "shape_is_button": true, 258 | "text": "Control Stick" 259 | }, 260 | "gcn_B": { 261 | "shape": "circle_medium", 262 | "text": "B" 263 | }, 264 | "gcn_C": { 265 | "shape": "circle_medium", 266 | "text": "C" 267 | }, 268 | "gcn_Y": { 269 | "shape": "lozenge_curved_horizontal", 270 | "text": "Y" 271 | }, 272 | "gcn_X": { 273 | "shape": "lozenge_curved_vertical", 274 | "text": "X" 275 | }, 276 | "gcn_Z": { 277 | "shape": "lozenge_horizontal", 278 | "text": "Z" 279 | }, 280 | "gcn_start": { 281 | "shape": "circle_medium", 282 | "text": "Start" 283 | }, 284 | "gcn_L": { 285 | "shape": "trigger_left", 286 | "text": "L" 287 | }, 288 | "gcn_R": { 289 | "shape": "trigger_right", 290 | "text": "R" 291 | }, 292 | 293 | "_comment": "Saturn stuff", 294 | "saturn_L": { 295 | "shape": "bumper_left", 296 | "icon": "skip_prev", 297 | "text": "⏮", 298 | "text_basic": "L" 299 | }, 300 | "saturn_R": { 301 | "shape": "bumper_right", 302 | "icon": "skip_next", 303 | "text": "⏭", 304 | "text_basic": "R" 305 | }, 306 | "saturn_start": { 307 | "shape": "pill", 308 | "shape_is_button": true, 309 | "text": "Start" 310 | }, 311 | 312 | "_comment": "Steamed Decks", 313 | "steam": { 314 | "shape": "lozenge_horizontal", 315 | "text": "STEAM" 316 | }, 317 | "deck_view": { 318 | "shape": "lozenge_horizontal", 319 | "icon": "box", 320 | "text": "▪", 321 | "text_basic": "View" 322 | }, 323 | "deck_options": { 324 | "shape": "lozenge_horizontal", 325 | "icon": "menu", 326 | "text": "≡", 327 | "text_basic": "Options" 328 | }, 329 | 330 | "_comment": "Iconographic buttons seen on some generic controllers", 331 | "home": { 332 | "shape": "circle", 333 | "icon": "home", 334 | "text": "Home" 335 | }, 336 | "power": { 337 | "shape": "circle", 338 | "icon": "power", 339 | "text": "⏻", 340 | "text_basic": "Power" 341 | }, 342 | "arrow_up": { 343 | "shape": "circle", 344 | "icon": "arrow_up", 345 | "text": "↑", 346 | "text_basic": "Up Arrow" 347 | }, 348 | "arrow_down": { 349 | "shape": "circle", 350 | "icon": "arrow_down", 351 | "text": "↓", 352 | "text_basic": "Down Arrow" 353 | }, 354 | "arrow_left": { 355 | "shape": "circle", 356 | "icon": "arrow_left", 357 | "text": "←", 358 | "text_basic": "Left Arrow" 359 | }, 360 | "arrow_right": { 361 | "shape": "circle", 362 | "icon": "arrow_right", 363 | "text": "→", 364 | "text_basic": "Right Arrow" 365 | }, 366 | 367 | "_comment": "Geometric shapes that take up the entire button space, usually seen on PlayStation controllers", 368 | "triangle": { 369 | "shape": "circle", 370 | "icon": "triangle", 371 | "text": "△", 372 | "text_basic": "Triangle" 373 | }, 374 | "square": { 375 | "shape": "circle", 376 | "icon": "square", 377 | "text": "□", 378 | "text_basic": "Square" 379 | }, 380 | "circle": { 381 | "shape": "circle", 382 | "icon": "circle_outline", 383 | "text": "○", 384 | "text_basic": "Circle" 385 | }, 386 | "cross": { 387 | "shape": "circle", 388 | "icon": "cross", 389 | "text": "⨯", 390 | "text_basic": "Cross" 391 | }, 392 | 393 | "_comment": "Buttons that are themselves special shapes", 394 | "nx_minus": { 395 | "shape": "minus", 396 | "shape_is_button": true, 397 | "text": "-" 398 | }, 399 | "nx_plus": { 400 | "shape": "plus", 401 | "shape_is_button": true, 402 | "text": "+" 403 | }, 404 | "ps_start": { 405 | "shape": "long_triangle_right", 406 | "shape_is_button": true, 407 | "text": "►", 408 | "text_basic": "Start" 409 | }, 410 | "ps_back": { 411 | "shape": "rectangle_horizontal", 412 | "shape_is_button": true, 413 | "text": "▬", 414 | "text_basic": "Back" 415 | }, 416 | 417 | "_comment": "A D-Pad that looks similar to that on PlayStation controllers; four pointed rectangles pointing inward, creating an X shape between the buttons", 418 | "dpad_inward_up": { 419 | "shape": "dpad_inward_up", 420 | "shape_is_button": true, 421 | "text": "D-Pad Up" 422 | }, 423 | "dpad_inward_down": { 424 | "shape": "dpad_inward_down", 425 | "shape_is_button": true, 426 | "text": "D-Pad Down" 427 | }, 428 | "dpad_inward_left": { 429 | "shape": "dpad_inward_left", 430 | "shape_is_button": true, 431 | "text": "D-Pad Left" 432 | }, 433 | "dpad_inward_right": { 434 | "shape": "dpad_inward_right", 435 | "shape_is_button": true, 436 | "text": "D-Pad Right" 437 | }, 438 | 439 | "_comment": "A standard plus-shaped D-Pad", 440 | "dpad_cross_up": { 441 | "shape": "dpad_cross_up", 442 | "shape_is_button": true, 443 | "text": "D-Pad Up" 444 | }, 445 | "dpad_cross_down": { 446 | "shape": "dpad_cross_down", 447 | "shape_is_button": true, 448 | "text": "D-Pad Down" 449 | }, 450 | "dpad_cross_left": { 451 | "shape": "dpad_cross_left", 452 | "shape_is_button": true, 453 | "text": "D-Pad Left" 454 | }, 455 | "dpad_cross_right": { 456 | "shape": "dpad_cross_right", 457 | "shape_is_button": true, 458 | "text": "D-Pad Right" 459 | }, 460 | 461 | "_comment": "A D-Pad like that on Nintendo's Joy-Con, which is simply a cluster of four circular buttons", 462 | "dpad_circle_up": { 463 | "shape": "circle_cluster_up", 464 | "shape_is_button": true, 465 | "text": "D-Pad Up" 466 | }, 467 | "dpad_circle_down": { 468 | "shape": "circle_cluster_down", 469 | "shape_is_button": true, 470 | "text": "D-Pad Down" 471 | }, 472 | "dpad_circle_left": { 473 | "shape": "circle_cluster_left", 474 | "shape_is_button": true, 475 | "text": "D-Pad Left" 476 | }, 477 | "dpad_circle_right": { 478 | "shape": "circle_cluster_right", 479 | "shape_is_button": true, 480 | "text": "D-Pad Right" 481 | }, 482 | 483 | 484 | "_comment": "Generic directional buttons", 485 | "dpad_up": { 486 | "shape": "circle", 487 | "icon": "triangle_up", 488 | "text": "▲", 489 | "text_basic": "D-Pad Up" 490 | }, 491 | "dpad_down": { 492 | "shape": "circle", 493 | "icon": "triangle_down", 494 | "text": "▼", 495 | "text_basic": "D-Pad Down" 496 | }, 497 | "dpad_left": { 498 | "shape": "circle", 499 | "icon": "triangle_left", 500 | "text": "◀", 501 | "text_basic": "D-Pad Left" 502 | }, 503 | "dpad_right": { 504 | "shape": "circle", 505 | "icon": "triangle_right", 506 | "text": "▶", 507 | "text_basic": "D-Pad Right" 508 | } 509 | } 510 | } 511 | -------------------------------------------------------------------------------- /www/_button.html.hbs: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{text}}
4 |
5 | -------------------------------------------------------------------------------- /www/bean-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/bean-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/build.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const hbs = require('handlebars'); 4 | 5 | const me = path.resolve(process.argv[1], '..'); 6 | 7 | const data = JSON.parse(fs.readFileSync(process.argv[2] || path.resolve(me, '../dist/symboliccontrollerdb.json')).toString('utf8')); 8 | 9 | const buttonTmpl = hbs.compile(fs.readFileSync(path.resolve(me, '_button.html.hbs')).toString('utf8')); 10 | 11 | function resolve(buttons) { 12 | let out = {}; 13 | Object.entries(buttons).forEach(([k, v]) => { 14 | out[k] = buttonTmpl({bg: v.bg, fg: v.fg, ...data.symbols.buttons[v.type]}); 15 | }); 16 | return out; 17 | } 18 | 19 | function distinct(arr) { 20 | let s = new Set(); 21 | arr.forEach(e => s.add(e)); 22 | return [...s]; 23 | } 24 | 25 | let ctx = { 26 | controllers: [], 27 | icons: Object.entries({ 28 | circle: "circle.svg", 29 | bumper_left: "bumper-left.svg", 30 | bumper_right: "bumper-right.svg", 31 | trigger_left: "trigger-left.svg", 32 | trigger_right: "trigger-right.svg", 33 | xbox: "xbox-swish.svg", 34 | triangle_up: "mdi/menu-up.svg", 35 | triangle_down: "mdi/menu-down.svg", 36 | triangle_left: "mdi/menu-left.svg", 37 | triangle_right: "mdi/menu-right.svg", 38 | dpad_inward_up: "mdi/gamepad-up.svg", 39 | dpad_inward_down: "mdi/gamepad-down.svg", 40 | dpad_inward_left: "mdi/gamepad-left.svg", 41 | dpad_inward_right: "mdi/gamepad-right.svg", 42 | dpad_cross_up: "mdi/gamepad-round-up.svg", 43 | dpad_cross_down: "mdi/gamepad-round-down.svg", 44 | dpad_cross_left: "mdi/gamepad-round-left.svg", 45 | dpad_cross_right: "mdi/gamepad-round-right.svg", 46 | circle_cluster_up: "mdi/gamepad-circle-up.svg", 47 | circle_cluster_down: "mdi/gamepad-circle-down.svg", 48 | circle_cluster_left: "mdi/gamepad-circle-left.svg", 49 | circle_cluster_right: "mdi/gamepad-circle-right.svg", 50 | arrow_up: "mdi/arrow-up.svg", 51 | arrow_down: "mdi/arrow-down.svg", 52 | arrow_left: "mdi/arrow-left.svg", 53 | arrow_right: "mdi/arrow-right.svg", 54 | power: "mdi/power.svg", 55 | circle_outline: "circle-inner.svg", 56 | square: "square.svg", 57 | cross: "mdi/close.svg", 58 | triangle: "triangle.svg", 59 | minus: "mdi/minus.svg", 60 | plus: "mdi/plus.svg", 61 | stick_down: "stick-down.svg", 62 | home: "mdi/home.svg", 63 | playstation: "playstation.svg", 64 | rectangle_horizontal: "rectangle.svg", 65 | long_triangle_right: "long-triangle-right.svg", 66 | skip_next: "mdi/skip-forward.svg", 67 | skip_prev: "mdi/skip-backward.svg", 68 | pill: "mdi/ellipse.svg", 69 | menu: "mdi/menu.svg", 70 | view: "view.svg", 71 | lozenge_vertical: "lozenge-vertical.svg", 72 | lozenge_horizontal: "lozenge-horizontal.svg", 73 | radiate: "radiate.svg", 74 | box: "mdi/square-medium.svg", 75 | circle_medium: "circle-medium.svg", 76 | lozenge_curved_horizontal: "lozenge-curved-horizontal.svg", 77 | lozenge_curved_vertical: "lozenge-curved-vertical.svg", 78 | bean_left: "bean-left.svg", 79 | bean_right: "bean-right.svg", 80 | xbox_original: "xbox-original.svg", 81 | }).map(([k, v]) => ({symbol:k,icon:v.replace("mdi/", "https://cdn.jsdelivr.net/npm/@mdi/svg@7.0.96/svg/")})), 82 | shapes: distinct([ 83 | ...Object.values(data.symbols.buttons).map(v => v.shape), 84 | ...Object.values(data.symbols.buttons).map(v => v.icon) 85 | ]).filter(v => v != null).sort() 86 | }; 87 | data.controllers.forEach((ctrl) => { 88 | ctx.controllers.push({ 89 | name: ctrl.name, 90 | conventions: { 91 | [ctrl.conventions.accept]: " convention-accept", 92 | [ctrl.conventions.back]: " convention-back" 93 | }, 94 | ...resolve(ctrl.buttons) 95 | }); 96 | }); 97 | ctx.colors = Object.entries(data.symbols.colors).map(([k, v]) => ({name:k,bg:v[0],fg:v[1]})); 98 | fs.writeFileSync('index.html', hbs.compile(fs.readFileSync(path.resolve(me, 'index.html.hbs')).toString('utf8'))(ctx)); 99 | -------------------------------------------------------------------------------- /www/bumper-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/bumper-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/circle-inner.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/circle-medium.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/circle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/index.html.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Symbolic Controller Database 7 | 8 | 155 | 156 | 157 |

158 | 159 | Symbolic Controller DB 160 | 161 | 162 | 163 |

164 |

165 | The SDL controller DB 166 | provides useful abstract descriptions of where buttons are and how 167 | controllers behave, but hammers them all into the terminology of an Xbox 168 | 360 controller. 169 |

170 |

171 | Showing users inputs on their controller using only the SDL DB is a 172 | poor and messy experience for users and developers alike. 173 |

174 |

175 | What if we had a free database of what controllers look like, in 176 | addition to how they're shaped and interfaced with? 177 |

178 | More info and contributing 179 |
180 |

Currently defined controllers

181 | Buttons with a green underline are the conventional "accept" button. Buttons with a red underline 182 | are the conventional "back" or "cancel" button. 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | {{#controllers}} 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | {{/controllers}} 237 | 238 |
ControllerPrimary ClusterShoulderTriggerD-PadSticksMeta
South
(A)
East
(B)
West
(X)
North
(Y)
LeftRightLeftRightUpDownLeftRightLeftRightBackGuideStart
{{name}}{{{a}}}{{{b}}}{{{x}}}{{{y}}}{{{leftshoulder}}}{{{rightshoulder}}}{{{lefttrigger}}}{{{righttrigger}}}{{{dpup}}}{{{dpdown}}}{{{dpleft}}}{{{dpright}}}{{{leftstick}}}{{{rightstick}}}{{{back}}}{{{guide}}}{{{start}}}
239 |

Default colors

240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | {{#colors}} 250 | 251 | 252 | 253 | 254 | 255 | {{/colors}} 256 | 257 |
NameBackgroundForeground
{{name}}
#{{bg}}
#{{fg}}
258 |

Currently defined shapes and icons

259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | {{#shapes}} 268 | 269 | 270 | 271 | 272 | {{/shapes}} 273 | 274 |
NameSuggested
Appearance
{{this}}
275 |
276 | Icons by Material Design Icons 277 | 278 | 279 | -------------------------------------------------------------------------------- /www/long-triangle-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/lozenge-curved-horizontal.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/lozenge-curved-vertical.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/lozenge-horizontal.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/lozenge-vertical.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "www", 3 | "lockfileVersion": 2, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "dependencies": { 8 | "handlebars": "^4.7.7" 9 | } 10 | }, 11 | "node_modules/handlebars": { 12 | "version": "4.7.7", 13 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", 14 | "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", 15 | "dependencies": { 16 | "minimist": "^1.2.5", 17 | "neo-async": "^2.6.0", 18 | "source-map": "^0.6.1", 19 | "wordwrap": "^1.0.0" 20 | }, 21 | "bin": { 22 | "handlebars": "bin/handlebars" 23 | }, 24 | "engines": { 25 | "node": ">=0.4.7" 26 | }, 27 | "optionalDependencies": { 28 | "uglify-js": "^3.1.4" 29 | } 30 | }, 31 | "node_modules/minimist": { 32 | "version": "1.2.6", 33 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 34 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" 35 | }, 36 | "node_modules/neo-async": { 37 | "version": "2.6.2", 38 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 39 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" 40 | }, 41 | "node_modules/source-map": { 42 | "version": "0.6.1", 43 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 44 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 45 | "engines": { 46 | "node": ">=0.10.0" 47 | } 48 | }, 49 | "node_modules/uglify-js": { 50 | "version": "3.17.2", 51 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.2.tgz", 52 | "integrity": "sha512-bbxglRjsGQMchfvXZNusUcYgiB9Hx2K4AHYXQy2DITZ9Rd+JzhX7+hoocE5Winr7z2oHvPsekkBwXtigvxevXg==", 53 | "optional": true, 54 | "bin": { 55 | "uglifyjs": "bin/uglifyjs" 56 | }, 57 | "engines": { 58 | "node": ">=0.8.0" 59 | } 60 | }, 61 | "node_modules/wordwrap": { 62 | "version": "1.0.0", 63 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 64 | "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" 65 | } 66 | }, 67 | "dependencies": { 68 | "handlebars": { 69 | "version": "4.7.7", 70 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", 71 | "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", 72 | "requires": { 73 | "minimist": "^1.2.5", 74 | "neo-async": "^2.6.0", 75 | "source-map": "^0.6.1", 76 | "uglify-js": "^3.1.4", 77 | "wordwrap": "^1.0.0" 78 | } 79 | }, 80 | "minimist": { 81 | "version": "1.2.6", 82 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 83 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" 84 | }, 85 | "neo-async": { 86 | "version": "2.6.2", 87 | "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", 88 | "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" 89 | }, 90 | "source-map": { 91 | "version": "0.6.1", 92 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 93 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" 94 | }, 95 | "uglify-js": { 96 | "version": "3.17.2", 97 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.2.tgz", 98 | "integrity": "sha512-bbxglRjsGQMchfvXZNusUcYgiB9Hx2K4AHYXQy2DITZ9Rd+JzhX7+hoocE5Winr7z2oHvPsekkBwXtigvxevXg==", 99 | "optional": true 100 | }, 101 | "wordwrap": { 102 | "version": "1.0.0", 103 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 104 | "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /www/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "handlebars": "^4.7.7" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /www/playstation.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/radiate.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/rectangle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/square.svg: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 33 | 37 | 38 | -------------------------------------------------------------------------------- /www/stick-down.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/triangle.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/trigger-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/trigger-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/view.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /www/xbox-original.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /www/xbox-swish.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------