0

During the Boot of most *nix environments, many commands check to see if shift is held down and change their behaviour if it is (boot into a safe mode).

I would like to do the same thing. I am writing a script that runs a python script on boot, but I would like to be able to hold down the a key to prevent the execution of the python script and return control to the user.

Anyone know how to do this?

skycoop
  • 311
  • 1
  • 3
  • 7
  • 3
    I believe you are going to need to actively query the keyboard state via some external method (sysctl, etc.). That being said I think this is a terrible idea. It is inherently racy and unreliable. A boot flag would be a much better option if you really need something that can be set at boot time and not ahead of time. – Etan Reisner Jul 27 '15 at 20:08
  • Note that your Python script will not have the same resources available to the firmware or boot loader (which run much earlier than your Python script will and can assume things like full and exclusive access to the hardware.) – chepner Jul 28 '15 at 15:56

2 Answers2

0

Granting that it might not be a useful feature, OP would find it simpler to do inside the python script (bash is more limited in what it can do).

The biggest drawback in either case is that the time interval during which the script could do the check is very small - and a keypress could be eaten by some other process.

If there were only one process, then one could use the bash read command e.g., as in Bash script listen for key press to move on

However, if the script misses the initial keypress, sensing the state of the keyboard seems much harder:

Community
  • 1
  • 1
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
0

you can have a try with this c++ code. to compile it you can use g++ -std=c++17 -w -O3 main.cpp -o readkey.

the code using ioctl(fileno(fpKbd.get()), EVIOCGKEY(sizeof(keyMap)), keyMap); to polling all key state on a Linux keyboard with EVIOCGKEY. then check and print the all pressed keys.

Here is another example: https://newbedev.com/how-can-i-get-the-keyboard-state-in-linux

#include <string.h>
#include <memory>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <linux/input.h>

