Keyboard

如何在控制台應用程序中獲得對修飾鍵的使用者級訪問權限?

  • January 25, 2012

我需要訪問我正在編寫的控制台應用程序(個性化編輯器)的修飾鍵狀態。

是否有任何包/庫/提供此訪問權限的任何東西?

我從某個地方拼湊了以下內容,但它只有在你是 root 時才有效,而且我真的不想在 root 級別搞砸。

#include <iostream>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <termios.h>
#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#include <errno.h>

int kbhit(void)
{
   struct termios oldt, newt;
   int ch;
   int oldf;

   tcgetattr(STDIN_FILENO, &oldt);

   newt = oldt;
   newt.c_lflag &= ~0000172 ; //~(ICANON | ECHO);

   tcsetattr(STDIN_FILENO, TCSANOW, &newt);
   oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
   fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

   ch = getchar();

   tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
   fcntl(STDIN_FILENO, F_SETFL, oldf);

   return ch;
}

enum MODKEYS
{
   SHIFT_L = 1,
   SHIFT_R = 2,
   CTRL_L = 4,
   CTRL_R = 8,
   ALT_L = 16,
   ALT_R = 32,
};

int chkmodifiers()
{
   int mods=0,keyb,mask;
   char key_map[KEY_MAX/8 + 1];    //  Create a byte array the size of the number of keys

   //event1 - got by inspecting /dev/input/... 
   FILE *kbd = fopen("/dev/input/event1", "r");
   if (kbd == NULL)
   {
       printf("(chkmodifiers) ERROR: %s\n", strerror(errno)); //permission - got to be root!
       return 0;
   }

   memset(key_map, 0, sizeof(key_map));
   ioctl(fileno(kbd), EVIOCGKEY(sizeof(key_map)), key_map);    //  Fill the keymap with the current keyboard state

   keyb = key_map[KEY_LEFTSHIFT/8];
   mask = 1 << (KEY_LEFTSHIFT % 8);
   if (keyb & mask) mods += SHIFT_L;

   keyb = key_map[KEY_RIGHTSHIFT/8];
   mask = 1 << (KEY_RIGHTSHIFT % 8);
   if (keyb & mask) mods += SHIFT_R;

   keyb = key_map[KEY_LEFTCTRL/8];
   mask = 1 << (KEY_LEFTCTRL % 8);
   if (keyb & mask) mods += CTRL_L;

   keyb = key_map[KEY_RIGHTCTRL/8];
   mask = 1 << (KEY_RIGHTCTRL % 8);
   if (keyb & mask) mods += CTRL_R;

   keyb = key_map[KEY_LEFTALT/8];
   mask = 1 << (KEY_LEFTALT % 8);
   if (keyb & mask) mods += ALT_L;

   keyb = key_map[KEY_RIGHTALT/8];
   mask = 1 << (KEY_RIGHTALT % 8);
   if (keyb & mask) mods += ALT_R;

   return mods;

}


int main()
{
   puts("Press a key!");

   char ch=0;
   int n=0,m;

   while (ch != 'q')
   {
       n = kbhit();
       if (n != -1)
       {
           m = chkmodifiers();
           ch =  (char)n;
           printf("You pressed '%c' [%d]\n", ch, n);
           if ((m & SHIFT_L) == SHIFT_L) printf(" .. and ls\n");
           if ((m & SHIFT_R) == SHIFT_R) printf(" .. and rs\n");
           if ((m & CTRL_L) == CTRL_L) printf(" .. and lc\n");
           if ((m & CTRL_R) == CTRL_R) printf(" .. and rc\n");
           if ((m & ALT_L) == ALT_L) printf(" .. and la\n");
           if ((m & ALT_R) == ALT_R) printf(" .. and ra\n");

       }
   }
   return 0;
}

也許看看libtermkey,一個終端鍵輸入庫,可辨識特殊鍵(如箭頭和功能鍵),包括“修改”鍵,如Ctrl-Left.

另一種選擇可能是增強charm的功能,這是一個最小的 ncurses 副本。

在終端中,一直很難獲得這種資訊。你只能得到一個“keycode”,當然,它意味著不同的東西,這取決於你使用的作業系統、鍵盤和終端的組合。

您可以通過呼叫xmodmap在您的作業系統上找到這些鍵碼的完整列表。

$ xmodmap -pke
keycode   9 = Escape NoSymbol Escape
keycode  10 = ampersand 1 ampersand 1 dead_caron dead_ogonek dead_caron dead_ogonek
keycode  11 = eacute 2 eacute 2 asciitilde Eacute asciitilde Eacute
[...]
keycode 244 = XF86Battery NoSymbol XF86Battery
keycode 245 = XF86Bluetooth NoSymbol XF86Bluetooth
keycode 246 = XF86WLAN NoSymbol XF86WLAN
keycode 247 =

以及所有修飾符值的列表:

$ xmodmap
xmodmap:  up to 4 keys per modifier, (keycodes in parentheses):

shift       Shift_L (0x32),  Shift_R (0x3e)
lock        Caps_Lock (0x42)
control     Control_L (0x25),  Control_R (0x69)
mod1        Alt_L (0x40),  Meta_L (0xcd)
mod2        Num_Lock (0x4d)
mod3      
mod4        Super_L (0x85),  Super_R (0x86),  Super_L (0xce),  Hyper_L (0xcf)
mod5        ISO_Level3_Shift (0x5c),  Mode_switch (0xcb)

terminfo數據庫中有一些原始資訊,或者在ncurses API 中更完善,以幫助系統開發人員克服這種混亂。

如果您可以重用現有的原始碼,例如nano 的原始碼,它應該可以為您節省大量時間。看看“get_escape_seq_kbinput”函式,看看我的意思。

如果您只需要現代 linux 支持,那麼呼叫keyname可能就足夠了。

引用自:https://unix.stackexchange.com/questions/29425