| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #include "Input/BsGamepad.h"
- #include "Input/BsInput.h"
- #include "Linux/BsLinuxInput.h"
- #include <fcntl.h>
- #include <linux/input.h>
- namespace bs
- {
- /** Contains private data for the Linux Gamepad implementation. */
- struct Gamepad::Pimpl
- {
- GamepadInfo info;
- INT32 fileHandle;
- ButtonCode povState;
- bool hasInputFocus;
- };
- Gamepad::Gamepad(const String& name, const GamepadInfo& gamepadInfo, Input* owner)
- : mName(name), mOwner(owner)
- {
- m = bs_new<Pimpl>();
- m->info = gamepadInfo;
- m->povState = BC_UNASSIGNED;
- m->hasInputFocus = true;
- String eventPath = "/dev/input/event" + toString(gamepadInfo.eventHandlerIdx);
- m->fileHandle = open(eventPath.c_str(), O_RDWR | O_NONBLOCK);
- if(m->fileHandle == -1)
- LOGERR("Failed to open input event file handle for device: " + gamepadInfo.name);
- }
- Gamepad::~Gamepad()
- {
- if(m->fileHandle != -1)
- close(m->fileHandle);
- bs_delete(m);
- }
- void Gamepad::capture()
- {
- if(m->fileHandle == -1)
- return;
- struct AxisState
- {
- bool moved;
- INT32 value;
- };
- AxisState axisState[24];
- bs_zero_out(axisState);
- input_event events[BUFFER_SIZE_GAMEPAD];
- while(true)
- {
- ssize_t numReadBytes = read(m->fileHandle, &events, sizeof(events));
- if(numReadBytes < 0)
- break;
- if(!m->hasInputFocus)
- continue;
- UINT32 numEvents = numReadBytes / sizeof(input_event);
- for(UINT32 i = 0; i < numEvents; ++i)
- {
- switch(events[i].type)
- {
- case EV_KEY:
- {
- auto findIter = m->info.buttonMap.find(events[i].code);
- if(findIter == m->info.buttonMap.end())
- continue;
- if(events[i].value)
- mOwner->_notifyButtonPressed(m->info.id, findIter->second, (UINT64)events[i].time.tv_usec);
- else
- mOwner->_notifyButtonReleased(m->info.id, findIter->second, (UINT64)events[i].time.tv_usec);
- }
- break;
- case EV_ABS:
- {
- // Stick or trigger
- if(events[i].code <= ABS_BRAKE)
- {
- const AxisInfo& axisInfo = m->info.axisMap[events[i].code];
- if(axisInfo.axisIdx >= 24)
- break;
- axisState[axisInfo.axisIdx].moved = true;
- // Scale range if needed
- if(axisInfo.min == Gamepad::MIN_AXIS && axisInfo.max != Gamepad::MAX_AXIS )
- axisState[axisInfo.axisIdx].value = events[i].value;
- else
- {
- float range = (float)(axisInfo.max - axisInfo.min);
- float normalizedValue = (axisInfo.max - events[i].value) / range;
- range = (float)(Gamepad::MAX_AXIS - Gamepad::MIN_AXIS);
- axisState[axisInfo.axisIdx].value = Gamepad::MIN_AXIS + (INT32)(normalizedValue * range);
- }
- }
- else if(events[i].code <= ABS_HAT3Y) // POV
- {
- // Note: We only support a single POV and report events from all POVs as if they were from the
- // same source
- INT32 povIdx = events[i].code - ABS_HAT0X;
- ButtonCode povButton = BC_UNASSIGNED;
- if((povIdx & 0x1) == 0) // Even, x axis
- {
- if(events[i].value == -1)
- povButton = BC_GAMEPAD_DPAD_LEFT;
- else if(events[i].value == 1)
- povButton = BC_GAMEPAD_DPAD_RIGHT;
- }
- else // Odd, y axis
- {
- if(events[i].value == -1)
- povButton = BC_GAMEPAD_DPAD_UP;
- else if(events[i].value == 1)
- povButton = BC_GAMEPAD_DPAD_DOWN;
- }
- if(m->povState != povButton)
- {
- if(m->povState != BC_UNASSIGNED)
- mOwner->_notifyButtonReleased(m->info.id, m->povState, (UINT64)events[i].time.tv_usec);
- if(povButton != BC_UNASSIGNED)
- mOwner->_notifyButtonPressed(m->info.id, povButton, (UINT64)events[i].time.tv_usec);
- m->povState = povButton;
- }
- }
- break;
- }
- default: break;
- }
- }
- }
- for(UINT32 i = 0; i < 24; i++)
- {
- if(axisState[i].moved)
- mOwner->_notifyAxisMoved(m->info.id, i, axisState[i].value);
- }
- }
- void Gamepad::changeCaptureContext(UINT64 windowHandle)
- {
- m->hasInputFocus = windowHandle != (UINT64)-1;
- }
- }
|