std::string GetKey(char ch)
{
    switch (ch) {
    case KEY_ESC:
        return "KEY_ESC";
    case KEY_1:
        return "KEY_1";
    case KEY_2:
        return "KEY_2";
    case KEY_3:
        return "KEY_3";
    case KEY_4:
        return "KEY_4";
    case KEY_5:
        return "KEY_5";
    case KEY_6:
        return "KEY_6";
    case KEY_7:
        return "KEY_7";
    case KEY_8:
        return "KEY_8";
    case KEY_9:
        return "KEY_9";
    case KEY_0:
        return "KEY_0";
    case KEY_MINUS:
        return "KEY_MINUS";
    case KEY_EQUAL:
        return "KEY_EQUAL";
    case KEY_BACKSPACE:
        return "KEY_BACKSPACE";
    case KEY_TAB:
        return "KEY_TAB";
    case KEY_Q:
        return "KEY_Q";
    case KEY_W:
        return "KEY_W";
    case KEY_E:
        return "KEY_E";
    case KEY_R:
        return "KEY_R";
    case KEY_T:
        return "KEY_T";
    case KEY_Y:
        return "KEY_Y";
    case KEY_U:
        return "KEY_U";
    case KEY_I:
        return "KEY_I";
    case KEY_O:
        return "KEY_O";
    case KEY_P:
        return "KEY_P";
    case KEY_LEFTBRACE:
        return "KEY_LEFTBRACE";
    case KEY_RIGHTBRACE:
        return "KEY_RIGHTBRACE";
    case KEY_ENTER:
        return "KEY_ENTER";
    case KEY_LEFTCTRL:
        return "KEY_LEFTCTRL";
    case KEY_A:
        return "KEY_A";
    case KEY_S:
        return "KEY_S";
    case KEY_D:
        return "KEY_D";
    case KEY_F:
        return "KEY_F";
    case KEY_G:
        return "KEY_G";
    case KEY_H:
        return "KEY_H";
    case KEY_J:
        return "KEY_J";
    case KEY_K:
        return "KEY_K";
    case KEY_L:
        return "KEY_L";
    case KEY_SEMICOLON:
        return "KEY_SEMICOLON";
    case KEY_APOSTROPHE:
        return "KEY_APOSTROPHE";
    case KEY_GRAVE:
        return "KEY_GRAVE";
    case KEY_LEFTSHIFT:
        return "KEY_LEFTSHIFT";
    case KEY_BACKSLASH:
        return "KEY_BACKSLASH";
    case KEY_Z:
        return "KEY_Z";
    case KEY_X:
        return "KEY_X";
    case KEY_C:
        return "KEY_C";
    case KEY_V:
        return "KEY_V";
    case KEY_B:
        return "KEY_B";
    case KEY_N:
        return "KEY_N";
    case KEY_M:
        return "KEY_M";
    case KEY_COMMA:
        return "KEY_COMMA";
    case KEY_DOT:
        return "KEY_DOT";
    case KEY_SLASH:
        return "KEY_SLASH";
    case KEY_RIGHTSHIFT:
        return "KEY_RIGHTSHIFT";
    case KEY_KPASTERISK:
        return "KEY_KPASTERISK";
    case KEY_LEFTALT:
        return "KEY_LEFTALT";
    case KEY_SPACE:
        return "KEY_SPACE";
    case KEY_CAPSLOCK:
        return "KEY_CAPSLOCK";
    case KEY_F1:
        return "KEY_F1";
    case KEY_F2:
        return "KEY_F2";
    case KEY_F3:
        return "KEY_F3";
    case KEY_F4:
        return "KEY_F4";
    case KEY_F5:
        return "KEY_F5";
    case KEY_F6:
        return "KEY_F6";
    case KEY_F7:
        return "KEY_F7";
    case KEY_F8:
        return "KEY_F8";
    case KEY_F9:
        return "KEY_F9";
    case KEY_F10:
        return "KEY_F10";
    case KEY_NUMLOCK:
        return "KEY_NUMLOCK";
    case KEY_SCROLLLOCK:
        return "KEY_SCROLLLOCK";
    case KEY_KP7:
        return "KEY_KP7";
    case KEY_KP8:
        return "KEY_KP8";
    case KEY_KP9:
        return "KEY_KP9";
    case KEY_KPMINUS:
        return "KEY_KPMINUS";
    case KEY_KP4:
        return "KEY_KP4";
    case KEY_KP5:
        return "KEY_KP5";
    case KEY_KP6:
        return "KEY_KP6";
    case KEY_KPPLUS:
        return "KEY_KPPLUS";
    case KEY_KP1:
        return "KEY_KP1";
    case KEY_KP2:
        return "KEY_KP2";
    case KEY_KP3:
        return "KEY_KP3";
    case KEY_KP0:
        return "KEY_KP0";
    case KEY_KPDOT:
        return "KEY_KPDOT";
    case KEY_ZENKAKUHANKAKU:
        return "KEY_ZENKAKUHANKAKU";
    case KEY_102ND:
        return "KEY_102ND";
    case KEY_F11:
        return "KEY_F11";
    case KEY_F12:
        return "KEY_F12";
    case KEY_RO:
        return "KEY_RO";
    case KEY_KATAKANA:
        return "KEY_KATAKANA";
    case KEY_HIRAGANA:
        return "KEY_HIRAGANA";
    case KEY_HENKAN:
        return "KEY_HENKAN";
    case KEY_KATAKANAHIRAGANA:
        return "KEY_KATAKANAHIRAGANA";
    case KEY_MUHENKAN:
        return "KEY_MUHENKAN";
    case KEY_KPJPCOMMA:
        return "KEY_KPJPCOMMA";
    case KEY_KPENTER:
        return "KEY_KPENTER";
    case KEY_RIGHTCTRL:
        return "KEY_RIGHTCTRL";
    case KEY_KPSLASH:
        return "KEY_KPSLASH";
    case KEY_SYSRQ:
        return "KEY_SYSRQ";
    case KEY_RIGHTALT:
        return "KEY_RIGHTALT";
    case KEY_HOME:
        return "KEY_HOME";
    case KEY_UP:
        return "KEY_UP";
    case KEY_PAGEUP:
        return "KEY_PAGEUP";
    case KEY_LEFT:
        return "KEY_LEFT";
    case KEY_RIGHT:
        return "KEY_RIGHT";
    case KEY_END:
        return "KEY_END";
    case KEY_DOWN:
        return "KEY_DOWN";
    case KEY_PAGEDOWN:
        return "KEY_PAGEDOWN";
    case KEY_INSERT:
        return "KEY_INSERT";
    case KEY_DELETE:
        return "KEY_DELETE";
    case KEY_MACRO:
        return "KEY_MACRO";
    case KEY_MUTE:
        return "KEY_MUTE";
    case KEY_VOLUMEDOWN:
        return "KEY_VOLUMEDOWN";
    case KEY_VOLUMEUP:
        return "KEY_VOLUMEUP";
    case KEY_POWER:
        return "KEY_POWER";
    case KEY_KPEQUAL:
        return "KEY_KPEQUAL";
    case KEY_KPPLUSMINUS:
        return "KEY_KPPLUSMINUS";
    case KEY_PAUSE:
        return "KEY_PAUSE";
    case KEY_KPCOMMA:
        return "KEY_KPCOMMA";
    case KEY_HANGUEL:
        return "KEY_HANGUEL";
    case KEY_HANJA:
        return "KEY_HANJA";
    case KEY_YEN:
        return "KEY_YEN";
    case KEY_LEFTMETA:
        return "KEY_LEFTMETA";
    case KEY_RIGHTMETA:
        return "KEY_RIGHTMETA";
    case KEY_COMPOSE:
        return "KEY_COMPOSE";
    case KEY_STOP:
        return "KEY_STOP";
    case KEY_CALC:
        return "KEY_CALC";
    case KEY_SETUP:
        return "KEY_SETUP";
    case KEY_SLEEP:
        return "KEY_SLEEP";
    case KEY_WAKEUP:
        return "KEY_WAKEUP";
    case KEY_PROG1:
        return "KEY_PROG1";
    case KEY_SCREENLOCK:
        return "KEY_SCREENLOCK";
    case KEY_MAIL:
        return "KEY_MAIL";
    case KEY_BOOKMARKS:
        return "KEY_BOOKMARKS";
    case KEY_COMPUTER:
        return "KEY_COMPUTER";
    case KEY_BACK:
        return "KEY_BACK";
    case KEY_FORWARD:
        return "KEY_FORWARD";
    case KEY_EJECTCLOSECD:
        return "KEY_EJECTCLOSECD";
    case KEY_NEXTSONG:
        return "KEY_NEXTSONG";
    case KEY_PLAYPAUSE:
        return "KEY_PLAYPAUSE";
    case KEY_PREVIOUSSONG:
        return "KEY_PREVIOUSSONG";
    case KEY_STOPCD:
        return "KEY_STOPCD";
    case KEY_HOMEPAGE:
        return "KEY_HOMEPAGE";
    case KEY_REFRESH:
        return "KEY_REFRESH";
    case KEY_F13:
        return "KEY_F13";
    case KEY_F14:
        return "KEY_F14";
    case KEY_F15:
        return "KEY_F15";
    case KEY_F21:
        return "KEY_F21";
    case KEY_SUSPEND:
        return "KEY_SUSPEND";
    case KEY_CAMERA:
        return "KEY_CAMERA";
    case KEY_EMAIL:
        return "KEY_EMAIL";
    case KEY_SEARCH:
        return "KEY_SEARCH";
    case KEY_BRIGHTNESSDOWN:
        return "KEY_BRIGHTNESSDOWN";
    case KEY_BRIGHTNESSUP:
        return "KEY_BRIGHTNESSUP";
    case KEY_MEDIA:
        return "KEY_MEDIA";
    case KEY_SWITCHVIDEOMODE:
        return "KEY_SWITCHVIDEOMODE";
    case KEY_BATTERY:
        return "KEY_BATTERY";
    case KEY_UNKNOWN:
        return "KEY_UNKNOWN";
    }
    return "UNKNOWN";
}

