summaryrefslogtreecommitdiff
path: root/src/SFML/Window/DRM/InputImplUDev.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/SFML/Window/DRM/InputImplUDev.cpp')
-rw-r--r--src/SFML/Window/DRM/InputImplUDev.cpp752
1 files changed, 752 insertions, 0 deletions
diff --git a/src/SFML/Window/DRM/InputImplUDev.cpp b/src/SFML/Window/DRM/InputImplUDev.cpp
new file mode 100644
index 0000000..2c78cf9
--- /dev/null
+++ b/src/SFML/Window/DRM/InputImplUDev.cpp
@@ -0,0 +1,752 @@
+////////////////////////////////////////////////////////////
+//
+// SFML - Simple and Fast Multimedia Library
+// Copyright (C) 2016 Andrew Mickelson
+//
+// This software is provided 'as-is', without any express or implied warranty.
+// In no event will the authors be held liable for any damages arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it freely,
+// subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented;
+// you must not claim that you wrote the original software.
+// If you use this software in a product, an acknowledgment
+// in the product documentation would be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such,
+// and must not be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////
+// Headers
+////////////////////////////////////////////////////////////
+#include <SFML/Window/DRM/InputImplUDev.hpp>
+#include <SFML/System/Err.hpp>
+#include <SFML/System/Lock.hpp>
+#include <SFML/System/Mutex.hpp>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <queue>
+#include <sstream>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
+#include <vector>
+
+
+namespace
+{
+ struct TouchSlot
+ {
+ int oldId;
+ int id;
+ sf::Vector2i pos;
+
+ TouchSlot() :
+ oldId(-1),
+ id(-1),
+ pos(0, 0)
+ {
+ }
+ };
+
+ sf::Mutex inputMutex; // threadsafe? maybe...
+ sf::Vector2i mousePos; // current mouse position
+
+ std::vector<int> fileDescriptors; // list of open file descriptors for /dev/input
+ std::vector<bool> mouseMap(sf::Mouse::ButtonCount, false); // track whether keys are down
+ std::vector<bool> keyMap(sf::Keyboard::KeyCount, false); // track whether mouse buttons are down
+
+ int touchFd = -1; // file descriptor we have seen MT events on; assumes only 1
+ std::vector<TouchSlot> touchSlots; // track the state of each touch "slot"
+ int currentSlot = 0; // which slot are we currently updating?
+
+ std::queue<sf::Event> eventQueue; // events received and waiting to be consumed
+ const int MAX_QUEUE = 64; // The maximum size we let eventQueue grow to
+
+ termios newTerminalConfig, oldTerminalConfig; // Terminal configurations
+
+ bool altDown() { return (keyMap[sf::Keyboard::LAlt] || keyMap[sf::Keyboard::RAlt]); }
+ bool controlDown() { return (keyMap[sf::Keyboard::LControl] || keyMap[sf::Keyboard::RControl]); }
+ bool shiftDown() { return (keyMap[sf::Keyboard::LShift] || keyMap[sf::Keyboard::RShift]); }
+ bool systemDown() { return (keyMap[sf::Keyboard::LSystem] || keyMap[sf::Keyboard::RSystem]); }
+
+ void uninitFileDescriptors(void)
+ {
+ for (std::vector<int>::iterator itr = fileDescriptors.begin(); itr != fileDescriptors.end(); ++itr)
+ close(*itr);
+ }
+
+#define BITS_PER_LONG (sizeof(unsigned long) * 8)
+#define NBITS(x) (((x - 1) / BITS_PER_LONG) + 1)
+#define OFF(x) (x % BITS_PER_LONG)
+#define LONG(x) (x / BITS_PER_LONG)
+#define TEST_BIT(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
+
+ // Only keep fileDescriptors that we think are a keyboard, mouse or touchpad/touchscreen
+ // Joysticks are handled in /src/SFML/Window/Unix/JoystickImpl.cpp
+ bool keepFileDescriptor(int fileDesc)
+ {
+ unsigned long bitmask_ev[NBITS(EV_MAX)];
+ unsigned long bitmask_key[NBITS(KEY_MAX)];
+ unsigned long bitmask_abs[NBITS(ABS_MAX)];
+ unsigned long bitmask_rel[NBITS(REL_MAX)];
+
+ ioctl(fileDesc, EVIOCGBIT(0, sizeof(bitmask_ev)), &bitmask_ev);
+ ioctl(fileDesc, EVIOCGBIT(EV_KEY, sizeof(bitmask_key)), &bitmask_key);
+ ioctl(fileDesc, EVIOCGBIT(EV_ABS, sizeof(bitmask_abs)), &bitmask_abs);
+ ioctl(fileDesc, EVIOCGBIT(EV_REL, sizeof(bitmask_rel)), &bitmask_rel);
+
+ // This is the keyboard test used by SDL.
+ // The first 32 bits are ESC, numbers and Q to D; If we have any of those,
+ // consider it a keyboard device; do not test for KEY_RESERVED, though
+ bool is_keyboard = (bitmask_key[0] & 0xFFFFFFFE);
+
+ bool is_abs = TEST_BIT(EV_ABS, bitmask_ev)
+ && TEST_BIT(ABS_X, bitmask_abs) && TEST_BIT(ABS_Y, bitmask_abs);
+
+ bool is_rel = TEST_BIT(EV_REL, bitmask_ev)
+ && TEST_BIT(REL_X, bitmask_rel) && TEST_BIT(REL_Y, bitmask_rel);
+
+ bool is_mouse = (is_abs || is_rel) && TEST_BIT(BTN_MOUSE, bitmask_key);
+
+ bool is_touch = is_abs && (TEST_BIT(BTN_TOOL_FINGER, bitmask_key) || TEST_BIT(BTN_TOUCH, bitmask_key));
+
+ return is_keyboard || is_mouse || is_touch;
+ }
+
+ void initFileDescriptors()
+ {
+ static bool initialized = false;
+ if (initialized)
+ return;
+
+ initialized = true;
+
+ for (int i = 0; i < 32; i++)
+ {
+ std::string name("/dev/input/event");
+ std::ostringstream stream;
+ stream << i;
+ name += stream.str();
+
+ int tempFD = open(name.c_str(), O_RDONLY | O_NONBLOCK);
+
+ if (tempFD < 0)
+ {
+ if (errno != ENOENT)
+ sf::err() << "Error opening " << name << ": " << std::strerror(errno) << std::endl;
+
+ continue;
+ }
+
+ if (keepFileDescriptor(tempFD))
+ fileDescriptors.push_back(tempFD);
+ else
+ close(tempFD);
+ }
+
+ std::atexit(uninitFileDescriptors);
+ }
+
+ sf::Mouse::Button toMouseButton(int code)
+ {
+ switch (code)
+ {
+ case BTN_LEFT: return sf::Mouse::Left;
+ case BTN_RIGHT: return sf::Mouse::Right;
+ case BTN_MIDDLE: return sf::Mouse::Middle;
+ case BTN_SIDE: return sf::Mouse::XButton1;
+ case BTN_EXTRA: return sf::Mouse::XButton2;
+
+ default:
+ return sf::Mouse::ButtonCount;
+ }
+ }
+
+ sf::Keyboard::Key toKey(int code)
+ {
+ switch (code)
+ {
+ case KEY_ESC: return sf::Keyboard::Escape;
+ case KEY_1: return sf::Keyboard::Num1;
+ case KEY_2: return sf::Keyboard::Num2;
+ case KEY_3: return sf::Keyboard::Num3;
+ case KEY_4: return sf::Keyboard::Num4;
+ case KEY_5: return sf::Keyboard::Num5;
+ case KEY_6: return sf::Keyboard::Num6;
+ case KEY_7: return sf::Keyboard::Num7;
+ case KEY_8: return sf::Keyboard::Num8;
+ case KEY_9: return sf::Keyboard::Num9;
+ case KEY_0: return sf::Keyboard::Num0;
+ case KEY_MINUS: return sf::Keyboard::Hyphen;
+ case KEY_EQUAL: return sf::Keyboard::Equal;
+ case KEY_BACKSPACE: return sf::Keyboard::Backspace;
+ case KEY_TAB: return sf::Keyboard::Tab;
+ case KEY_Q: return sf::Keyboard::Q;
+ case KEY_W: return sf::Keyboard::W;
+ case KEY_E: return sf::Keyboard::E;
+ case KEY_R: return sf::Keyboard::R;
+ case KEY_T: return sf::Keyboard::T;
+ case KEY_Y: return sf::Keyboard::Y;
+ case KEY_U: return sf::Keyboard::U;
+ case KEY_I: return sf::Keyboard::I;
+ case KEY_O: return sf::Keyboard::O;
+ case KEY_P: return sf::Keyboard::P;
+ case KEY_LEFTBRACE: return sf::Keyboard::LBracket;
+ case KEY_RIGHTBRACE: return sf::Keyboard::RBracket;
+ case KEY_KPENTER:
+ case KEY_ENTER: return sf::Keyboard::Enter;
+ case KEY_LEFTCTRL: return sf::Keyboard::LControl;
+ case KEY_A: return sf::Keyboard::A;
+ case KEY_S: return sf::Keyboard::S;
+ case KEY_D: return sf::Keyboard::D;
+ case KEY_F: return sf::Keyboard::F;
+ case KEY_G: return sf::Keyboard::G;
+ case KEY_H: return sf::Keyboard::H;
+ case KEY_J: return sf::Keyboard::J;
+ case KEY_K: return sf::Keyboard::K;
+ case KEY_L: return sf::Keyboard::L;
+ case KEY_SEMICOLON: return sf::Keyboard::Semicolon;
+ case KEY_APOSTROPHE: return sf::Keyboard::Quote;
+ case KEY_GRAVE: return sf::Keyboard::Grave;
+ case KEY_LEFTSHIFT: return sf::Keyboard::LShift;
+ case KEY_BACKSLASH: return sf::Keyboard::Backslash;
+ case KEY_Z: return sf::Keyboard::Z;
+ case KEY_X: return sf::Keyboard::X;
+ case KEY_C: return sf::Keyboard::C;
+ case KEY_V: return sf::Keyboard::V;
+ case KEY_B: return sf::Keyboard::B;
+ case KEY_N: return sf::Keyboard::N;
+ case KEY_M: return sf::Keyboard::M;
+ case KEY_COMMA: return sf::Keyboard::Comma;
+ case KEY_DOT: return sf::Keyboard::Period;
+ case KEY_SLASH: return sf::Keyboard::Slash;
+ case KEY_RIGHTSHIFT: return sf::Keyboard::RShift;
+ case KEY_KPASTERISK: return sf::Keyboard::Multiply;
+ case KEY_LEFTALT: return sf::Keyboard::LAlt;
+ case KEY_SPACE: return sf::Keyboard::Space;
+ case KEY_F1: return sf::Keyboard::F1;
+ case KEY_F2: return sf::Keyboard::F2;
+ case KEY_F3: return sf::Keyboard::F3;
+ case KEY_F4: return sf::Keyboard::F4;
+ case KEY_F5: return sf::Keyboard::F5;
+ case KEY_F6: return sf::Keyboard::F6;
+ case KEY_F7: return sf::Keyboard::F7;
+ case KEY_F8: return sf::Keyboard::F8;
+ case KEY_F9: return sf::Keyboard::F9;
+ case KEY_F10: return sf::Keyboard::F10;
+ case KEY_F11: return sf::Keyboard::F11;
+ case KEY_F12: return sf::Keyboard::F12;
+ case KEY_F13: return sf::Keyboard::F13;
+ case KEY_F14: return sf::Keyboard::F14;
+ case KEY_F15: return sf::Keyboard::F15;
+ case KEY_KP7: return sf::Keyboard::Numpad7;
+ case KEY_KP8: return sf::Keyboard::Numpad8;
+ case KEY_KP9: return sf::Keyboard::Numpad9;
+ case KEY_KPMINUS: return sf::Keyboard::Subtract;
+ case KEY_KP4: return sf::Keyboard::Numpad4;
+ case KEY_KP5: return sf::Keyboard::Numpad5;
+ case KEY_KP6: return sf::Keyboard::Numpad6;
+ case KEY_KPPLUS: return sf::Keyboard::Add;
+ case KEY_KP1: return sf::Keyboard::Numpad1;
+ case KEY_KP2: return sf::Keyboard::Numpad2;
+ case KEY_KP3: return sf::Keyboard::Numpad3;
+ case KEY_KP0: return sf::Keyboard::Numpad0;
+ case KEY_KPDOT: return sf::Keyboard::Delete;
+ case KEY_RIGHTCTRL: return sf::Keyboard::RControl;
+ case KEY_KPSLASH: return sf::Keyboard::Divide;
+ case KEY_RIGHTALT: return sf::Keyboard::RAlt;
+ case KEY_HOME: return sf::Keyboard::Home;
+ case KEY_UP: return sf::Keyboard::Up;
+ case KEY_PAGEUP: return sf::Keyboard::PageUp;
+ case KEY_LEFT: return sf::Keyboard::Left;
+ case KEY_RIGHT: return sf::Keyboard::Right;
+ case KEY_END: return sf::Keyboard::End;
+ case KEY_DOWN: return sf::Keyboard::Down;
+ case KEY_PAGEDOWN: return sf::Keyboard::PageDown;
+ case KEY_INSERT: return sf::Keyboard::Insert;
+ case KEY_DELETE: return sf::Keyboard::Delete;
+ case KEY_PAUSE: return sf::Keyboard::Pause;
+ case KEY_LEFTMETA: return sf::Keyboard::LSystem;
+ case KEY_RIGHTMETA: return sf::Keyboard::RSystem;
+
+ case KEY_RESERVED:
+ case KEY_SYSRQ:
+ case KEY_CAPSLOCK:
+ case KEY_NUMLOCK:
+ case KEY_SCROLLLOCK:
+ default:
+ return sf::Keyboard::Unknown;
+ }
+ }
+
+ void pushEvent(sf::Event& event)
+ {
+ if (eventQueue.size() >= MAX_QUEUE)
+ eventQueue.pop();
+
+ eventQueue.push(event);
+ }
+
+ TouchSlot& atSlot(int idx)
+ {
+ if (idx >= static_cast<int>(touchSlots.size()))
+ touchSlots.resize(static_cast<size_t>(idx + 1));
+ return touchSlots.at(static_cast<size_t>(idx));
+ }
+
+ void processSlots()
+ {
+ for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
+ {
+ sf::Event event;
+
+ event.touch.x = slot->pos.x;
+ event.touch.y = slot->pos.y;
+
+ if (slot->oldId == slot->id)
+ {
+ event.type = sf::Event::TouchMoved;
+ event.touch.finger = static_cast<unsigned int>(slot->id);
+ pushEvent(event);
+ }
+ else
+ {
+ if (slot->oldId != -1)
+ {
+ event.type = sf::Event::TouchEnded;
+ event.touch.finger = static_cast<unsigned int>(slot->oldId);
+ pushEvent(event);
+ }
+ if (slot->id != -1)
+ {
+ event.type = sf::Event::TouchBegan;
+ event.touch.finger = static_cast<unsigned int>(slot->id);
+ pushEvent(event);
+ }
+
+ slot->oldId = slot->id;
+ }
+ }
+ }
+
+ bool eventProcess(sf::Event& event)
+ {
+ sf::Lock lock(inputMutex);
+
+ // Ensure that we are initialized
+ initFileDescriptors();
+
+ // This is for handling the Backspace and DEL text events, which we
+ // generate based on keystrokes (and not stdin)
+ static unsigned int doDeferredText = 0;
+ if (doDeferredText)
+ {
+ event.type = sf::Event::TextEntered;
+ event.text.unicode = doDeferredText;
+ doDeferredText = 0;
+ return true;
+ }
+
+ ssize_t bytesRead;
+
+ // Check all the open file descriptors for the next event
+ for (std::vector<int>::iterator itr = fileDescriptors.begin(); itr != fileDescriptors.end(); ++itr)
+ {
+ input_event inputEvent;
+ bytesRead = read(*itr, &inputEvent, sizeof(inputEvent));
+
+ while (bytesRead > 0)
+ {
+ if (inputEvent.type == EV_KEY)
+ {
+ sf::Mouse::Button mb = toMouseButton(inputEvent.code);
+ if (mb != sf::Mouse::ButtonCount)
+ {
+ event.type = inputEvent.value ? sf::Event::MouseButtonPressed : sf::Event::MouseButtonReleased;
+ event.mouseButton.button = mb;
+ event.mouseButton.x = mousePos.x;
+ event.mouseButton.y = mousePos.y;
+
+ mouseMap[mb] = inputEvent.value;
+ return true;
+ }
+ else
+ {
+ sf::Keyboard::Key kb = toKey(inputEvent.code);
+
+ unsigned int special = 0;
+ if ((kb == sf::Keyboard::Delete)
+ || (kb == sf::Keyboard::Backspace))
+ special = (kb == sf::Keyboard::Delete) ? 127 : 8;
+
+ if (inputEvent.value == 2)
+ {
+ // key repeat events
+ //
+ if (special)
+ {
+ event.type = sf::Event::TextEntered;
+ event.text.unicode = special;
+ return true;
+ }
+ }
+ else if (kb != sf::Keyboard::Unknown)
+ {
+ // key down and key up events
+ //
+ event.type = inputEvent.value ? sf::Event::KeyPressed : sf::Event::KeyReleased;
+ event.key.code = kb;
+ event.key.scancode = sf::Keyboard::Scan::Unknown; // TODO: not implemented
+ event.key.alt = altDown();
+ event.key.control = controlDown();
+ event.key.shift = shiftDown();
+ event.key.system = systemDown();
+
+ keyMap[static_cast<std::size_t>(kb)] = inputEvent.value;
+
+ if (special && inputEvent.value)
+ doDeferredText = special;
+
+ return true;
+ }
+ }
+ }
+ else if (inputEvent.type == EV_REL)
+ {
+ bool posChange = false;
+ switch (inputEvent.code)
+ {
+ case REL_X:
+ mousePos.x += inputEvent.value;
+ posChange = true;
+ break;
+
+ case REL_Y:
+ mousePos.y += inputEvent.value;
+ posChange = true;
+ break;
+
+ case REL_WHEEL:
+ event.type = sf::Event::MouseWheelScrolled;
+ event.mouseWheelScroll.delta = static_cast<float>(inputEvent.value);
+ event.mouseWheelScroll.x = mousePos.x;
+ event.mouseWheelScroll.y = mousePos.y;
+ return true;
+ }
+
+ if (posChange)
+ {
+ event.type = sf::Event::MouseMoved;
+ event.mouseMove.x = mousePos.x;
+ event.mouseMove.y = mousePos.y;
+ return true;
+ }
+ }
+ else if (inputEvent.type == EV_ABS)
+ {
+ switch (inputEvent.code)
+ {
+ case ABS_MT_SLOT:
+ currentSlot = inputEvent.value;
+ touchFd = *itr;
+ break;
+ case ABS_MT_TRACKING_ID:
+ atSlot(currentSlot).id = inputEvent.value;
+ touchFd = *itr;
+ break;
+ case ABS_MT_POSITION_X:
+ atSlot(currentSlot).pos.x = inputEvent.value;
+ touchFd = *itr;
+ break;
+ case ABS_MT_POSITION_Y:
+ atSlot(currentSlot).pos.y = inputEvent.value;
+ touchFd = *itr;
+ break;
+ }
+ }
+ else if (inputEvent.type == EV_SYN && inputEvent.code == SYN_REPORT &&
+ *itr == touchFd)
+ {
+ // This pushes events directly to the queue, because it
+ // can generate more than one event.
+ processSlots();
+ }
+
+ bytesRead = read(*itr, &inputEvent, sizeof(inputEvent));
+ }
+
+ if ((bytesRead < 0) && (errno != EAGAIN))
+ sf::err() << " Error: " << std::strerror(errno) << std::endl;
+ }
+
+ // Finally check if there is a Text event on stdin
+ //
+ // We only clear the ICANON flag for the time of reading
+
+ newTerminalConfig.c_lflag &= ~static_cast<tcflag_t>(ICANON);
+ tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig);
+
+ timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ unsigned char code = 0;
+
+ fd_set readFDSet;
+ FD_ZERO(&readFDSet);
+ FD_SET(STDIN_FILENO, &readFDSet);
+ int ready = select(STDIN_FILENO + 1, &readFDSet, NULL, NULL, &timeout);
+
+ if (ready > 0 && FD_ISSET(STDIN_FILENO, &readFDSet))
+ bytesRead = read(STDIN_FILENO, &code, 1);
+
+ if ((code == 127) || (code == 8)) // Suppress 127 (DEL) to 8 (BACKSPACE)
+ code = 0;
+ else if (code == 27) // ESC
+ {
+ // Suppress ANSI escape sequences
+ FD_ZERO(&readFDSet);
+ FD_SET(STDIN_FILENO, &readFDSet);
+ ready = select(STDIN_FILENO + 1, &readFDSet, NULL, NULL, &timeout);
+ if (ready > 0 && FD_ISSET(STDIN_FILENO, &readFDSet))
+ {
+ unsigned char tempBuffer[16];
+ bytesRead = read(STDIN_FILENO, tempBuffer, 16);
+ code = 0;
+ }
+ }
+
+ newTerminalConfig.c_lflag |= ICANON;
+ tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig);
+
+ if (code > 0)
+ {
+ // TODO: Proper unicode handling
+ event.type = sf::Event::TextEntered;
+ event.text.unicode = code;
+ return true;
+ }
+
+ // No events available
+ return false;
+ }
+
+ // assumes inputMutex is locked
+ void update()
+ {
+ sf::Event event;
+ while (eventProcess(event))
+ {
+ pushEvent(event);
+ }
+ }
+}
+
+namespace sf
+{
+namespace priv
+{
+////////////////////////////////////////////////////////////
+bool InputImpl::isKeyPressed(Keyboard::Key key)
+{
+ Lock lock(inputMutex);
+ if ((key < 0) || (key >= static_cast<int>(keyMap.size())))
+ return false;
+
+ update();
+ return keyMap[static_cast<std::size_t>(key)];
+}
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isKeyPressed(Keyboard::Scancode /* code */)
+{
+ // TODO: not implemented
+ err() << "sf::Keyboard::isKeyPressed(Keyboard::Scancode) is not implemented for DRM." << std::endl;
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Keyboard::Key InputImpl::localize(Keyboard::Scancode /* code */)
+{
+ // TODO: not implemented
+ err() << "sf::Keyboard::localize is not implemented for DRM." << std::endl;
+ return Keyboard::Unknown;
+}
+
+
+////////////////////////////////////////////////////////////
+Keyboard::Scancode InputImpl::delocalize(Keyboard::Key /* key */)
+{
+ // TODO: not implemented
+ err() << "sf::Keyboard::delocalize is not implemented for DRM." << std::endl;
+ return Keyboard::Scan::Unknown;
+}
+
+
+////////////////////////////////////////////////////////////
+String InputImpl::getDescription(Keyboard::Scancode /* code */)
+{
+ // TODO: not implemented
+ err() << "sf::Keyboard::getDescription is not implemented for DRM." << std::endl;
+ return "";
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
+{
+ // Not applicable
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isMouseButtonPressed(Mouse::Button button)
+{
+ Lock lock(inputMutex);
+ if ((button < 0) || (button >= static_cast<int>(mouseMap.size())))
+ return false;
+
+ update();
+ return mouseMap[button];
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition()
+{
+ Lock lock(inputMutex);
+ return mousePos;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getMousePosition(const WindowBase& /*relativeTo*/)
+{
+ return getMousePosition();
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position)
+{
+ Lock lock(inputMutex);
+ mousePos = position;
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setMousePosition(const Vector2i& position, const WindowBase& /*relativeTo*/)
+{
+ setMousePosition(position);
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::isTouchDown(unsigned int finger)
+{
+ for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
+ {
+ if (slot->id == static_cast<int>(finger))
+ return true;
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int finger)
+{
+ for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
+ {
+ if (slot->id == static_cast<int>(finger))
+ return slot->pos;
+ }
+
+ return Vector2i();
+}
+
+
+////////////////////////////////////////////////////////////
+Vector2i InputImpl::getTouchPosition(unsigned int finger, const WindowBase& /*relativeTo*/)
+{
+ return getTouchPosition(finger);
+}
+
+
+////////////////////////////////////////////////////////////
+bool InputImpl::checkEvent(sf::Event& event)
+{
+ Lock lock(inputMutex);
+ if (!eventQueue.empty())
+ {
+ event = eventQueue.front();
+ eventQueue.pop();
+
+ return true;
+ }
+
+ if (eventProcess(event))
+ {
+ return true;
+ }
+ else
+ {
+ // In the case of multitouch, eventProcess() could have returned false
+ // but added events directly to the queue. (This is ugly, but I'm not
+ // sure of a good way to handle generating multiple events at once.)
+ if (!eventQueue.empty())
+ {
+ event = eventQueue.front();
+ eventQueue.pop();
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::setTerminalConfig()
+{
+ sf::Lock lock(inputMutex);
+ initFileDescriptors();
+
+ tcgetattr(STDIN_FILENO, &newTerminalConfig); // get current terminal config
+ oldTerminalConfig = newTerminalConfig; // create a backup
+ newTerminalConfig.c_lflag &= ~static_cast<tcflag_t>(ECHO); // disable console feedback
+ newTerminalConfig.c_lflag &= ~static_cast<tcflag_t>(ISIG); // disable signals
+ newTerminalConfig.c_lflag |= ICANON; // disable noncanonical mode
+ newTerminalConfig.c_iflag |= IGNCR; // ignore carriage return
+ tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig); // set our new config
+ tcflush(STDIN_FILENO, TCIFLUSH); // flush the buffer
+}
+
+
+////////////////////////////////////////////////////////////
+void InputImpl::restoreTerminalConfig()
+{
+ sf::Lock lock(inputMutex);
+ initFileDescriptors();
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldTerminalConfig); // restore terminal config
+ tcflush(STDIN_FILENO, TCIFLUSH); // flush the buffer
+}
+
+} // namespace priv
+
+} // namespace sf