我无法通过使用 ncurses 中的 getch() 函数来获取 Ctrl、Shift 或 Alt。我是否在手册中漏掉了什么?
有时候正确答案会被贬低,而那些“权威”放弃的答案会被提升,真是令人惊奇……通过一点创意,key_name实际上拥有解决这个问题的正确钥匙,只有一个注意事项——要与其他键一起按SHIFT/ALT/CTRL:
首先,对于可打印字母之类的“普通键”,你可以很容易地检测到SHIFT,因为它会变成大写。
对于特殊键,例如KEY_LEFT,当选择SHIFT时生成的代码实际上是KEY_SLEFT。右侧的KEY_RIGHT也是如此。不幸的是,对于似乎不受SHIFT影响的KEY_UP / KEY_DOWN,没有这样的运气。所以您可以通过从getch()返回的字符区分它们——KEY_S..意味着按下了Shift。
对于ALT(至少没有被X或Aqua Windowmanager捕获的内容),keyname将键转换为M... something。
对于CTRL,实际键名之前会有“^”。例如,键18的名称是^R。
因此,您现在可以通过以下简单的片段确定switch(getch)语句等的键代码:
ch = getch(); endwin(); printf("KEY NAME : %s - %d\n", keyname(ch),ch);
就这样了。在下定论之前要三思而后行,不要轻易说“不行”。也许有一种不太明显的方法。
Shift+2
可以根据布局生成不同的字符。 - Adam SpiersKEY_SR
和KEY_SF
似乎分别来自SHIFT+UP和SHIFT+DOWN。 - schneiderfelipe至少对于控制修饰符,有一个简单的解决方案。Curses源代码派生自vi,其中你可以找到以下内容(请参见https://github.com/n-t-roff/ex-1.1/blob/master/ex.h第77行和https://github.com/n-t-roff/ex-1.1/blob/master/ex_vops.c第445行):
#ifndef CTRL
#define CTRL(c) ((c) & 037)
#endif
switch(getch()) {
case CTRL('r'):
/* key ctrl-r (i.e. ^R) pressed */
根据所使用的包含文件,CTRL
可能已经在您的代码中定义,也可能没有定义。
(大致上复制自如何在Curses中获取Shift+X / Alt+X键的内容?的答案)
简而言之 - 你不能。修饰键只是修饰键,它们本身并不存在,它们只是修改你可能按下的其他(打印)键。
话虽如此,如果你感觉特别勇敢,你可以尝试我的libtermkey,它至少可以正确解析像Ctrl-箭头这样的内容。
最后,如果你感觉更加勇敢,你可以运行我编写的终端pangoterm,它具有通用的方法来编码任意修改过的Unicode键,因此它可以区分Ctrl-m和Enter,Ctrl-Shift-a和Ctrl-a等...
然而,在这些范围之外,答案仍然是“你不能”。keypad()
函数时,应用程序将获得一个单一的数字。对于后一种情况,键码是在运行时确定的。keyname
提供了一些特殊行为,但阅读其说明并不是这样:
iscntrl
宏进行处理)。xterm
)。xterm
可以使用 modifyOtherKeys
资源进行传递。 modifyOtherKeys (class ModifyOtherKeys)
Like modifyCursorKeys, tells xterm to construct an escape
sequence for other keys (such as "2") when modified by
Control-, Alt- or Meta-modifiers. This feature does not apply
to function keys and well-defined keys such as ESC or the
control keys. The default is "0":
0 disables this feature.
1 enables this feature for keys except for those with well-
known behavior, e.g., Tab, Backarrow and some special
control character cases, e.g., Control-Space to make a
NUL.
2 enables this feature for keys including the exceptions
listed.
这对应于控制序列,可以在XTerm控制序列中看到:
CSI > Ps; Ps m
Set or reset resource-values used by xterm to decide whether
to construct escape sequences holding information about the
modifiers pressed with a given key. The first parameter iden-
tifies the resource to set/reset. The second parameter is the
value to assign to the resource. If the second parameter is
omitted, the resource is reset to its initial value.
Ps = 0 -> modifyKeyboard.
Ps = 1 -> modifyCursorKeys.
Ps = 2 -> modifyFunctionKeys.
Ps = 4 -> modifyOtherKeys.
但在ncurses中没有理由使用它,因为它是特定于xterm的功能,会使getch
变得不必要的复杂。
#define ESC 27
int altpressed;
int sgetch()
{
int t;
t=getch();
if ( t == ESC ) { // possible alt held down
t=bgetch(10);
if ( t == -1 ) // escape key pressed
return ESC;
altpressed=1;
}
return t;
}
现在是bgetch():
// getch with block/unblock
int bgetch(int delay)
{
int t;
if ( delay != BLOCK )
blockunblockgetch(delay);
t=getch();
blockunblockgetch();
return t;
}
...和block/unblock/getch():
// block, unblock getch
int blockunblockgetch(int delay)
{
wtimeout(win1, delay);
return ( delay == -1 ) ? 0 : 1;
}
您可以调用key_name(c)
将从getch()
生成的键转换为显示ctrl修饰符状态的内容。
例如,如果按下ctrl-r,则此代码显示"^R":
while( true )
{
char c = getch();
if ( ERR == c )
break;
const char *name = key_name( c );
move( 2, 2 );
clear();
printw( "You entered: %s ", name );
refresh();
}
getch
返回的是 chartype
,而不是 char
。 - yyny我知道这已经过时了,但对于仍在寻找的任何人... 你可以在Windows上做到这一点(至少在我的版本上)。 只需将getch解释为类似字节的整数,然后再转换为字符串即可。
str(getchvariablehere)
GetAsyncKeyState
),但这是与键盘一起工作,而不是像getch
一样处理输入。 - Seth Carnegie