├── LICENSE ├── README.md ├── diagram.png ├── disconnect.png ├── godot.cfg ├── icon.png ├── indicators.png ├── jsdiagram.tscn ├── mapping.tscn └── remapping.gd /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Andreas Haas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # joystick-mapping 2 | A simple tool that produces SDL2 - compatible Gamepad mappings using the Godot Engine. 3 | 4 | License: [MIT](LICENSE) 5 | 6 | Note that Godot doesn't have clipboard functionality on Android. 7 | Use the remote debugging option to retrieve the mappings (or something like `adb logcat | grep MAPPING`). 8 | -------------------------------------------------------------------------------- /diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/27thLiz/joystick-mapping/bf459cb2f38ce7bd18a75318c1765c412cd64201/diagram.png -------------------------------------------------------------------------------- /disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/27thLiz/joystick-mapping/bf459cb2f38ce7bd18a75318c1765c412cd64201/disconnect.png -------------------------------------------------------------------------------- /godot.cfg: -------------------------------------------------------------------------------- 1 | [application] 2 | 3 | name="joystick-mapping" 4 | main_scene="res://mapping.tscn" 5 | [input] 6 | 7 | ui_accept=[ InputEvent(KEY,16777221), InputEvent(KEY,16777222), InputEvent(KEY,32)] 8 | ui_select=[ InputEvent(KEY,32)] 9 | ui_cancel=[ InputEvent(KEY,16777217)] 10 | ui_focus_next=[ InputEvent(KEY,16777218) ] 11 | ui_focus_prev=[ InputEvent(KEY,16777218,S) ] 12 | ui_left=[ InputEvent(KEY,16777231)] 13 | ui_right=[ InputEvent(KEY,16777233)] 14 | ui_up=[ InputEvent(KEY,16777232)] 15 | ui_down=[ InputEvent(KEY,16777234) ] 16 | ui_page_up=[ InputEvent(KEY,16777235) ] 17 | ui_page_down=[ InputEvent(KEY,16777236) ] 18 | mapping_skip=[ InputEvent(KEY,32) ] 19 | mapping_back=[ InputEvent(KEY,16777220) ] 20 | start_mapping=[ InputEvent(KEY,83) ] 21 | mapping_cancel=[ InputEvent(KEY,16777217) ] 22 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/27thLiz/joystick-mapping/bf459cb2f38ce7bd18a75318c1765c412cd64201/icon.png -------------------------------------------------------------------------------- /indicators.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/27thLiz/joystick-mapping/bf459cb2f38ce7bd18a75318c1765c412cd64201/indicators.png -------------------------------------------------------------------------------- /jsdiagram.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=27 format=2] 2 | 3 | [ext_resource type="Texture" path="res://diagram.png" id=1] 4 | 5 | [ext_resource type="Texture" path="res://indicators.png" id=2] 6 | 7 | 8 | [node name="diagram" type="Sprite"] 9 | 10 | scale=Vector2( 0.432859, 0.446287 ) 11 | texture=ExtResource(1) 12 | centered=false 13 | __meta__={ 14 | "__editor_plugin_screen__": "2D" 15 | } 16 | 17 | [node name="buttons" parent="." type="Node2D"] 18 | 19 | position=Vector2( 246.762, 272.349 ) 20 | __meta__={ 21 | "_editor_collapsed": true 22 | } 23 | 24 | [node name="0" parent="buttons" type="Sprite"] 25 | 26 | visible=false 27 | position=Vector2( 147.73, 120.925 ) 28 | scale=Vector2( 0.9, 0.9 ) 29 | texture=ExtResource(2) 30 | region=true 31 | region_rect=Rect2( 0, 0, 45, 45 ) 32 | 33 | [node name="1" parent="buttons" type="Sprite"] 34 | 35 | visible=false 36 | position=Vector2( 185.769, 82.4874 ) 37 | scale=Vector2( 0.9, 0.9 ) 38 | texture=ExtResource(2) 39 | region=true 40 | region_rect=Rect2( 0, 0, 45, 45 ) 41 | 42 | [node name="2" parent="buttons" type="Sprite"] 43 | 44 | visible=false 45 | position=Vector2( 112.377, 82.4874 ) 46 | scale=Vector2( 0.9, 0.9 ) 47 | texture=ExtResource(2) 48 | region=true 49 | region_rect=Rect2( 0, 0, 45, 45 ) 50 | 51 | [node name="3" parent="buttons" type="Sprite"] 52 | 53 | visible=false 54 | position=Vector2( 149.073, 47.3293 ) 55 | scale=Vector2( 0.9, 0.9 ) 56 | texture=ExtResource(2) 57 | region=true 58 | region_rect=Rect2( 0, 0, 45, 45 ) 59 | 60 | [node name="4" parent="buttons" type="Sprite"] 61 | 62 | visible=false 63 | position=Vector2( -161.038, -158.037 ) 64 | scale=Vector2( 5.3348, 3.35512 ) 65 | texture=ExtResource(2) 66 | region=true 67 | region_rect=Rect2( 10, 10, 10, 10 ) 68 | 69 | [node name="5" parent="buttons" type="Sprite"] 70 | 71 | visible=false 72 | position=Vector2( 159.362, -156.977 ) 73 | scale=Vector2( 5.3348, 3.35512 ) 74 | texture=ExtResource(2) 75 | region=true 76 | region_rect=Rect2( 10, 10, 10, 10 ) 77 | 78 | [node name="6" parent="buttons" type="Sprite"] 79 | 80 | visible=false 81 | position=Vector2( -159.349, -221.878 ) 82 | scale=Vector2( 1.0458, 2.16952 ) 83 | texture=ExtResource(2) 84 | flip_h=true 85 | region=true 86 | region_rect=Rect2( 0, 0, 45, 22 ) 87 | 88 | [node name="7" parent="buttons" type="Sprite"] 89 | 90 | visible=false 91 | position=Vector2( 156.677, -220.11 ) 92 | scale=Vector2( 1.0458, 2.16952 ) 93 | texture=ExtResource(2) 94 | region=true 95 | region_rect=Rect2( 0, 0, 45, 22 ) 96 | 97 | [node name="8" parent="buttons" type="Sprite"] 98 | 99 | visible=false 100 | position=Vector2( -67.5308, 164.422 ) 101 | scale=Vector2( 0.9, 0.9 ) 102 | texture=ExtResource(2) 103 | region=true 104 | region_rect=Rect2( 0, 0, 45, 45 ) 105 | 106 | [node name="9" parent="buttons" type="Sprite"] 107 | 108 | visible=false 109 | position=Vector2( 75.8825, 167.363 ) 110 | scale=Vector2( 0.9, 0.9 ) 111 | texture=ExtResource(2) 112 | region=true 113 | region_rect=Rect2( 0, 0, 45, 45 ) 114 | 115 | [node name="10" parent="buttons" type="Sprite"] 116 | 117 | visible=false 118 | position=Vector2( -46.6707, 52.702 ) 119 | scale=Vector2( 0.810497, 0.57205 ) 120 | texture=ExtResource(2) 121 | region=true 122 | region_rect=Rect2( 0, 0, 45, 45 ) 123 | 124 | [node name="11" parent="buttons" type="Sprite"] 125 | 126 | visible=false 127 | position=Vector2( 56.2581, 54.4382 ) 128 | scale=Vector2( 0.810497, 0.57205 ) 129 | texture=ExtResource(2) 130 | region=true 131 | region_rect=Rect2( 0, 0, 45, 45 ) 132 | 133 | [node name="12" parent="buttons" type="Sprite"] 134 | 135 | visible=false 136 | position=Vector2( -139.402, 46.8295 ) 137 | scale=Vector2( 0.9, 0.9 ) 138 | texture=ExtResource(2) 139 | region=true 140 | region_rect=Rect2( 50, 0, 54, 14 ) 141 | 142 | [node name="13" parent="buttons" type="Sprite"] 143 | 144 | visible=false 145 | position=Vector2( -139.838, 115.789 ) 146 | scale=Vector2( 0.9, 0.9 ) 147 | texture=ExtResource(2) 148 | flip_v=true 149 | region=true 150 | region_rect=Rect2( 50, 0, 54, 14 ) 151 | 152 | [node name="14" parent="buttons" type="Sprite"] 153 | 154 | visible=false 155 | position=Vector2( -172.262, 81.8793 ) 156 | scale=Vector2( 0.9, 0.9 ) 157 | texture=ExtResource(2) 158 | region=true 159 | region_rect=Rect2( 50, 0, 14, 54 ) 160 | 161 | [node name="15" parent="buttons" type="Sprite"] 162 | 163 | visible=false 164 | position=Vector2( -105.085, 81.0326 ) 165 | scale=Vector2( 0.9, 0.9 ) 166 | texture=ExtResource(2) 167 | flip_h=true 168 | region=true 169 | region_rect=Rect2( 50, 0, 14, 54 ) 170 | 171 | [node name="axes" parent="." type="Node2D"] 172 | 173 | position=Vector2( 246.027, 273.003 ) 174 | __meta__={ 175 | "_editor_collapsed": true 176 | } 177 | 178 | [node name="0-" parent="axes" type="Sprite"] 179 | 180 | visible=false 181 | position=Vector2( -94.4295, 164.932 ) 182 | scale=Vector2( 0.9, 0.9 ) 183 | texture=ExtResource(2) 184 | region=true 185 | region_rect=Rect2( 50, 0, 14, 54 ) 186 | 187 | [node name="0+" parent="axes" type="Sprite"] 188 | 189 | visible=false 190 | position=Vector2( -40.3475, 164.509 ) 191 | scale=Vector2( 0.9, 0.9 ) 192 | texture=ExtResource(2) 193 | flip_h=true 194 | region=true 195 | region_rect=Rect2( 50, 0, 14, 54 ) 196 | 197 | [node name="1-" parent="axes" type="Sprite"] 198 | 199 | visible=false 200 | position=Vector2( -67.6802, 137.926 ) 201 | scale=Vector2( 0.9, 0.9 ) 202 | texture=ExtResource(2) 203 | region=true 204 | region_rect=Rect2( 50, 0, 54, 14 ) 205 | 206 | [node name="1+" parent="axes" type="Sprite"] 207 | 208 | visible=false 209 | position=Vector2( -67.4618, 192.915 ) 210 | scale=Vector2( 0.9, 0.9 ) 211 | texture=ExtResource(2) 212 | flip_v=true 213 | region=true 214 | region_rect=Rect2( 50, 0, 54, 14 ) 215 | 216 | [node name="3-" parent="axes" type="Sprite"] 217 | 218 | visible=false 219 | position=Vector2( 76.6557, 140.986 ) 220 | scale=Vector2( 0.9, 0.9 ) 221 | texture=ExtResource(2) 222 | region=true 223 | region_rect=Rect2( 50, 0, 54, 14 ) 224 | 225 | [node name="3+" parent="axes" type="Sprite"] 226 | 227 | visible=false 228 | position=Vector2( 76.0009, 195.339 ) 229 | scale=Vector2( 0.9, 0.9 ) 230 | texture=ExtResource(2) 231 | flip_v=true 232 | region=true 233 | region_rect=Rect2( 50, 0, 54, 14 ) 234 | 235 | [node name="2-" parent="axes" type="Sprite"] 236 | 237 | visible=false 238 | position=Vector2( 48.8152, 167.145 ) 239 | scale=Vector2( 0.9, 0.9 ) 240 | texture=ExtResource(2) 241 | region=true 242 | region_rect=Rect2( 50, 0, 14, 54 ) 243 | 244 | [node name="2+" parent="axes" type="Sprite"] 245 | 246 | visible=false 247 | position=Vector2( 102.899, 167.857 ) 248 | scale=Vector2( 0.9, 0.9 ) 249 | texture=ExtResource(2) 250 | flip_h=true 251 | region=true 252 | region_rect=Rect2( 50, 0, 14, 54 ) 253 | -------------------------------------------------------------------------------- /mapping.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://remapping.gd" type="Script" id=1] 4 | [ext_resource path="res://jsdiagram.tscn" type="PackedScene" id=2] 5 | 6 | [node name="Main" type="Node"] 7 | 8 | script = ExtResource( 1 ) 9 | __meta__ = { 10 | "__editor_plugin_screen__": "2D" 11 | } 12 | 13 | [node name="diagram" parent="." instance=ExtResource( 2 )] 14 | 15 | position = Vector2( 434, 13 ) 16 | scale = Vector2( 0.5, 0.5 ) 17 | 18 | [node name="notice" type="RichTextLabel" parent="."] 19 | 20 | margin_left = 8.0 21 | margin_top = 289.0 22 | margin_right = 359.0 23 | margin_bottom = 415.0 24 | mouse_filter = 0 25 | size_flags_horizontal = 2 26 | size_flags_vertical = 2 27 | bbcode_enabled = true 28 | bbcode_text = "Mappings are SDL2 - compatible. 29 | But Godot has no hat events, only buttons and axes. 30 | This means that you will get two mappings: 31 | 32 | mapping a: dpad as hat 33 | mapping b: dpad as buttons 34 | 35 | Try them both to see which one has a working dpad!" 36 | visible_characters = -1 37 | 38 | [node name="label_a" type="Label" parent="."] 39 | 40 | margin_left = 11.0 41 | margin_top = 163.0 42 | margin_right = 73.0 43 | margin_bottom = 176.0 44 | rect_clip_content = false 45 | mouse_filter = 2 46 | size_flags_horizontal = 2 47 | size_flags_vertical = 0 48 | text = "mapping a:" 49 | percent_visible = 1.0 50 | lines_skipped = 0 51 | max_lines_visible = -1 52 | 53 | [node name="label_b" type="Label" parent="."] 54 | 55 | margin_left = 11.0 56 | margin_top = 198.0 57 | margin_right = 73.0 58 | margin_bottom = 211.0 59 | rect_clip_content = false 60 | mouse_filter = 2 61 | size_flags_horizontal = 2 62 | size_flags_vertical = 0 63 | text = "mapping b:" 64 | percent_visible = 1.0 65 | lines_skipped = 0 66 | max_lines_visible = -1 67 | 68 | [node name="mapping_a" type="LineEdit" parent="."] 69 | 70 | margin_left = 83.0 71 | margin_top = 159.0 72 | margin_right = 263.0 73 | margin_bottom = 182.0 74 | rect_clip_content = false 75 | mouse_filter = 0 76 | size_flags_horizontal = 2 77 | size_flags_vertical = 2 78 | editable = false 79 | expand_to_len = false 80 | focus_mode = 2 81 | placeholder_alpha = 0.6 82 | caret_blink = false 83 | caret_blink_speed = 0.65 84 | 85 | [node name="mapping_b" type="LineEdit" parent="."] 86 | 87 | margin_left = 83.0 88 | margin_top = 193.0 89 | margin_right = 263.0 90 | margin_bottom = 216.0 91 | rect_clip_content = false 92 | mouse_filter = 0 93 | size_flags_horizontal = 2 94 | size_flags_vertical = 2 95 | editable = false 96 | expand_to_len = false 97 | focus_mode = 2 98 | placeholder_alpha = 0.6 99 | caret_blink = false 100 | caret_blink_speed = 0.65 101 | 102 | [node name="start_button" type="Button" parent="."] 103 | 104 | margin_left = 11.0 105 | margin_top = 119.0 106 | margin_right = 185.0 107 | margin_bottom = 139.0 108 | rect_clip_content = false 109 | mouse_filter = 0 110 | size_flags_horizontal = 2 111 | size_flags_vertical = 2 112 | toggle_mode = false 113 | enabled_focus_mode = 2 114 | shortcut = null 115 | group = null 116 | text = "Start mapping" 117 | flat = false 118 | 119 | [node name="back" type="Button" parent="."] 120 | 121 | margin_left = 212.0 122 | margin_top = 119.0 123 | margin_right = 263.0 124 | margin_bottom = 138.0 125 | rect_clip_content = false 126 | mouse_filter = 0 127 | size_flags_horizontal = 2 128 | size_flags_vertical = 2 129 | disabled = true 130 | toggle_mode = false 131 | enabled_focus_mode = 2 132 | shortcut = null 133 | group = null 134 | text = "Back" 135 | flat = false 136 | 137 | [node name="skip" type="Button" parent="."] 138 | 139 | margin_left = 275.0 140 | margin_top = 119.0 141 | margin_right = 326.0 142 | margin_bottom = 138.0 143 | rect_clip_content = false 144 | mouse_filter = 0 145 | size_flags_horizontal = 2 146 | size_flags_vertical = 2 147 | disabled = true 148 | toggle_mode = false 149 | enabled_focus_mode = 2 150 | shortcut = null 151 | group = null 152 | text = "Skip" 153 | flat = false 154 | 155 | [node name="cancel" type="Button" parent="."] 156 | 157 | margin_left = 338.0 158 | margin_top = 119.0 159 | margin_right = 389.0 160 | margin_bottom = 138.0 161 | rect_clip_content = false 162 | mouse_filter = 0 163 | size_flags_horizontal = 2 164 | size_flags_vertical = 2 165 | disabled = true 166 | toggle_mode = false 167 | enabled_focus_mode = 2 168 | shortcut = null 169 | group = null 170 | text = "Cancel" 171 | flat = false 172 | 173 | [node name="apply_a" type="Button" parent="."] 174 | 175 | margin_left = 277.0 176 | margin_top = 161.0 177 | margin_right = 321.0 178 | margin_bottom = 180.0 179 | rect_clip_content = false 180 | mouse_filter = 0 181 | size_flags_horizontal = 2 182 | size_flags_vertical = 2 183 | disabled = true 184 | toggle_mode = false 185 | enabled_focus_mode = 2 186 | shortcut = null 187 | group = null 188 | text = "Apply" 189 | flat = false 190 | 191 | [node name="apply_b" type="Button" parent="."] 192 | 193 | margin_left = 277.0 194 | margin_top = 195.0 195 | margin_right = 321.0 196 | margin_bottom = 214.0 197 | rect_clip_content = false 198 | mouse_filter = 0 199 | size_flags_horizontal = 2 200 | size_flags_vertical = 2 201 | disabled = true 202 | toggle_mode = false 203 | enabled_focus_mode = 2 204 | shortcut = null 205 | group = null 206 | text = "Apply" 207 | flat = false 208 | 209 | [node name="label_name" type="Label" parent="."] 210 | 211 | margin_left = 11.0 212 | margin_top = 47.0 213 | margin_right = 48.0 214 | margin_bottom = 60.0 215 | rect_clip_content = false 216 | mouse_filter = 2 217 | size_flags_horizontal = 2 218 | size_flags_vertical = 0 219 | text = "Name:" 220 | percent_visible = 1.0 221 | lines_skipped = 0 222 | max_lines_visible = -1 223 | 224 | [node name="joy_name" type="Label" parent="."] 225 | 226 | margin_left = 69.0 227 | margin_top = 47.0 228 | margin_right = 222.0 229 | margin_bottom = 60.0 230 | rect_clip_content = false 231 | mouse_filter = 2 232 | size_flags_horizontal = 2 233 | size_flags_vertical = 0 234 | custom_colors/font_color = Color( 0.0625, 0.705492, 0.104534, 1 ) 235 | text = "X360 Controller" 236 | percent_visible = 1.0 237 | lines_skipped = 0 238 | max_lines_visible = -1 239 | 240 | [node name="label_guid" type="Label" parent="."] 241 | 242 | margin_left = 11.0 243 | margin_top = 70.0 244 | margin_right = 36.0 245 | margin_bottom = 83.0 246 | rect_clip_content = false 247 | mouse_filter = 2 248 | size_flags_horizontal = 2 249 | size_flags_vertical = 0 250 | text = "UID:" 251 | percent_visible = 1.0 252 | lines_skipped = 0 253 | max_lines_visible = -1 254 | 255 | [node name="joy_guid" type="Label" parent="."] 256 | 257 | margin_left = 69.0 258 | margin_top = 71.0 259 | margin_right = 197.0 260 | margin_bottom = 84.0 261 | rect_clip_content = false 262 | mouse_filter = 2 263 | size_flags_horizontal = 2 264 | size_flags_vertical = 0 265 | custom_colors/font_color = Color( 0.0625, 0.705492, 0.104534, 1 ) 266 | text = "030000005e0400008e02000014010000" 267 | percent_visible = 1.0 268 | lines_skipped = 0 269 | max_lines_visible = -1 270 | 271 | [node name="label_device" type="Label" parent="."] 272 | 273 | margin_left = 11.0 274 | margin_top = 14.0 275 | margin_right = 51.0 276 | margin_bottom = 27.0 277 | rect_clip_content = false 278 | mouse_filter = 2 279 | size_flags_horizontal = 2 280 | size_flags_vertical = 0 281 | text = "Device" 282 | percent_visible = 1.0 283 | lines_skipped = 0 284 | max_lines_visible = -1 285 | 286 | [node name="joy_num" type="SpinBox" parent="."] 287 | 288 | margin_left = 71.0 289 | margin_top = 9.0 290 | margin_right = 145.0 291 | margin_bottom = 33.0 292 | rect_clip_content = false 293 | mouse_filter = 0 294 | size_flags_horizontal = 2 295 | size_flags_vertical = 2 296 | min_value = 0.0 297 | max_value = 15.0 298 | step = 1.0 299 | page = 0.0 300 | value = 0.0 301 | exp_edit = false 302 | rounded = false 303 | editable = true 304 | prefix = "" 305 | suffix = "" 306 | 307 | [node name="label_mapped" type="Label" parent="."] 308 | 309 | margin_left = 11.0 310 | margin_top = 95.0 311 | margin_right = 48.0 312 | margin_bottom = 108.0 313 | rect_clip_content = false 314 | mouse_filter = 2 315 | size_flags_horizontal = 2 316 | size_flags_vertical = 0 317 | text = "Mapped:" 318 | percent_visible = 1.0 319 | lines_skipped = 0 320 | max_lines_visible = -1 321 | 322 | [node name="joy_mapped" type="Label" parent="."] 323 | 324 | margin_left = 69.0 325 | margin_top = 95.0 326 | margin_right = 222.0 327 | margin_bottom = 108.0 328 | rect_clip_content = false 329 | mouse_filter = 2 330 | size_flags_horizontal = 2 331 | size_flags_vertical = 0 332 | custom_colors/font_color = Color( 0.0625, 0.705492, 0.104534, 1 ) 333 | text = "Yes" 334 | percent_visible = 1.0 335 | lines_skipped = 0 336 | max_lines_visible = -1 337 | 338 | [node name="xinput_notice" type="AcceptDialog" parent="."] 339 | 340 | visible = false 341 | margin_left = 208.0 342 | margin_top = 192.0 343 | margin_right = 448.0 344 | margin_bottom = 262.0 345 | rect_clip_content = false 346 | mouse_filter = 0 347 | size_flags_horizontal = 2 348 | size_flags_vertical = 2 349 | popup_exclusive = false 350 | window_title = "Alert!" 351 | resizable = false 352 | dialog_text = "XInput devices don't need a mapping" 353 | dialog_hide_on_ok = true 354 | 355 | [node name="copy_a" type="Button" parent="."] 356 | 357 | margin_left = 342.0 358 | margin_top = 161.0 359 | margin_right = 386.0 360 | margin_bottom = 180.0 361 | rect_clip_content = false 362 | mouse_filter = 0 363 | size_flags_horizontal = 2 364 | size_flags_vertical = 2 365 | disabled = true 366 | toggle_mode = false 367 | enabled_focus_mode = 2 368 | shortcut = null 369 | group = null 370 | text = "Copy" 371 | flat = false 372 | 373 | [node name="copy_b" type="Button" parent="."] 374 | 375 | margin_left = 342.0 376 | margin_top = 195.0 377 | margin_right = 386.0 378 | margin_bottom = 214.0 379 | rect_clip_content = false 380 | mouse_filter = 0 381 | size_flags_horizontal = 2 382 | size_flags_vertical = 2 383 | disabled = true 384 | toggle_mode = false 385 | enabled_focus_mode = 2 386 | shortcut = null 387 | group = null 388 | text = "Copy" 389 | flat = false 390 | 391 | [node name="input_timer" type="Timer" parent="."] 392 | 393 | process_mode = 0 394 | wait_time = 0.2 395 | one_shot = true 396 | autostart = false 397 | 398 | [node name="extra_event_diag" type="AcceptDialog" parent="."] 399 | 400 | visible = false 401 | margin_left = 162.0 402 | margin_top = 122.0 403 | margin_right = 542.0 404 | margin_bottom = 314.0 405 | rect_clip_content = false 406 | mouse_filter = 0 407 | size_flags_horizontal = 2 408 | size_flags_vertical = 2 409 | popup_exclusive = false 410 | window_title = "Alert!" 411 | resizable = false 412 | dialog_hide_on_ok = true 413 | 414 | [node name="description" type="Label" parent="extra_event_diag"] 415 | 416 | margin_left = 8.0 417 | margin_top = 8.0 418 | margin_right = 403.0 419 | margin_bottom = 156.0 420 | rect_clip_content = false 421 | mouse_filter = 2 422 | size_flags_horizontal = 2 423 | size_flags_vertical = 0 424 | text = "Oops, looks like we have recieved multiple events for action: " 425 | percent_visible = 1.0 426 | lines_skipped = 0 427 | max_lines_visible = -1 428 | 429 | [node name="action_label" type="Label" parent="extra_event_diag"] 430 | 431 | margin_left = 8.0 432 | margin_top = 8.0 433 | margin_right = 403.0 434 | margin_bottom = 156.0 435 | rect_clip_content = false 436 | mouse_filter = 2 437 | size_flags_horizontal = 2 438 | size_flags_vertical = 0 439 | custom_colors/font_color = Color( 0.451875, 0.980469, 0.0536194, 1 ) 440 | text = "TEST" 441 | align = 1 442 | percent_visible = 1.0 443 | lines_skipped = 0 444 | max_lines_visible = -1 445 | 446 | [node name="description_1" type="Label" parent="extra_event_diag"] 447 | 448 | margin_left = 8.0 449 | margin_top = 8.0 450 | margin_right = 403.0 451 | margin_bottom = 156.0 452 | rect_clip_content = false 453 | mouse_filter = 2 454 | size_flags_horizontal = 2 455 | size_flags_vertical = 0 456 | text = "Choose an event from the list below" 457 | percent_visible = 1.0 458 | lines_skipped = 0 459 | max_lines_visible = -1 460 | 461 | [node name="MenuButton" type="MenuButton" parent="extra_event_diag"] 462 | 463 | margin_left = 8.0 464 | margin_top = 8.0 465 | margin_right = 403.0 466 | margin_bottom = 156.0 467 | rect_clip_content = false 468 | mouse_filter = 0 469 | size_flags_horizontal = 2 470 | size_flags_vertical = 2 471 | toggle_mode = false 472 | action_mode = 0 473 | enabled_focus_mode = 0 474 | shortcut = null 475 | group = null 476 | text = "Choose event" 477 | flat = false 478 | items = [ ] 479 | 480 | [connection signal="value_changed" from="joy_num" to="." method="_on_joy_num_value_changed"] 481 | 482 | [connection signal="timeout" from="input_timer" to="." method="_input_timeout"] 483 | 484 | [connection signal="confirmed" from="extra_event_diag" to="." method="_extra_event_diag_confirmed"] 485 | 486 | 487 | -------------------------------------------------------------------------------- /remapping.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | const buttons = ["a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", 4 | "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright"] 5 | 6 | const axes = ["leftx", "lefty", "rightx", "righty", "", "", "lefttrigger", "righttrigger"] 7 | 8 | const hat = { 12:"h0.1", 13:"h0.4", 14:"h0.8", 15:"h0.2" } 9 | 10 | onready var joy_num = get_node("joy_num") 11 | onready var joy_name = get_node("joy_name") 12 | onready var joy_guid = get_node("joy_guid") 13 | onready var joy_mapped = get_node("joy_mapped") 14 | onready var mapping_label_a = get_node("mapping_a") 15 | onready var mapping_label_b = get_node("mapping_b") 16 | onready var timer = get_node("input_timer") 17 | onready var diag = get_node("extra_event_diag") 18 | onready var popup = diag.get_node("MenuButton").get_popup() 19 | var device_id = 0 20 | var device_uid = "" 21 | var device_name = "" 22 | var device_mapped = false setget on_device_mapped_changed 23 | var mapping_a = "" 24 | var mapping_b = "" 25 | var to_button 26 | var to_axis 27 | var from_button 28 | var from_axis 29 | var ignore_axes = [] 30 | var possible_events = [] 31 | var got_button 32 | var skip = false 33 | var cancel = false 34 | var do_mapping = false 35 | var got_extra_input = false 36 | var event_chosen = false 37 | 38 | func _ready(): 39 | _on_joy_num_value_changed(0) 40 | set_fixed_process(true) 41 | set_process_input(true) 42 | add_user_signal("input_recieved") 43 | diag.get_node("MenuButton").get_popup().connect("item_pressed", self, "_event_selected") 44 | 45 | func _input(event): 46 | if !do_mapping: 47 | if (event.is_action_released("start_mapping")): 48 | _on_start_button_released() 49 | else: 50 | if (event.type == InputEvent.KEY): 51 | print(event.scancode) 52 | if (event.is_action_released("mapping_back")): 53 | _on_back_released() 54 | if (event.is_action_released("mapping_skip")): 55 | _on_skip_released() 56 | if (event.is_action_released("mapping_cancel")): 57 | _on_cancel_released() 58 | if (event.device != device_id): 59 | return 60 | if (event.type == InputEvent.JOYPAD_MOTION and abs(event.value) > 0.7): 61 | if (event.axis in ignore_axes): 62 | return 63 | if !(to_button > 11 and to_button < 16): 64 | ignore_axes.append(event.axis) 65 | from_axis = event.axis 66 | got_button = false 67 | start_timer(event) 68 | elif (event.type == InputEvent.JOYPAD_BUTTON and !event.pressed): 69 | from_button = event.button_index 70 | got_button = true 71 | start_timer(event) 72 | 73 | func _fixed_process(delta): 74 | 75 | if do_mapping: 76 | return 77 | if (device_name != Input.get_joy_name(device_id)): 78 | _on_joy_num_value_changed(device_id) 79 | for btn in range(16): 80 | var pressed = Input.is_joy_button_pressed(device_id, btn) 81 | var indicator = get_node("diagram/buttons/" + str(btn)) 82 | if (pressed): 83 | indicator.show() 84 | else: 85 | indicator.hide() 86 | for axis in range(4): 87 | var value = Input.get_joy_axis(device_id, axis) 88 | var positive = get_node("diagram/axes/" + str(axis) + "+") 89 | var negative = get_node("diagram/axes/" + str(axis) + "-") 90 | if (abs(value) < 0.2): 91 | positive.hide() 92 | negative.hide() 93 | continue 94 | if (value > 0): 95 | positive.show() 96 | else: 97 | negative.show() 98 | 99 | func start_mapping(): 100 | do_mapping = true 101 | mapping_a = device_uid + "," + device_name + "," 102 | mapping_b = device_uid + "," + device_name + "," 103 | to_button = 0 104 | to_axis = 0 105 | ignore_axes = [] 106 | var finished = false 107 | var map_a = {} 108 | var map_b = {} 109 | while(true): 110 | 111 | if to_button < 16: 112 | var indicator = get_node("diagram/buttons/" + str(to_button)) 113 | indicator.show() 114 | yield(self, "input_recieved") 115 | if cancel: 116 | break 117 | if skip: 118 | skip = false 119 | indicator.hide() 120 | continue 121 | if !got_button: 122 | var axis_mapping = "a" + str(from_axis) 123 | map_a[buttons[to_button]] = axis_mapping 124 | map_b[buttons[to_button]] = axis_mapping 125 | else: 126 | var button_mapping = "b" + str(from_button) 127 | map_b[buttons[to_button]] = button_mapping 128 | if from_button in hat: 129 | map_a[buttons[to_button]] = hat[from_button] 130 | else: 131 | map_a[buttons[to_button]] = button_mapping 132 | indicator.hide() 133 | to_button += 1 134 | continue 135 | 136 | if to_axis < 4: 137 | var indicator_pos = get_node("diagram/axes/" + str(to_axis) + "+") 138 | var indicator_neg = get_node("diagram/axes/" + str(to_axis) + "-") 139 | indicator_pos.show() 140 | indicator_neg.show() 141 | 142 | yield(self, "input_recieved") 143 | if cancel: 144 | break 145 | if skip: 146 | skip = false 147 | indicator_pos.hide() 148 | indicator_neg.hide() 149 | continue 150 | if got_button: 151 | var button_mapping = "b" + str(from_button) 152 | map_a[axes[to_axis]] = button_mapping 153 | map_b[axes[to_axis]] = button_mapping 154 | else: 155 | var axis_mapping = "a" + str(from_axis) 156 | map_a[axes[to_axis]] = axis_mapping 157 | map_b[axes[to_axis]] = axis_mapping 158 | to_axis += 1 159 | indicator_pos.hide() 160 | indicator_neg.hide() 161 | continue 162 | finished = true 163 | break 164 | 165 | for key in map_a.keys(): 166 | mapping_a += key + ":" + map_a[key] + "," 167 | 168 | for key in map_b.keys(): 169 | mapping_b += key + ":" + map_b[key] + "," 170 | 171 | get_node("back").set_disabled(true) 172 | get_node("cancel").set_disabled(true) 173 | get_node("skip").set_disabled(true) 174 | if finished: 175 | get_node("apply_a").set_disabled(false) 176 | get_node("apply_b").set_disabled(false) 177 | get_node("copy_a").set_disabled(false) 178 | get_node("copy_b").set_disabled(false) 179 | mapping_label_a.set_text(mapping_a) 180 | mapping_label_b.set_text(mapping_b) 181 | print("MAPPING A: ", mapping_a) 182 | print("MAPPING B: ", mapping_b) 183 | Input.add_joy_mapping(mapping_a, true) 184 | do_mapping = false 185 | 186 | func hide_all_indicators(): 187 | for indicator in get_node("diagram/axes").get_children(): 188 | indicator.hide() 189 | for indicator in get_node("diagram/buttons").get_children(): 190 | indicator.hide() 191 | 192 | func _on_joy_num_value_changed( value ): 193 | device_id = value 194 | device_name = Input.get_joy_name(device_id) 195 | device_uid = Input.get_joy_guid(device_id) 196 | self.device_mapped = Input.is_joy_known(device_id) 197 | joy_name.set_text(device_name) 198 | joy_guid.set_text(device_uid) 199 | 200 | func on_device_mapped_changed(mapped): 201 | if mapped: 202 | joy_mapped.set_text("Yes") 203 | else: 204 | joy_mapped.set_text("No") 205 | 206 | func _on_start_button_released(): 207 | if device_uid == "__XINPUT_DEVICE__": 208 | get_node("xinput_notice").show() 209 | return 210 | hide_all_indicators() 211 | get_node("back").set_disabled(false) 212 | get_node("cancel").set_disabled(false) 213 | get_node("skip").set_disabled(false) 214 | on_device_mapped_changed(device_id) 215 | Input.remove_joy_mapping(device_uid) 216 | start_mapping() 217 | 218 | func _on_apply_a_released(): 219 | var text = mapping_label_a.get_text() 220 | if text != "": 221 | Input.add_joy_mapping(mapping_a, true) 222 | self.device_mapped = true 223 | 224 | func _on_apply_b_released(): 225 | var text = mapping_label_b.get_text() 226 | if text != "": 227 | Input.add_joy_mapping(mapping_b, true) 228 | self.device_mapped = true 229 | 230 | func _on_back_released(): 231 | if to_button == 0: 232 | return 233 | 234 | if to_button < 16: 235 | to_button -= 1 236 | elif to_axis == 0: 237 | to_button = 15 238 | else: 239 | to_axis -= 1 240 | skip = true 241 | emit_signal("input_recieved") 242 | 243 | func _on_cancel_released(): 244 | cancel = true; 245 | emit_signal("input_recieved") 246 | 247 | func _on_skip_released(): 248 | if to_button == 15: 249 | to_button = 16 250 | elif to_button < 15: 251 | to_button += 1 252 | elif to_axis < 4: 253 | to_axis += 1 254 | skip = true 255 | emit_signal("input_recieved") 256 | 257 | func _on_copy_a_released(): 258 | OS.set_clipboard(mapping_a) 259 | 260 | func _on_copy_b_released(): 261 | OS.set_clipboard(mapping_b) 262 | 263 | func start_timer(event): 264 | possible_events.append(event) 265 | if !got_extra_input: 266 | timer.start() 267 | got_extra_input = true 268 | else: 269 | timer.stop() 270 | popup.clear() 271 | for ev in possible_events: 272 | var item 273 | if ev.type == InputEvent.JOYPAD_BUTTON: 274 | item = "Joy Button " + str(ev.button_index) 275 | else: 276 | item = "Joy Axis " + str(ev.axis) 277 | popup.add_item(item) 278 | diag.show() 279 | var action = diag.get_node("action_label") 280 | if to_button < JOY_BUTTON_MAX: 281 | action.set_text(buttons[to_button]) 282 | else: 283 | action.set_text(axes[to_axis]) 284 | diag.get_node("MenuButton").set_text("Choose event") 285 | event_chosen = false 286 | 287 | func _input_timeout(): 288 | got_extra_input = false 289 | emit_signal("input_recieved") 290 | possible_events = [] 291 | 292 | func _event_selected(index): 293 | var ev = possible_events[index] 294 | if ev.type == InputEvent.JOYPAD_BUTTON: 295 | got_button = true 296 | from_button = ev.button_index 297 | else: 298 | got_button = false 299 | from_axis = ev.axis 300 | event_chosen = true 301 | diag.get_node("MenuButton").set_text(popup.get_item_text(index)) 302 | 303 | func _extra_event_diag_confirmed(): 304 | if !event_chosen: 305 | diag.show() 306 | else: 307 | _input_timeout() 308 | --------------------------------------------------------------------------------