BsLinuxGamepad.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Input/BsGamepad.h"
  4. #include "Input/BsInput.h"
  5. #include "Linux/BsLinuxInput.h"
  6. #include <fcntl.h>
  7. #include <linux/input.h>
  8. namespace bs
  9. {
  10. /** Contains private data for the Linux Gamepad implementation. */
  11. struct Gamepad::Pimpl
  12. {
  13. GamepadInfo info;
  14. INT32 fileHandle;
  15. ButtonCode povState;
  16. };
  17. Gamepad::Gamepad(const String& name, const GamepadInfo& gamepadInfo, Input* owner)
  18. : mName(name), mOwner(owner)
  19. {
  20. m = bs_new<Pimpl>();
  21. m->info = gamepadInfo;
  22. m->povState = BC_UNASSIGNED;
  23. String eventPath = "/dev/input/event" + toString(gamepadInfo.eventHandlerIdx);
  24. m->fileHandle = open(eventPath.c_str(), O_RDWR | O_NONBLOCK);
  25. if(m->fileHandle == -1)
  26. LOGERR("Failed to open input event file handle for device: " + gamepadInfo.name);
  27. }
  28. Gamepad::~Gamepad()
  29. {
  30. if(m->fileHandle != -1)
  31. close(m->fileHandle);
  32. bs_delete(m);
  33. }
  34. void Gamepad::capture()
  35. {
  36. if(m->fileHandle == -1)
  37. return;
  38. struct AxisState
  39. {
  40. bool moved;
  41. INT32 value;
  42. };
  43. AxisState axisState[24];
  44. bs_zero_out(axisState);
  45. input_event events[BUFFER_SIZE_GAMEPAD];
  46. while(true)
  47. {
  48. ssize_t numReadBytes = read(m->fileHandle, &events, sizeof(events));
  49. if(numReadBytes < 0)
  50. break;
  51. UINT32 numEvents = numReadBytes / sizeof(input_event);
  52. for(UINT32 i = 0; i < numEvents; ++i)
  53. {
  54. switch(events[i].type)
  55. {
  56. case EV_KEY:
  57. {
  58. auto findIter = m->info.buttonMap.find(events[i].code);
  59. if(findIter == m->info.buttonMap.end())
  60. continue;
  61. if(events[i].value)
  62. mOwner->_notifyButtonPressed(m->info.id, findIter->second, (UINT64)events[i].time.tv_usec);
  63. else
  64. mOwner->_notifyButtonReleased(m->info.id, findIter->second, (UINT64)events[i].time.tv_usec);
  65. }
  66. break;
  67. case EV_ABS:
  68. {
  69. // Stick or trigger
  70. if(events[i].code <= ABS_BRAKE)
  71. {
  72. const AxisInfo& axisInfo = m->info.axisMap[events[i].code];
  73. if(axisInfo.axisIdx >= 24)
  74. break;
  75. axisState[axisInfo.axisIdx].moved = true;
  76. // Scale range if needed
  77. if(axisInfo.min == Gamepad::MIN_AXIS && axisInfo.max != Gamepad::MAX_AXIS )
  78. axisState[axisInfo.axisIdx].value = events[i].value;
  79. else
  80. {
  81. float range = (float)(axisInfo.max - axisInfo.min);
  82. float normalizedValue = (axisInfo.max - events[i].value) / range;
  83. range = (float)(Gamepad::MAX_AXIS - Gamepad::MIN_AXIS);
  84. axisState[axisInfo.axisIdx].value = Gamepad::MIN_AXIS + (INT32)(normalizedValue * range);
  85. }
  86. }
  87. else if(events[i].code <= ABS_HAT3Y) // POV
  88. {
  89. // Note: We only support a single POV and report events from all POVs as if they were from the
  90. // same source
  91. INT32 povIdx = events[i].code - ABS_HAT0X;
  92. ButtonCode povButton = BC_UNASSIGNED;
  93. if((povIdx & 0x1) == 0) // Even, x axis
  94. {
  95. if(events[i].value == -1)
  96. povButton = BC_GAMEPAD_DPAD_LEFT;
  97. else if(events[i].value == 1)
  98. povButton = BC_GAMEPAD_DPAD_RIGHT;
  99. }
  100. else // Odd, y axis
  101. {
  102. if(events[i].value == -1)
  103. povButton = BC_GAMEPAD_DPAD_UP;
  104. else if(events[i].value == 1)
  105. povButton = BC_GAMEPAD_DPAD_DOWN;
  106. }
  107. if(m->povState != povButton)
  108. {
  109. if(m->povState != BC_UNASSIGNED)
  110. mOwner->_notifyButtonReleased(m->info.id, m->povState, (UINT64)events[i].time.tv_usec);
  111. if(povButton != BC_UNASSIGNED)
  112. mOwner->_notifyButtonPressed(m->info.id, povButton, (UINT64)events[i].time.tv_usec);
  113. m->povState = povButton;
  114. }
  115. }
  116. break;
  117. }
  118. default: break;
  119. }
  120. }
  121. }
  122. for(UINT32 i = 0; i < 24; i++)
  123. {
  124. if(axisState[i].moved)
  125. mOwner->_notifyAxisMoved(m->info.id, i, axisState[i].value);
  126. }
  127. }
  128. void Gamepad::changeCaptureContext(UINT64 windowHandle)
  129. {
  130. // Do nothing
  131. }
  132. }