The open source OpenXR runtime

aux/bindings: Add "features" to inputs in bindings.json

In our model we have a "subpath" for each hardware input like "/input/trackpad".
Each of these hardware inputs has "features" like "click", "touch", "position", "force".

Ideally each of these "features" is bound to some monado input in the "monado_bindings" dict
but this is not required. bindings.json will know about hardware features even if we don't bind them (yet).

For each of these features bindings.py generates a group of related paths for a single monado binding:
For a monado input XRT_INPUT_???_TRACKPAD these paths would be generated:
/user/hand/left/input/trackpad/x
/user/hand/left/input/trackpad/y
/user/hand/left/input/trackpad

+260 -335
+171 -226
src/xrt/auxiliary/bindings/bindings.json
··· 12 12 "/input/select": { 13 13 "type": "button", 14 14 "localized_name": "Select", 15 - "click": true, 16 - "touch": false, 15 + "features": ["click"], 17 16 "monado_bindings": { 18 17 "click": "XRT_INPUT_SIMPLE_SELECT_CLICK" 19 18 } ··· 21 20 "/input/menu": { 22 21 "type": "button", 23 22 "localized_name": "Menu", 24 - "click": true, 25 - "touch": false, 23 + "features": ["click"], 26 24 "monado_bindings": { 27 25 "click": "XRT_INPUT_SIMPLE_MENU_CLICK" 28 26 } ··· 30 28 "/input/grip": { 31 29 "type": "pose", 32 30 "localized_name": "Grip", 31 + "features": ["pose"], 33 32 "monado_bindings": { 34 33 "pose": "XRT_INPUT_SIMPLE_GRIP_POSE" 35 34 } ··· 37 36 "/input/aim": { 38 37 "type": "pose", 39 38 "localized_name": "Aim", 39 + "features": ["pose"], 40 40 "monado_bindings": { 41 41 "pose": "XRT_INPUT_SIMPLE_AIM_POSE" 42 42 } ··· 44 44 "/output/haptic": { 45 45 "type": "vibration", 46 46 "localized_name": "Haptic", 47 + "features": ["haptic"], 47 48 "monado_bindings": { 48 49 "haptic": "XRT_OUTPUT_NAME_SIMPLE_VIBRATION" 49 50 } ··· 63 64 "/input/select": { 64 65 "type": "button", 65 66 "localized_name": "Select", 66 - "click": true, 67 - "touch": false, 67 + "features": ["click"], 68 68 "monado_bindings": { 69 69 "click": "XRT_INPUT_DAYDREAM_BAR_CLICK" 70 70 } ··· 72 72 "/input/trackpad": { 73 73 "type": "trackpad", 74 74 "localized_name": "Trackpad", 75 - "force": false, 76 - "touch": true, 77 - "click": true, 75 + "features": ["touch", "click", "position"], 78 76 "monado_bindings": { 79 77 "touch": "XRT_INPUT_DAYDREAM_TOUCHPAD_TOUCH", 80 78 "click": "XRT_INPUT_DAYDREAM_TOUCHPAD_CLICK", ··· 84 82 "/input/grip": { 85 83 "type": "pose", 86 84 "localized_name": "Grip", 85 + "features": ["pose"], 87 86 "monado_bindings": { 88 87 "pose": "XRT_INPUT_DAYDREAM_POSE" 89 88 } ··· 91 90 "/input/aim": { 92 91 "type": "pose", 93 92 "localized_name": "Aim", 93 + "features": ["pose"], 94 94 "monado_bindings": { 95 95 "pose": "XRT_INPUT_DAYDREAM_POSE" 96 96 } ··· 110 110 "/input/system": { 111 111 "type": "button", 112 112 "localized_name": "System", 113 - "click": true, 114 - "touch": false, 113 + "features": ["click"], 115 114 "monado_bindings": { 116 115 "click": "XRT_INPUT_VIVE_SYSTEM_CLICK" 117 116 } ··· 119 118 "/input/squeeze": { 120 119 "type": "button", 121 120 "localized_name": "Squeeze", 122 - "click": true, 123 - "touch": false, 121 + "features": ["click"], 124 122 "monado_bindings": { 125 123 "click": "XRT_INPUT_VIVE_SQUEEZE_CLICK" 126 124 } ··· 128 126 "/input/menu": { 129 127 "type": "button", 130 128 "localized_name": "Menu", 131 - "click": true, 132 - "touch": false, 129 + "features": ["click"], 133 130 "monado_bindings": { 134 131 "click": "XRT_INPUT_VIVE_MENU_CLICK" 135 132 } ··· 137 134 "/input/trigger": { 138 135 "type": "trigger", 139 136 "localized_name": "Trigger", 140 - "click": true, 141 - "touch": false, 142 - "value": true, 137 + "features": ["click", "value"], 143 138 "monado_bindings": { 144 139 "click": "XRT_INPUT_VIVE_TRIGGER_CLICK", 145 140 "value": "XRT_INPUT_VIVE_TRIGGER_VALUE" ··· 148 143 "/input/trackpad": { 149 144 "type": "trackpad", 150 145 "localized_name": "Trackpad", 151 - "force": false, 152 - "touch": true, 153 - "click": true, 146 + "features": ["click", "touch", "position"], 154 147 "monado_bindings": { 155 148 "click": "XRT_INPUT_VIVE_TRACKPAD_CLICK", 156 149 "touch": "XRT_INPUT_VIVE_TRACKPAD_TOUCH", ··· 160 153 "/input/grip": { 161 154 "type": "pose", 162 155 "localized_name": "Grip", 156 + "features": ["pose"], 163 157 "monado_bindings": { 164 158 "pose": "XRT_INPUT_VIVE_GRIP_POSE" 165 159 } ··· 167 161 "/input/aim": { 168 162 "type": "pose", 169 163 "localized_name": "Aim", 164 + "features": ["pose"], 170 165 "monado_bindings": { 171 166 "pose": "XRT_INPUT_VIVE_AIM_POSE" 172 167 } ··· 174 169 "/output/haptic": { 175 170 "type": "vibration", 176 171 "localized_name": "Haptic", 172 + "features": ["haptic"], 177 173 "monado_bindings": { 178 174 "haptic": "XRT_OUTPUT_NAME_VIVE_HAPTIC" 179 175 } ··· 192 188 "/input/system": { 193 189 "type": "button", 194 190 "localized_name": "System", 195 - "click": "true", 196 - "touch": false, 191 + "features": ["click"], 197 192 "monado_bindings": { 198 193 "click": "XRT_INPUT_VIVEPRO_SYSTEM_CLICK" 199 194 } ··· 201 196 "/input/volume_up": { 202 197 "type": "button", 203 198 "localized_name": "Volume Up", 204 - "click": true, 205 - "touch": false, 199 + "features": ["click"], 206 200 "monado_bindings": { 207 201 "click": "XRT_INPUT_VIVEPRO_VOLUP_CLICK" 208 202 } ··· 210 204 "/input/volume_down": { 211 205 "type": "button", 212 206 "localized_name": "Volume Down", 213 - "click": true, 214 - "touch": false, 207 + "features": ["click"], 215 208 "monado_bindings": { 216 209 "click": "XRT_INPUT_VIVEPRO_VOLDN_CLICK" 217 210 } ··· 219 212 "/input/mute_mic": { 220 213 "type": "button", 221 214 "localized_name": "Mute Microphone", 222 - "click": true, 223 - "touch": false, 215 + "features": ["click"], 224 216 "monado_bindings": { 225 217 "click": "XRT_INPUT_VIVEPRO_MUTE_MIC_CLICK" 226 218 } ··· 240 232 "/input/menu": { 241 233 "type": "button", 242 234 "localized_name": "Menu", 243 - "click": true, 244 - "touch": false, 235 + "features": ["click"], 245 236 "monado_bindings": { 246 237 "click": "XRT_INPUT_WMR_MENU_CLICK" 247 238 } ··· 249 240 "/input/squeeze": { 250 241 "type": "button", 251 242 "localized_name": "Squeeze", 252 - "click": true, 253 - "touch": false, 243 + "features": ["click"], 254 244 "monado_bindings": { 255 245 "click": "XRT_INPUT_WMR_SQUEEZE_CLICK" 256 246 } ··· 258 248 "/input/trigger": { 259 249 "type": "trigger", 260 250 "localized_name": "Trigger", 261 - "click": false, 262 - "touch": false, 263 - "value": true, 251 + "features": ["value"], 264 252 "monado_bindings": { 265 253 "value": "XRT_INPUT_WMR_TRIGGER_VALUE" 266 254 } ··· 268 256 "/input/thumbstick": { 269 257 "type": "joystick", 270 258 "localized_name": "Thumbstick", 271 - "click": true, 272 - "touch": false, 259 + "features": ["click", "position"], 273 260 "monado_bindings": { 274 261 "click": "XRT_INPUT_WMR_THUMBSTICK_CLICK", 275 262 "position": "XRT_INPUT_WMR_THUMBSTICK" ··· 278 265 "/input/trackpad": { 279 266 "type": "trackpad", 280 267 "localized_name": "Trackpad", 281 - "force": false, 282 - "click": true, 283 - "touch": true, 268 + "features": ["click", "touch", "position"], 284 269 "monado_bindings": { 285 270 "click": "XRT_INPUT_WMR_TRACKPAD_CLICK", 286 271 "touch": "XRT_INPUT_WMR_TRACKPAD_TOUCH", ··· 290 275 "/input/grip": { 291 276 "type": "pose", 292 277 "localized_name": "Grip", 278 + "features": ["pose"], 293 279 "monado_bindings": { 294 280 "pose": "XRT_INPUT_WMR_GRIP_POSE" 295 281 } ··· 297 283 "/input/aim": { 298 284 "type": "pose", 299 285 "localized_name": "Aim", 286 + "features": ["pose"], 300 287 "monado_bindings": { 301 288 "pose": "XRT_INPUT_WMR_AIM_POSE" 302 289 } ··· 304 291 "/output/haptic": { 305 292 "type": "vibration", 306 293 "localized_name": "Haptic", 294 + "features": ["haptic"], 307 295 "monado_bindings": { 308 296 "haptic": "XRT_OUTPUT_NAME_WMR_HAPTIC" 309 297 } ··· 322 310 "/input/menu": { 323 311 "type": "button", 324 312 "localized_name": "Menu", 325 - "click": true, 326 - "touch": false, 313 + "features": ["click"], 327 314 "monado_bindings": { 328 315 "click": "XRT_INPUT_XBOX_MENU_CLICK" 329 316 } ··· 331 318 "/input/view": { 332 319 "type": "button", 333 320 "localized_name": "View", 334 - "click": true, 335 - "touch": false, 321 + "features": ["click"], 336 322 "monado_bindings": { 337 323 "click": "XRT_INPUT_XBOX_VIEW_CLICK" 338 324 } ··· 340 326 "/input/a": { 341 327 "type": "button", 342 328 "localized_name": "A", 343 - "click": true, 344 - "touch": false, 329 + "features": ["click"], 345 330 "monado_bindings": { 346 331 "click": "XRT_INPUT_XBOX_A_CLICK" 347 332 } ··· 349 334 "/input/b": { 350 335 "type": "button", 351 336 "localized_name": "B", 352 - "click": true, 353 - "touch": false, 337 + "features": ["click"], 354 338 "monado_bindings": { 355 339 "click": "XRT_INPUT_XBOX_B_CLICK" 356 340 } ··· 358 342 "/input/x": { 359 343 "type": "button", 360 344 "localized_name": "X", 361 - "click": true, 362 - "touch": false, 345 + "features": ["click"], 363 346 "monado_bindings": { 364 347 "click": "XRT_INPUT_XBOX_X_CLICK" 365 348 } ··· 367 350 "/input/y": { 368 351 "type": "button", 369 352 "localized_name": "Y", 370 - "click": true, 371 - "touch": false, 353 + "features": ["click"], 372 354 "monado_bindings": { 373 355 "click": "XRT_INPUT_XBOX_Y_CLICK" 374 356 } ··· 376 358 "/input/dpad_down": { 377 359 "type": "button", 378 360 "localized_name": "DPAD down", 379 - "click": true, 380 - "touch": false, 361 + "features": ["click"], 381 362 "monado_bindings": { 382 363 "click": "XRT_INPUT_XBOX_DPAD_DOWN_CLICK" 383 364 } ··· 385 366 "/input/dpad_right": { 386 367 "type": "button", 387 368 "localized_name": "DPAD right", 388 - "click": true, 389 - "touch": false, 369 + "features": ["click"], 390 370 "monado_bindings": { 391 371 "click": "XRT_INPUT_XBOX_DPAD_RIGHT_CLICK" 392 372 } ··· 394 374 "/input/dpad_up": { 395 375 "type": "button", 396 376 "localized_name": "DPAD up", 397 - "click": true, 398 - "touch": false, 377 + "features": ["click"], 399 378 "monado_bindings": { 400 379 "click": "XRT_INPUT_XBOX_DPAD_UP_CLICK" 401 380 } ··· 403 382 "/input/dpad_left": { 404 383 "type": "button", 405 384 "localized_name": "DPAD left", 406 - "click": true, 407 - "touch": false, 385 + "features": ["click"], 408 386 "monado_bindings": { 409 387 "click": "XRT_INPUT_XBOX_DPAD_LEFT_CLICK" 410 388 } ··· 412 390 "/input/shoulder_left": { 413 391 "type": "button", 414 392 "localized_name": "Shoulder left", 415 - "click": true, 416 - "touch": false, 393 + "features": ["click"], 417 394 "monado_bindings": { 418 395 "click": "XRT_INPUT_XBOX_SHOULDER_LEFT_CLICK" 419 396 } ··· 421 398 "/input/shoulder_right": { 422 399 "type": "button", 423 400 "localized_name": "Shoulder right", 424 - "click": true, 425 - "touch": false, 401 + "features": ["click"], 426 402 "monado_bindings": { 427 403 "click": "XRT_INPUT_XBOX_SHOULDER_RIGHT_CLICK" 428 404 } ··· 430 406 "/input/thumbstick_left": { 431 407 "type": "joystick", 432 408 "localized_name": "Left Thumbstick", 433 - "click": true, 434 - "touch": false, 409 + "features": ["click", "position"], 435 410 "monado_bindings": { 436 411 "click": "XRT_INPUT_XBOX_THUMBSTICK_LEFT_CLICK", 437 412 "position": "XRT_INPUT_XBOX_THUMBSTICK_LEFT" ··· 440 415 "/input/thumbstick_right": { 441 416 "type": "joystick", 442 417 "localized_name": "Right Thumbstick", 443 - "click": true, 444 - "touch": false, 418 + "features": ["click", "position"], 445 419 "monado_bindings": { 446 420 "click": "XRT_INPUT_XBOX_THUMBSTICK_RIGHT_CLICK", 447 421 "position": "XRT_INPUT_XBOX_THUMBSTICK_RIGHT" ··· 450 424 "/input/trigger_left": { 451 425 "type": "trigger", 452 426 "localized_name": "Left Trigger", 453 - "click": false, 454 - "touch": false, 455 - "value": true, 427 + "features": ["value"], 456 428 "monado_bindings": { 457 429 "value": "XRT_INPUT_XBOX_LEFT_TRIGGER_VALUE" 458 430 } ··· 460 432 "/input/trigger_right": { 461 433 "type": "trigger", 462 434 "localized_name": "Right Trigger", 463 - "click": false, 464 - "touch": false, 465 - "value": true, 435 + "features": ["value"], 466 436 "monado_bindings": { 467 437 "value": "XRT_INPUT_XBOX_RIGHT_TRIGGER_VALUE" 468 438 } ··· 470 440 "/output/haptic_left": { 471 441 "type": "vibration", 472 442 "localized_name": "Left Haptic", 443 + "features": ["haptic"], 473 444 "monado_bindings": { 474 445 "haptic": "XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT" 475 446 } ··· 477 448 "/output/haptic_right": { 478 449 "type": "vibration", 479 450 "localized_name": "Right Haptic", 451 + "features": ["haptic"], 480 452 "monado_bindings": { 481 453 "haptic": "XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHTT" 482 454 } ··· 484 456 "/output/haptic_left_trigger": { 485 457 "type": "vibration", 486 458 "localized_name": "Left Trigger Haptic", 459 + "features": ["haptic"], 487 460 "monado_bindings": { 488 461 "haptic": "XRT_OUTPUT_NAME_XBOX_HAPTIC_LEFT_TRIGGER" 489 462 } ··· 491 464 "/output/haptic_right_trigger": { 492 465 "type": "vibration", 493 466 "localized_name": "Right Trigger Haptic", 467 + "features": ["haptic"], 494 468 "monado_bindings": { 495 469 "haptic": "XRT_OUTPUT_NAME_XBOX_HAPTIC_RIGHT_TRIGGER" 496 470 } ··· 510 484 "/input/system": { 511 485 "type": "button", 512 486 "localized_name": "System", 513 - "click": true, 514 - "touch": false, 487 + "features": ["click"], 515 488 "monado_bindings": { 516 489 "click": "XRT_INPUT_GO_SYSTEM_CLICK" 517 490 } ··· 519 492 "/input/trigger": { 520 493 "type": "button", 521 494 "localized_name": "Trigger", 522 - "click": true, 523 - "touch": false, 495 + "features": ["click"], 524 496 "monado_bindings": { 525 497 "click": "XRT_INPUT_GO_TRIGGER_CLICK" 526 498 } ··· 528 500 "/input/back": { 529 501 "type": "button", 530 502 "localized_name": "Back", 531 - "click": true, 532 - "touch": false, 503 + "features": ["click"], 533 504 "monado_bindings": { 534 505 "click": "XRT_INPUT_GO_BACK_CLICK" 535 506 } ··· 537 508 "/input/trackpad": { 538 509 "type": "trackpad", 539 510 "localized_name": "Trackpad", 540 - "force": false, 541 - "click": true, 542 - "touch": true, 511 + "features": ["click", "touch", "position"], 543 512 "monado_bindings": { 544 513 "click": "XRT_INPUT_GO_TRACKPAD_CLICK", 545 514 "touch": "XRT_INPUT_GO_TRACKPAD_TOUCH", ··· 549 518 "/input/grip": { 550 519 "type": "pose", 551 520 "localized_name": "Grip", 521 + "features": ["pose"], 552 522 "monado_bindings": { 553 523 "pose": "XRT_INPUT_GO_GRIP_POSE" 554 524 } ··· 556 526 "/input/aim": { 557 527 "type": "pose", 558 528 "localized_name": "Aim", 529 + "features": ["pose"], 559 530 "monado_bindings": { 560 531 "pose": "XRT_INPUT_GO_AIM_POSE" 561 532 } ··· 575 546 "/input/x": { 576 547 "type": "button", 577 548 "localized_name": "X", 578 - "click": true, 579 - "touch": true, 549 + "features": ["click", "touch"], 580 550 "side": "left", 581 551 "monado_bindings": { 582 552 "click": "XRT_INPUT_TOUCH_X_CLICK", ··· 586 556 "/input/y": { 587 557 "type": "button", 588 558 "localized_name": "Y", 589 - "click": true, 590 - "touch": true, 559 + "features": ["click", "touch"], 591 560 "side": "left", 592 561 "monado_bindings": { 593 562 "click": "XRT_INPUT_TOUCH_Y_CLICK", ··· 597 566 "/input/menu": { 598 567 "type": "button", 599 568 "localized_name": "Menu", 600 - "click": true, 601 - "touch": false, 569 + "features": ["click"], 602 570 "side": "left", 603 571 "monado_bindings": { 604 572 "click": "XRT_INPUT_TOUCH_MENU_CLICK" ··· 607 575 "/input/a": { 608 576 "type": "button", 609 577 "localized_name": "A", 610 - "click": true, 611 - "touch": true, 578 + "features": ["click", "touch"], 612 579 "side": "right", 613 580 "monado_bindings": { 614 581 "click": "XRT_INPUT_TOUCH_A_CLICK", ··· 618 585 "/input/b": { 619 586 "type": "button", 620 587 "localized_name": "B", 621 - "click": true, 622 - "touch": true, 588 + "features": ["click", "touch"], 623 589 "side": "right", 624 590 "monado_bindings": { 625 591 "click": "XRT_INPUT_TOUCH_B_CLICK", ··· 629 595 "/input/system": { 630 596 "type": "button", 631 597 "localized_name": "System", 632 - "click": true, 633 - "touch": false, 598 + "features": ["click"], 634 599 "side": "right", 635 600 "monado_bindings": { 636 601 "click": "XRT_INPUT_TOUCH_SYSTEM_CLICK" ··· 639 604 "/input/squeeze": { 640 605 "type": "trigger", 641 606 "localized_name": "Squeeze", 642 - "click": false, 643 - "touch": false, 644 - "value": true, 607 + "features": ["value"], 645 608 "monado_bindings": { 646 609 "value": "XRT_INPUT_TOUCH_SQUEEZE_VALUE" 647 610 } ··· 649 612 "/input/trigger": { 650 613 "type": "trigger", 651 614 "localized_name": "Trigger", 652 - "click": false, 653 - "touch": true, 654 - "value": true, 615 + "features": ["touch", "value"], 655 616 "monado_bindings": { 656 617 "touch": "XRT_INPUT_TOUCH_TRIGGER_TOUCH", 657 618 "value": "XRT_INPUT_TOUCH_TRIGGER_VALUE" ··· 660 621 "/input/thumbstick": { 661 622 "type": "joystick", 662 623 "localized_name": "Thumbstick", 663 - "click": true, 664 - "touch": true, 624 + "features": ["click", "touch", "position"], 665 625 "monado_bindings": { 666 626 "click": "XRT_INPUT_TOUCH_THUMBSTICK_CLICK", 667 627 "touch": "XRT_INPUT_TOUCH_THUMBSTICK_TOUCH", ··· 671 631 "/input/thumbrest": { 672 632 "type": "button", 673 633 "localized_name": "Thumb Rest", 674 - "click": false, 675 - "touch": true, 634 + "features": ["touch"], 676 635 "monado_bindings": { 677 636 "touch": "XRT_INPUT_TOUCH_THUMBREST_TOUCH" 678 637 } ··· 680 639 "/input/grip": { 681 640 "type": "pose", 682 641 "localized_name": "Grip", 642 + "features": ["pose"], 683 643 "monado_bindings": { 684 644 "pose": "XRT_INPUT_TOUCH_GRIP_POSE" 685 645 } ··· 687 647 "/input/aim": { 688 648 "type": "pose", 689 649 "localized_name": "Aim", 650 + "features": ["pose"], 690 651 "monado_bindings": { 691 652 "pose": "XRT_INPUT_TOUCH_AIM_POSE" 692 653 } ··· 694 655 "/output/haptic": { 695 656 "type": "vibration", 696 657 "localized_name": "Haptic", 658 + "features": ["haptic"], 697 659 "monado_bindings": { 698 660 "haptic": "XRT_OUTPUT_NAME_TOUCH_HAPTIC" 699 661 } ··· 713 675 "/input/system": { 714 676 "type": "button", 715 677 "localized_name": "System", 716 - "click": true, 717 - "touch": true, 678 + "features": ["click", "touch"], 718 679 "monado_bindings": { 719 680 "click": "XRT_INPUT_INDEX_SYSTEM_CLICK", 720 681 "touch": "XRT_INPUT_INDEX_SYSTEM_TOUCH" ··· 723 684 "/input/a": { 724 685 "type": "button", 725 686 "localized_name": "A", 726 - "click": true, 727 - "touch": true, 687 + "features": ["click", "touch"], 728 688 "monado_bindings": { 729 689 "click": "XRT_INPUT_INDEX_A_CLICK", 730 690 "touch": "XRT_INPUT_INDEX_A_TOUCH" ··· 733 693 "/input/b": { 734 694 "type": "button", 735 695 "localized_name": "B", 736 - "click": true, 737 - "touch": true, 696 + "features": ["click", "touch"], 738 697 "monado_bindings": { 739 698 "click": "XRT_INPUT_INDEX_B_CLICK", 740 699 "touch": "XRT_INPUT_INDEX_B_TOUCH" ··· 743 702 "/input/squeeze": { 744 703 "type": "trigger", 745 704 "localized_name": "Squeeze", 746 - "force": true, 747 - "value": true, 748 - "touch": false, 749 - "click": false, 705 + "features": ["force", "value"], 750 706 "monado_bindings": { 751 707 "value": "XRT_INPUT_INDEX_SQUEEZE_VALUE", 752 708 "force": "XRT_INPUT_INDEX_SQUEEZE_FORCE" ··· 755 711 "/input/trigger": { 756 712 "type": "trigger", 757 713 "localized_name": "Trigger", 758 - "click": true, 759 - "touch": true, 760 - "value": true, 714 + "features": ["click", "touch", "value"], 761 715 "monado_bindings": { 762 716 "click": "XRT_INPUT_INDEX_TRIGGER_CLICK", 763 717 "touch": "XRT_INPUT_INDEX_TRIGGER_TOUCH", ··· 767 721 "/input/thumbstick": { 768 722 "type": "joystick", 769 723 "localized_name": "Thumbstick", 770 - "click": true, 771 - "touch": true, 724 + "features": ["click", "touch", "position"], 772 725 "monado_bindings": { 773 726 "click": "XRT_INPUT_INDEX_THUMBSTICK_CLICK", 774 727 "touch": "XRT_INPUT_INDEX_THUMBSTICK_TOUCH", ··· 778 731 "/input/trackpad": { 779 732 "type": "trackpad", 780 733 "localized_name": "Trackpad", 781 - "force": true, 782 - "touch": true, 734 + "features": ["touch", "force", "position"], 783 735 "monado_bindings": { 784 736 "force": "XRT_INPUT_INDEX_TRACKPAD_FORCE", 785 737 "touch": "XRT_INPUT_INDEX_TRACKPAD_TOUCH", ··· 789 741 "/input/grip": { 790 742 "type": "pose", 791 743 "localized_name": "Grip", 744 + "features": ["pose"], 792 745 "monado_bindings": { 793 746 "pose": "XRT_INPUT_INDEX_GRIP_POSE" 794 747 } ··· 796 749 "/input/aim": { 797 750 "type": "pose", 798 751 "localized_name": "Aim", 752 + "features": ["pose"], 799 753 "monado_bindings": { 800 754 "pose": "XRT_INPUT_INDEX_AIM_POSE" 801 755 } ··· 803 757 "/output/haptic": { 804 758 "type": "vibration", 805 759 "localized_name": "Haptic", 760 + "features": ["haptic"], 806 761 "monado_bindings": { 807 762 "haptic": "XRT_OUTPUT_NAME_INDEX_HAPTIC" 808 763 } ··· 823 778 "/input/select": { 824 779 "type": "trigger", 825 780 "localized_name": "Select", 826 - "value": true, 827 - "touch": false, 781 + "features": ["value"], 828 782 "monado_bindings": { 829 783 "value": "XRT_INPUT_HAND_SELECT_VALUE" 830 784 } ··· 832 786 "/input/squeeze": { 833 787 "type": "trigger", 834 788 "localized_name": "Squeeze", 835 - "value": true, 836 - "touch": false, 789 + "features": ["value"], 837 790 "monado_bindings": { 838 791 "value": "XRT_INPUT_HAND_SQUEEZE_VALUE" 839 792 } ··· 841 794 "/input/grip": { 842 795 "type": "pose", 843 796 "localized_name": "Grip", 797 + "features": ["pose"], 844 798 "monado_bindings": { 845 799 "pose": "XRT_INPUT_HAND_GRIP_POSE" 846 800 } ··· 848 802 "/input/aim": { 849 803 "type": "pose", 850 804 "localized_name": "Aim", 805 + "features": ["pose"], 851 806 "monado_bindings": { 852 807 "pose": "XRT_INPUT_HAND_AIM_POSE" 853 808 } ··· 868 823 "/input/system": { 869 824 "type": "button", 870 825 "localized_name": "System", 871 - "click": true, 872 - "touch": false, 826 + "features": ["click"], 873 827 "monado_bindings": { 874 828 "click": "XRT_INPUT_PSMV_PS_CLICK" 875 829 } ··· 877 831 "/input/menu": { 878 832 "type": "button", 879 833 "localized_name": "Menu", 880 - "click": true, 881 - "touch": false, 834 + "features": ["click"], 882 835 "monado_bindings": { 883 836 "click": "XRT_INPUT_PSMV_MOVE_CLICK" 884 837 } ··· 886 839 "/input/start": { 887 840 "type": "button", 888 841 "localized_name": "Start", 889 - "click": true, 890 - "touch": false, 842 + "features": ["click"], 891 843 "monado_bindings": { 892 844 "click": "XRT_INPUT_PSMV_START_CLICK" 893 845 } ··· 895 847 "/input/select": { 896 848 "type": "button", 897 849 "localized_name": "Select", 898 - "click": true, 899 - "touch": false, 850 + "features": ["click"], 900 851 "monado_bindings": { 901 852 "click": "XRT_INPUT_PSMV_SELECT_CLICK" 902 853 } ··· 904 855 "/input/square_mndx": { 905 856 "type": "button", 906 857 "localized_name": "Square", 907 - "click": true, 908 - "touch": false, 858 + "features": ["click"], 909 859 "monado_bindings": { 910 860 "click": "XRT_INPUT_PSMV_SQUARE_CLICK" 911 861 } ··· 913 863 "/input/cross_mndx": { 914 864 "type": "button", 915 865 "localized_name": "Cross", 916 - "click": true, 917 - "touch": false, 866 + "features": ["click"], 918 867 "monado_bindings": { 919 868 "click": "XRT_INPUT_PSMV_CROSS_CLICK" 920 869 } ··· 922 871 "/input/circle_mndx": { 923 872 "type": "button", 924 873 "localized_name": "Circle", 925 - "click": true, 926 - "touch": false, 874 + "features": ["click"], 927 875 "monado_bindings": { 928 876 "click": "XRT_INPUT_PSMV_CIRCLE_CLICK" 929 877 } ··· 931 879 "/input/triangle_mndx": { 932 880 "type": "button", 933 881 "localized_name": "Triangle", 934 - "click": true, 935 - "touch": false, 882 + "features": ["click"], 936 883 "monado_bindings": { 937 884 "click": "XRT_INPUT_PSMV_TRIANGLE_CLICK" 938 885 } ··· 940 887 "/input/trigger": { 941 888 "type": "trigger", 942 889 "localized_name": "Trigger", 943 - "value": true, 944 - "touch": false, 890 + "features": ["value"], 945 891 "monado_bindings": { 946 892 "value": "XRT_INPUT_PSMV_TRIGGER_VALUE" 947 893 } ··· 949 895 "/input/grip": { 950 896 "type": "pose", 951 897 "localized_name": "Grip", 898 + "features": ["pose"], 952 899 "monado_bindings": { 953 900 "pose": "XRT_INPUT_PSMV_GRIP_POSE" 954 901 } ··· 956 903 "/input/ball_mndx": { 957 904 "type": "pose", 958 905 "localized_name": "Ball", 906 + "features": ["pose"], 959 907 "monado_bindings": { 960 908 "pose": "XRT_INPUT_PSMV_BALL_CENTER_POSE" 961 909 } ··· 963 911 "/input/body_center_mndx": { 964 912 "type": "pose", 965 913 "localized_name": "Body Center", 914 + "features": ["pose"], 966 915 "monado_bindings": { 967 916 "pose": "XRT_INPUT_PSMV_BODY_CENTER_POSE" 968 917 } ··· 970 919 "/input/aim": { 971 920 "type": "pose", 972 921 "localized_name": "aim", 922 + "features": ["pose"], 973 923 "monado_bindings": { 974 924 "pose": "XRT_INPUT_PSMV_AIM_POSE" 975 925 } ··· 977 927 "/output/haptic": { 978 928 "type": "vibration", 979 929 "localized_name": "Haptic", 930 + "features": ["haptic"], 980 931 "monado_bindings": { 981 932 "haptic": "XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION" 982 933 } 983 934 } 984 935 } 985 - } 986 - }, 936 + }, 987 937 988 - "/interaction_profiles/mndx/hydra": { 989 - "title": "Monado Hydra Controller", 990 - "type": "tracked_controller", 991 - "monado_device": "XRT_DEVICE_HYDRA", 992 - "extension": "XR_MNDX_hydra", 993 - "subaction_paths": [ 994 - "/user/hand/left", 995 - "/user/hand/right" 996 - ], 997 - "subpaths": { 998 - "/input/1": { 999 - "type": "button", 1000 - "localized_name": "1", 1001 - "click": true, 1002 - "touch": false, 1003 - "monado_bindings": { 1004 - "click": "XRT_INPUT_HYDRA_1_CLICK" 1005 - } 1006 - }, 1007 - "/input/2": { 1008 - "type": "button", 1009 - "localized_name": "2", 1010 - "click": true, 1011 - "touch": false, 1012 - "monado_bindings": { 1013 - "click": "XRT_INPUT_HYDRA_2_CLICK" 1014 - } 1015 - }, 1016 - "/input/3": { 1017 - "type": "button", 1018 - "localized_name": "3", 1019 - "click": true, 1020 - "touch": false, 1021 - "monado_bindings": { 1022 - "click": "XRT_INPUT_HYDRA_3_CLICK" 1023 - } 1024 - }, 1025 - "/input/4": { 1026 - "type": "button", 1027 - "localized_name": "4", 1028 - "click": true, 1029 - "touch": false, 1030 - "monado_bindings": { 1031 - "click": "XRT_INPUT_HYDRA_4_CLICK" 1032 - } 1033 - }, 1034 - "/input/bumper": { 1035 - "type": "button", 1036 - "localized_name": "Bumper", 1037 - "click": true, 1038 - "touch": false, 1039 - "monado_bindings": { 1040 - "click": "XRT_INPUT_HYDRA_BUMPER_CLICK" 1041 - } 1042 - }, 1043 - "/input/thumbstick": { 1044 - "type": "joystick", 1045 - "localized_name": "Thumbstick", 1046 - "click": true, 1047 - "touch": false, 1048 - "monado_bindings": { 1049 - "click": "XRT_INPUT_HYDRA_JOYSTICK_CLICK", 1050 - "position": "XRT_INPUT_HYDRA_JOYSTICK_VALUE" 1051 - } 1052 - }, 1053 - "/input/trigger": { 1054 - "type": "trigger", 1055 - "localized_name": "Trigger", 1056 - "value": true, 1057 - "touch": false, 1058 - "monado_bindings": { 1059 - "value": "XRT_INPUT_HYDRA_TRIGGER_VALUE" 1060 - } 1061 - }, 1062 - "/input/grip": { 1063 - "type": "pose", 1064 - "localized_name": "Grip", 1065 - "monado_bindings": { 1066 - "pose": "XRT_INPUT_HYDRA_POSE" 938 + "/interaction_profiles/mndx/hydra": { 939 + "title": "Monado Hydra Controller", 940 + "type": "tracked_controller", 941 + "monado_device": "XRT_DEVICE_HYDRA", 942 + "extension": "XR_MNDX_hydra", 943 + "subaction_paths": [ 944 + "/user/hand/left", 945 + "/user/hand/right" 946 + ], 947 + "subpaths": { 948 + "/input/1": { 949 + "type": "button", 950 + "localized_name": "1", 951 + "features": ["click"], 952 + "monado_bindings": { 953 + "click": "XRT_INPUT_HYDRA_1_CLICK" 954 + } 955 + }, 956 + "/input/2": { 957 + "type": "button", 958 + "localized_name": "2", 959 + "features": ["click"], 960 + "monado_bindings": { 961 + "click": "XRT_INPUT_HYDRA_2_CLICK" 962 + } 963 + }, 964 + "/input/3": { 965 + "type": "button", 966 + "localized_name": "3", 967 + "features": ["click"], 968 + "monado_bindings": { 969 + "click": "XRT_INPUT_HYDRA_3_CLICK" 970 + } 971 + }, 972 + "/input/4": { 973 + "type": "button", 974 + "localized_name": "4", 975 + "features": ["click"], 976 + "monado_bindings": { 977 + "click": "XRT_INPUT_HYDRA_4_CLICK" 978 + } 979 + }, 980 + "/input/bumper": { 981 + "type": "button", 982 + "localized_name": "Bumper", 983 + "features": ["click"], 984 + "monado_bindings": { 985 + "click": "XRT_INPUT_HYDRA_BUMPER_CLICK" 986 + } 987 + }, 988 + "/input/thumbstick": { 989 + "type": "joystick", 990 + "localized_name": "Thumbstick", 991 + "features": ["click", "position"], 992 + "monado_bindings": { 993 + "click": "XRT_INPUT_HYDRA_JOYSTICK_CLICK", 994 + "position": "XRT_INPUT_HYDRA_JOYSTICK_VALUE" 995 + } 996 + }, 997 + "/input/trigger": { 998 + "type": "trigger", 999 + "localized_name": "Trigger", 1000 + "features": ["value"], 1001 + "monado_bindings": { 1002 + "value": "XRT_INPUT_HYDRA_TRIGGER_VALUE" 1003 + } 1004 + }, 1005 + "/input/grip": { 1006 + "type": "pose", 1007 + "localized_name": "Grip", 1008 + "features": ["pose"], 1009 + "monado_bindings": { 1010 + "pose": "XRT_INPUT_HYDRA_POSE" 1011 + } 1067 1012 } 1068 1013 } 1069 1014 }
+68 -102
src/xrt/auxiliary/bindings/bindings.py
··· 8 8 import argparse 9 9 10 10 11 - class BindingPath: 12 - def __init__(self, subaction_path, path): 13 - """Construct an component.""" 14 - self.subaction_path = subaction_path 15 - self.path = path 16 - 17 - 18 - def handle_subpath(pathgroup_cls, pathgroup_list, subaction_path, sub_path_itm): 11 + def handle_subpath(pathgroup_cls, feature_list, subaction_path, sub_path_itm): 19 12 sub_path_name = sub_path_itm[0] 20 13 sub_path_obj = sub_path_itm[1] 21 14 ··· 23 16 if "side" in sub_path_obj and sub_path_obj["side"] not in subaction_path: 24 17 return 25 18 26 - # path without the component, e.g. /user/hand/left/input/a, without /click 27 - base_path = subaction_path + sub_path_name 19 + for feature in sub_path_obj["features"]: 20 + feature_list.append(Feature(subaction_path, sub_path_itm, feature)) 28 21 29 - # Add each component with a base path as a separate PathGroup, e.g. 30 - # /user/hand/left/input/a/click and /user/hand/input/a map to the same a click. 31 - # /user/hand/left/input/a/touch and /user/hand/input/a map to the same a touch. 32 - # Code later will have to decide how /user/hand/input/a is actually bound 33 - if sub_path_obj["type"] in ["button", "trigger", "trackpad", "joystick"]: 34 - # Add component paths like /user/hand/left/input/a/touch 35 - for component in ["click", "touch", "value", "force"]: 36 - if component in sub_path_obj and sub_path_obj[component]: 37 - binding_key = component 38 - pathgroup = [] 39 22 40 - comp_path = base_path + "/" + component 41 - pathgroup.append(BindingPath(subaction_path, comp_path)) 42 - 43 - # Add a base path like /user/hand/left/input/a with the same 44 - # binding_key as the component 45 - pathgroup.append(BindingPath(subaction_path, base_path)) 46 - 47 - pathgroup_list.append(pathgroup_cls(subaction_path, pathgroup, sub_path_itm, binding_key)) 48 - 49 - # same for joystick and trackpad, but with special x/y components 50 - if sub_path_obj["type"] in ["joystick", "trackpad"]: 51 - binding_key = "position" 52 - pathgroup = [] 53 - 54 - pathgroup.append(BindingPath(subaction_path, base_path + "/x")) 55 - pathgroup.append(BindingPath(subaction_path, base_path + "/y")) 56 - 57 - # Add a base path like /user/hand/left/input/trackpad with the same binding_key as the /x and /y component 58 - pathgroup.append(BindingPath(subaction_path, base_path)) 59 - 60 - pathgroup_list.append(pathgroup_cls(subaction_path, pathgroup, sub_path_itm, binding_key)) 61 - 62 - # pose inputs can be bound with or without pose component 63 - if sub_path_obj["type"] == "pose": 64 - binding_key = "pose" 65 - pathgroup = [] 66 - 67 - pathgroup.append(BindingPath(subaction_path, base_path)) 68 - pathgroup.append(BindingPath(subaction_path, base_path + "/pose")) 69 - 70 - pathgroup_list.append(pathgroup_cls(subaction_path, pathgroup, sub_path_itm, binding_key)) 71 - 72 - # haptic feedback only has a base path 73 - if sub_path_obj["type"] == "vibration": 74 - binding_key = "haptic" 75 - pathgroup = [] 76 - 77 - pathgroup.append(BindingPath(subaction_path, base_path)) 78 - 79 - pathgroup_list.append(pathgroup_cls(subaction_path, pathgroup, sub_path_itm, binding_key)) 80 - 81 - 82 - class PathGroup: 83 - """Group of paths associated with a single input, for example 84 - * /user/hand/left/input/trackpad 85 - * /user/hand/left/input/trackpad/x 86 - * /user/hand/left/input/trackpad/y 23 + class Feature: 24 + """Features roughly correlate with data sources. For example a trackpad may 25 + have several features: position, click, touch, force, ... 87 26 """ 88 27 89 28 @classmethod 90 - def parse_paths(pathgroup_cls, subaction_paths, paths): 91 - """Turn a profile's input paths into an array of PathGroup objects. 92 - Creates a PathGroup for each subaction_path and stripped subpaths. 93 - """ 94 - pathgroup_list = [] 29 + def parse_features(feature_cls, subaction_paths, paths): 30 + """Turn a profile's input paths into a list of Feature objects.""" 31 + feature_list = [] 95 32 for subaction_path in subaction_paths: 96 33 for sub_path_itm in paths.items(): 97 - handle_subpath(pathgroup_cls, pathgroup_list, subaction_path, sub_path_itm) 98 - return pathgroup_list 34 + handle_subpath(feature_cls, feature_list, subaction_path, sub_path_itm) 35 + return feature_list 99 36 100 - def __init__(self, subaction_path, pathgroup, sub_path_itm, binding_key=None): 37 + def __init__(self, subaction_path, sub_path_itm, feature_str): 101 38 self.sub_path_name = sub_path_itm[0] 102 39 self.sub_path_obj = sub_path_itm[1] 103 40 self.subaction_path = subaction_path 104 - self.pathgroup = pathgroup 105 - self.binding_key = binding_key 106 - self.is_output = self.sub_path_obj["type"] == "vibration" 107 - self.is_input = not self.is_output 41 + self.feature_str = feature_str 42 + 43 + """A group of paths that derive from the same input. 44 + For example .../thumbstick, .../thumbstick/x, .../thumbstick/y 45 + """ 46 + def to_monado_paths(self): 47 + paths = [] 48 + 49 + basepath = self.subaction_path + "/" + self.sub_path_name 50 + 51 + if self.feature_str == "position": 52 + paths.append(basepath + "/" + "x") 53 + paths.append(basepath + "/" + "y") 54 + paths.append(basepath) 55 + else: 56 + paths.append(basepath + "/" + self.feature_str) 57 + paths.append(basepath) 58 + 59 + return paths 60 + 61 + def is_input(self): 62 + # only haptics is output so far, everythine else is input 63 + return self.feature_str != "haptic" 64 + 65 + def is_output(self): 66 + return not self.is_input() 108 67 109 68 110 69 class Profile: ··· 115 74 self.monado_device = data["monado_device"] 116 75 self.title = data['title'] 117 76 self.func = name[22:].replace("/", "_") 118 - self.pathgroups = PathGroup.parse_paths(data["subaction_paths"], 119 - data["subpaths"]) 77 + self.features = Feature.parse_features(data["subaction_paths"], 78 + data["subpaths"]) 120 79 self.hw_type = data["type"] 121 80 122 81 self.by_length = {} 123 - for pathgroup in self.pathgroups: 124 - for input_path in pathgroup.pathgroup: 125 - length = len(input_path.path) 82 + for feature in self.features: 83 + for path in feature.to_monado_paths(): 84 + length = len(path) 126 85 if (length in self.by_length): 127 - self.by_length[length].append(input_path) 86 + self.by_length[length].append(path) 128 87 else: 129 - self.by_length[length] = [input_path] 88 + self.by_length[length] = [path] 130 89 131 90 132 91 class Bindings: ··· 187 146 f.write(func_start.format(func=profile.func)) 188 147 for length in profile.by_length: 189 148 f.write("\tcase " + str(length) + ":\n\t\t") 190 - for component in profile.by_length[length]: 191 - f.write(if_strcmp.format(check=component.path)) 149 + for path in profile.by_length[length]: 150 + f.write(if_strcmp.format(check=path)) 192 151 f.write("{\n\t\t\treturn false;\n\t\t}\n") 193 152 f.write("\tdefault:\n\t\treturn false;\n\t}\n}\n") 194 153 ··· 199 158 fname = vendor_name + "_" + hw_name + "_profile.json" 200 159 controller_type = "monado_" + vendor_name + "_" + hw_name 201 160 202 - num_bindings = len(profile.pathgroups) 161 + num_bindings = len(profile.features) 203 162 f.write(f'\t{{ // profile_template\n') 204 163 f.write(f'\t\t.name = {profile.monado_device},\n') 205 164 f.write(f'\t\t.path = "{profile.name}",\n') ··· 209 168 f.write(f'\t\t.num_bindings = {num_bindings},\n') 210 169 f.write(f'\t\t.bindings = (struct binding_template[]){{ // array of binding_template\n') 211 170 212 - pathgroup: PathGroup 213 - for idx, pathgroup in enumerate(profile.pathgroups): 214 - sp_obj = pathgroup.sub_path_obj 171 + feature: Feature 172 + for idx, feature in enumerate(profile.features): 173 + sp_obj = feature.sub_path_obj 215 174 216 - steamvr_path = pathgroup.sub_path_name 217 - if pathgroup.binding_key in ["click", "touch", "force", "value"]: 218 - steamvr_path += "/" + pathgroup.binding_key 175 + steamvr_path = feature.sub_path_name 176 + if feature.feature_str in ["click", "touch", "force", "value"]: 177 + steamvr_path += "/" + feature.feature_str 219 178 220 179 f.write(f'\t\t\t{{ // binding_template {idx}\n') 221 - f.write(f'\t\t\t\t.subaction_path = "{pathgroup.subaction_path}",\n') 180 + f.write(f'\t\t\t\t.subaction_path = "{feature.subaction_path}",\n') 222 181 f.write(f'\t\t\t\t.steamvr_path = "{steamvr_path}",\n') 223 182 f.write(f'\t\t\t\t.localized_name = "{sp_obj["localized_name"]}",\n') 224 183 225 184 f.write('\t\t\t\t.paths = { // array of paths\n') 226 - for input_path in pathgroup.pathgroup: 227 - f.write(f'\t\t\t\t\t"{input_path.path}",\n') 185 + for path in feature.to_monado_paths(): 186 + f.write(f'\t\t\t\t\t"{path}",\n') 228 187 f.write('\t\t\t\t\tNULL\n') 229 188 f.write('\t\t\t\t}, // /array of paths\n') 230 189 231 - binding_key = pathgroup.binding_key 232 - monado_binding = sp_obj["monado_bindings"][binding_key] 190 + # print("feature", feature.__dict__) 191 + 192 + feature_str = feature.feature_str 193 + 194 + # controllers can have input that we don't have bindings for' 195 + if feature_str not in sp_obj["monado_bindings"]: 196 + continue 197 + 198 + monado_binding = sp_obj["monado_bindings"][feature_str] 233 199 234 - if pathgroup.is_input and monado_binding is not None: 200 + if feature.is_input() and monado_binding is not None: 235 201 f.write(f'\t\t\t\t.input = {monado_binding},\n') 236 202 else: 237 203 f.write(f'\t\t\t\t.input = 0,\n') 238 204 239 - if pathgroup.is_output and monado_binding is not None: 205 + if feature.is_output() and monado_binding is not None: 240 206 f.write(f'\t\t\t\t.output = {monado_binding},\n') 241 207 else: 242 208 f.write(f'\t\t\t\t.output = 0,\n')
+21 -7
src/xrt/auxiliary/bindings/steamvr_profiles.py
··· 41 41 return sub_path_name 42 42 43 43 44 + def get_required_features(path_type): 45 + if path_type == "button": 46 + return ["click", "touch"] 47 + if path_type == "trigger": 48 + return ["click", "touch", "value", "force"] 49 + if path_type == "joystick": 50 + return ["click", "touch"] 51 + if path_type == "pose": 52 + return [] 53 + if path_type == "vibration": 54 + return [] 55 + return [] 56 + 57 + 44 58 def main(): 45 59 """Handle command line and generate a file.""" 46 60 parser = argparse.ArgumentParser(description='Bindings generator.') ··· 65 79 66 80 input_source = {} 67 81 68 - pg: PathGroup 69 - for idx, pg in enumerate(p.pathgroups): 70 - sp_name = steamvr_subpath_name(pg.sub_path_name, pg.sub_path_obj) 71 - sp = pg.sub_path_obj 82 + feature: Feature 83 + for idx, feature in enumerate(p.features): 84 + sp_name = steamvr_subpath_name(feature.sub_path_name, feature.sub_path_obj) 85 + sp = feature.sub_path_obj 72 86 73 87 input_source[sp_name] = { 74 88 "type": sp["type"], 75 89 "binding_image_point": [0, 0], # TODO 76 90 "order": idx 77 91 } 78 - for component in ["click", "touch", "value", "force"]: 79 - if component in sp: 80 - input_source[sp_name][component] = sp[component] 92 + 93 + for req in get_required_features(sp["type"]): 94 + input_source[sp_name][req] = req in sp["features"] 81 95 82 96 j = { 83 97 "json_id": "input_profile",