diff options
Diffstat (limited to 'src/SFML/Window/DRM/InputImplUDev.cpp')
-rw-r--r-- | src/SFML/Window/DRM/InputImplUDev.cpp | 752 |
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 |