/* PIP - Platform Independent Primitives Keyboard grabber for console Copyright (C) 2014 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "pikbdlistener.h" /** \class PIKbdListener * \brief Keyboard console input listener * \details This class provide listening of console keyboard input. * There is two ways to receive pressed key: * * external static functionwith format "void func(char key, void * data_)" * * event \a keyPressed() * * Also there is static variable \a exiting which by default is set to * \b false. If \a enableExitCapture() was called and listener was started * with function \a start(), this variable will be set to \b true if exit * key will be pressed. By default exit key is 'Q' = shift + 'q'. * To wait for this variable changes to \b true there is WAIT_FOR_EXIT macro * \snippet pikbdlistener.cpp main * */ bool PIKbdListener::exiting; PIKbdListener::PIKbdListener(KBFunc slot, void * _data): PIThread() { #ifdef WINDOWS hIn = GetStdHandle(STD_INPUT_HANDLE); GetConsoleMode(hIn, &smode); #else struct termios term; tcgetattr(0, &term); sterm = term; #endif is_active = true; ret_func = slot; data_ = _data; PIKbdListener::exiting = exit_enabled = false; start(); } void PIKbdListener::begin() { //cout << "list begin" << endl; #ifdef WINDOWS GetConsoleMode(hIn, &tmode); SetConsoleMode(hIn, ENABLE_PROCESSED_INPUT); #else struct termios term; tcgetattr(0, &term); term.c_lflag &= ~(ECHO | ICANON) | NOFLSH; tterm = term; tcsetattr(0, TCSAFLUSH, &term); #endif } void PIKbdListener::run() { rc = 0; char lc = 0; #ifdef WINDOWS INPUT_RECORD ir; ReadConsoleInput(hIn, &ir, 1, &ret); if (ir.EventType == KEY_EVENT) { KEY_EVENT_RECORD ker = ir.Event.KeyEvent; if (ker.bKeyDown) { bool ctrl = ((ker.dwControlKeyState & LEFT_CTRL_PRESSED) || (ker.dwControlKeyState & RIGHT_CTRL_PRESSED)); bool shift = (ker.dwControlKeyState & SHIFT_PRESSED); if (ker.dwControlKeyState & CAPSLOCK_ON) shift = !shift; //cout << "key " << int(ker.wVirtualKeyCode) << endl; switch (ker.wVirtualKeyCode) { case 37: ret = 1; lc = (ctrl ? CtrlLeftArrow : LeftArrow); break; case 38: ret = 1; lc = (ctrl ? CtrlUpArrow : UpArrow); break; case 39: ret = 1; lc = (ctrl ? CtrlRightArrow : RightArrow); break; case 40: ret = 1; lc = (ctrl ? CtrlDownArrow : DownArrow); break; default: ret = 1; lc = (shift ? char(toupper(ker.uChar.AsciiChar)) : ker.uChar.AsciiChar); break; } if (lc == 0) {piMSleep(10); return;} } else {piMSleep(10); return;} } else {piMSleep(10); return;} /*if (lc == 0) { ReadConsole(hIn, &rc, 1, &ret, 0); //cout << "read console" << endl; lc = char(rc); }*/ /*if (ret < 0 || ret > 3) return; lc = char(((uchar * )&rc)[ret - 1]); for (int i = 0; i < ret; ++i) cout << std::hex << int(((uchar * )&rc)[i]) << ' '; cout << endl << std::hex << rc << endl;*/ #else ret = read(0, &rc, 4); if (ret < 0 || ret > 3) {piMSleep(10); return;} lc = char(((uchar * )&rc)[ret - 1]); //for (int i = 0; i < ret; ++i) // cout << std::hex << int(((uchar * )&rc)[i]) << ' '; //cout << endl << std::hex << rc << endl; if (((char * )&rc)[0] == '\e' && ret == 3) { if (((char * )&rc)[1] == '[') { switch (((char * )&rc)[2]) { case 'A': lc = UpArrow; break; // up case 'B': lc = DownArrow; break; // down case 'C': lc = RightArrow; break; // right case 'D': lc = LeftArrow; break; // left } } } if (((char * )&rc)[0] == '5' && ret == 2) { switch (((char * )&rc)[1]) { case 'A': lc = CtrlUpArrow; break; // up case 'B': lc = CtrlDownArrow; break; // down case 'C': lc = CtrlRightArrow; break; // right case 'D': lc = CtrlLeftArrow; break; // left } } #endif if (exit_enabled && ret == 1 && lc == exit_key) { PIKbdListener::exiting = true; return; } if (ret > 0) { keyPressed(lc, data_); if (ret_func != 0) ret_func(lc, data_); } } void PIKbdListener::end() { //cout << "list end" << endl; #ifdef WINDOWS SetConsoleMode(hIn, smode); #else tcsetattr(0, TCSANOW, &sterm); #endif } void PIKbdListener::setActive(bool yes) { is_active = yes; if (is_active) { #ifdef WINDOWS SetConsoleMode(hIn, tmode); #else tcsetattr(0, TCSANOW, &tterm); #endif } else { #ifdef WINDOWS SetConsoleMode(hIn, smode); #else tcsetattr(0, TCSANOW, &sterm); #endif } }