std::vector<std::string> GetKeyboard()
{
    std::ifstream file("/proc/bus/input/devices");
    if (!file.is_open()) {
        std::cout << "unable to open devices" << std::endl;
        return {};
    }

    std::vector<std::string> keyboards;
    bool inKeyboardSection = false;
    for (std::string line; getline(file, line);) {
        std::transform(line.begin(), line.end(), line.begin(), ::tolower);
        if (line.find("keyboard") != line.npos)
            inKeyboardSection = true;
        if (inKeyboardSection && line.empty())
            inKeyboardSection = false;
        if (inKeyboardSection && line.find("h: handlers=") != line.npos && line.find("kbd") != line.npos) {
            auto start = line.find("event");
            auto end = line.find(" ", start);
            if (start != line.npos && end != line.npos) {
                keyboards.push_back("/dev/input/" + line.substr(start, end - start));
            }
        }
    }
    return keyboards;
}

int main(int argc, char* argv[])
{
    auto kbds = GetKeyboard();
    if (kbds.empty()) {
        std::cout << "no keyboard found" << std::endl;
        return 1;
    }

    std::string keys;
    for (auto kbd : kbds) {
        auto deleter = [](FILE* fd) { fclose(fd); };
        std::unique_ptr<FILE, decltype(deleter)> fpKbd(fopen(kbd.c_str(), "r"), deleter);

        if (!fpKbd) {
            std::cout << "unable to open keyboard" << std::endl;
            return 1;
        }

        char keyMap[KEY_MAX / 8 + 1];

        memset(keyMap, 0, sizeof(keyMap));
        ioctl(fileno(fpKbd.get()), EVIOCGKEY(sizeof(keyMap)), keyMap);
        for (int i = 0; i < KEY_MAX / 8 + 1; ++i) {
            auto ch = keyMap[i];
            for (int j = 0; j < 8; ++j) {
                if ((ch >> j) & 1) {
                    if (!keys.empty())
                        keys += ",";
                    keys += GetKey(i * 8 + j);
                }
            }
        }
    }

    if (!keys.empty())
        std::cout << keys << std::endl;
}
TQ.Liu
  • 81
  • 6
  • That's a massive amount of code just to check if the shift key is depressed. Where did you get it? You should cite your source. And trim it down to just the relevant part, please. – John Kugelman Nov 29 '21 at 20:18
  • Can you also explain how it works? A code dump without explanation isn't terribly useful. – John Kugelman Nov 29 '21 at 20:20
  • the code using `ioctl(fileno(fpKbd.get()), EVIOCGKEY(sizeof(keyMap)), keyMap);` to get polling all key state on a Linux keyboard with EVIOCGKEY. then check and print the all pressed key. – TQ.Liu Nov 30 '21 at 17:40
  • Please [edit] your answer. Comments are ephemeral and can be deleted at any time. – John Kugelman Nov 30 '21 at 17:45