input-mapper.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. InputMapper::InputMapper(View* view) : PanelItem(view, Size{~0, ~0}) {
  2. setCollapsible().setVisible(false);
  3. nameLabel.setFont(Font().setBold());
  4. inputList.setBatchable();
  5. inputList.onActivate([&](auto cell) { eventAssign(); });
  6. inputList.onChange([&] { eventChange(); });
  7. mouseXaxis.setText("Mouse X-axis").setCollapsible().onActivate([&] { eventAssignMouse(0, 0); });
  8. mouseYaxis.setText("Mouse Y-axis").setCollapsible().onActivate([&] { eventAssignMouse(0, 1); });
  9. mouseLeft.setText("Mouse Left").setCollapsible().onActivate([&] { eventAssignMouse(1, 0); });
  10. mouseMiddle.setText("Mouse Middle").setCollapsible().onActivate([&] { eventAssignMouse(1, 1); });
  11. mouseRight.setText("Mouse Right").setCollapsible().onActivate([&] { eventAssignMouse(1, 2); });
  12. assignButton.setText("Assign").onActivate([&] { eventAssign(); });
  13. clearButton.setText("Clear").onActivate([&] { eventClear(); });
  14. }
  15. auto InputMapper::show() -> void {
  16. setVisible(true);
  17. }
  18. auto InputMapper::hide() -> void {
  19. setVisible(false);
  20. node = {};
  21. inputList.reset();
  22. }
  23. auto InputMapper::refresh(higan::Node::Object node) -> void {
  24. this->node = node;
  25. nameLabel.setText(node->name());
  26. inputList.reset().setEnabled();
  27. inputList.append(TableViewColumn().setText("Name"));
  28. inputList.append(TableViewColumn().setText("Mapping").setExpandable());
  29. for(auto& node : node->find<higan::Node::Input>()) {
  30. if(node->parent() != this->node) continue;
  31. TableViewItem item{&inputList};
  32. item.setAttribute<higan::Node::Input>("node", node);
  33. TableViewCell name{&item};
  34. name.setText(node->name()).setFont(Font().setBold());
  35. TableViewCell value{&item};
  36. }
  37. update();
  38. inputList.doChange();
  39. }
  40. auto InputMapper::update() -> void {
  41. for(auto& item : inputList.items()) {
  42. auto value = item.cell(1);
  43. auto node = item.attribute<higan::Node::Input>("node");
  44. if(node == assigning) continue; //don't overwrite input being assigned
  45. if(auto name = node->attribute("inputName")) {
  46. auto device = node->attribute("deviceName");
  47. if(device == "Keyboard") value.setIcon(Icon::Device::Keyboard);
  48. else if(device == "Mouse") value.setIcon(Icon::Device::Mouse);
  49. else if(device == "Joypad") value.setIcon(Icon::Device::Joypad);
  50. else value.setIcon(Icon::Action::Close);
  51. string label;
  52. if(label == "Joypad") label.append(node->attribute("groupName"), ".");
  53. label.append(node->attribute("inputName"));
  54. if(auto qualifier = node->attribute("qualifier")) label.append(".", qualifier);
  55. value.setText(label);
  56. } else {
  57. value.setIcon(Icon::Action::Close);
  58. value.setText("(unmapped)");
  59. }
  60. }
  61. inputList.resizeColumns();
  62. }
  63. auto InputMapper::eventAssignMouse(uint groupID, uint inputID) -> void {
  64. for(auto& device : inputManager.devices) {
  65. if(!device->isMouse()) continue;
  66. eventInput(device, groupID, inputID, 0, 1, true);
  67. return;
  68. }
  69. }
  70. auto InputMapper::eventAssign() -> void {
  71. //prevent an activation via the return key from mapping return instantly
  72. inputManager.poll();
  73. assigningQueue = inputList.batched(); //assign selected
  74. if(!assigningQueue) assigningQueue = inputList.items(); //assign all
  75. if(!assigningQueue) return; //no inputs to assign
  76. eventAssignNext();
  77. }
  78. auto InputMapper::eventAssignNext() -> void {
  79. if(!assigningQueue) {
  80. inputList.selectNone().setFocused();
  81. return eventChange();
  82. }
  83. //use the viewport to sink inputs away from the table view during assignment
  84. program.viewport.setFocused();
  85. auto item = assigningQueue.takeFirst();
  86. inputList.selectNone();
  87. item.setSelected().setFocused(); //scroll the current assigning mapping into view
  88. auto input = item.attribute<higan::Node::Input>("node");
  89. item.cell(1).setIcon(Icon::Go::Right).setText("(assign)");
  90. assigning = input;
  91. eventChange();
  92. update(); //update state; clears stale 'assign' text
  93. }
  94. auto InputMapper::eventClear() -> void {
  95. auto batched = inputList.batched(); //clear selected
  96. if(!batched) batched = inputList.items(); //clear all
  97. if(!batched) return; //no inputs to clear
  98. for(auto& item : batched) {
  99. auto input = item.attribute<higan::Node::Input>("node");
  100. input->setAttribute("pathID");
  101. input->setAttribute("vendorID");
  102. input->setAttribute("productID");
  103. input->setAttribute("groupID");
  104. input->setAttribute("inputID");
  105. input->setAttribute("deviceName");
  106. input->setAttribute("groupName");
  107. input->setAttribute("inputName");
  108. input->setAttribute("qualifier");
  109. if (input == assigning) {
  110. assigning.reset();
  111. eventChange();
  112. }
  113. }
  114. inputManager.bind();
  115. update();
  116. }
  117. auto InputMapper::eventChange() -> void {
  118. auto batched = inputList.batched();
  119. bool showMouseAxes = false;
  120. bool showMouseButtons = false;
  121. if(assigning) {
  122. if(assigning->cast<higan::Node::Axis>()) showMouseAxes = true;
  123. if(assigning->cast<higan::Node::Button>()) showMouseButtons = true;
  124. }
  125. mouseXaxis.setVisible(showMouseAxes);
  126. mouseYaxis.setVisible(showMouseAxes);
  127. mouseLeft.setVisible(showMouseButtons);
  128. mouseMiddle.setVisible(showMouseButtons);
  129. mouseRight.setVisible(showMouseButtons);
  130. controlLayout.resize();
  131. assignButton.setText((bool)batched ? "Assign" : "Assign All");
  132. clearButton.setText((bool)batched ? "Clear" : "Clear All");
  133. }
  134. auto InputMapper::eventInput(shared_pointer<HID::Device> device, uint group, uint input, int16_t oldValue, int16_t newValue, bool allowMouseInput) -> void {
  135. if(!assigning) return;
  136. auto isButton = (bool)assigning->cast<higan::Node::Button>();
  137. auto isAxis = (bool)assigning->cast<higan::Node::Axis>();
  138. auto isTrigger = (bool)assigning->cast<higan::Node::Trigger>();
  139. auto isRumble = (bool)assigning->cast<higan::Node::Rumble>();
  140. bool allow = false;
  141. string qualifier;
  142. if(isButton) {
  143. if(device->isKeyboard()) {
  144. if(oldValue == 0 && newValue == 1) allow = true;
  145. }
  146. if(device->isJoypad() && (group == HID::Joypad::Axis || group == HID::Joypad::Hat)) {
  147. if(newValue < -24576) allow = true, qualifier = "Lo";
  148. if(newValue > +24576) allow = true, qualifier = "Hi";
  149. }
  150. if(device->isJoypad() && group == HID::Joypad::Button) {
  151. if(oldValue == 0 && newValue == 1) allow = true;
  152. }
  153. }
  154. if(isAxis) {
  155. }
  156. if(isTrigger) {
  157. }
  158. if(isRumble) {
  159. }
  160. if(allowMouseInput && device->isMouse()) allow = true;
  161. if(!allow) return;
  162. if(device->group(group).input(input).name() == "Escape") {
  163. assigning->setAttribute("pathID");
  164. assigning->setAttribute("vendorID");
  165. assigning->setAttribute("productID");
  166. assigning->setAttribute("groupID");
  167. assigning->setAttribute("inputID");
  168. assigning->setAttribute("deviceName");
  169. assigning->setAttribute("groupName");
  170. assigning->setAttribute("inputName");
  171. assigning->setAttribute("qualifier");
  172. } else {
  173. assigning->setAttribute("pathID", device->pathID());
  174. assigning->setAttribute("vendorID", device->vendorID());
  175. assigning->setAttribute("productID", device->productID());
  176. assigning->setAttribute("groupID", group);
  177. assigning->setAttribute("inputID", input);
  178. assigning->setAttribute("deviceName", device->name());
  179. assigning->setAttribute("groupName", device->group(group).name());
  180. assigning->setAttribute("inputName", device->group(group).input(input).name());
  181. assigning->setAttribute("qualifier", qualifier);
  182. }
  183. assigning.reset();
  184. inputManager.bind();
  185. update();
  186. eventAssignNext();
  187. }