Reputation: 8735
How to get Ctrl, Shift or Alt with getch()
ncurses ?
Do I miss something in the man ?
Upvotes: 29
Views: 31790
Reputation: 141
I use a double getch() trick.
#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;
}
Now bgetch() :
// getch with block/unblock
int bgetch(int delay)
{
int t;
if ( delay != BLOCK )
blockunblockgetch(delay);
t=getch();
blockunblockgetch();
return t;
}
..and blockunblockgetch() :
// block, unblock getch
int blockunblockgetch(int delay)
{
wtimeout(win1, delay);
return ( delay == -1 ) ? 0 : 1;
}
What you have is simply a getch() that if ESC is detected, it blocks the next getch() for 10ms. If there is another char in the stream, it will return that char (in int) with altpressed (a global variable) set to 1. You can then utilize the alt+key checking altpressed. SHIFT and CTRL are easier to detect, they are recognized as single ints with NCURSES.
Upvotes: 3
Reputation: 1
I know this is old, but for anyone still looking... You CAN do this on Windows (At least on my version). Simply interpret getch as bytes-like integer then as a string.
str(getchvariablehere)
For example, Ctrl+A is 1 on my keyboard. Its a bit tedious, but you can check any combo with this method.
My wording may be off, but this method seems to work with raster fonts that can't display bytes as arbitrary unicode.
Upvotes: -1
Reputation: 54475
Agreeing (partly) with @leonerd, ncurses will only give you those keys as they are used as modifiers to other keys (ignoring the ASCII escape character which some people confuse with the Alt key). Some specific devices can be told to give this information (e.g., Linux console as documented in console_ioctl(4)), but that's not a problem that ncurses will solve for you.
Refer to the ncurses FAQ How can I use shift- or control-modifiers? for a long answer.
But short: ncurses doesn't tell you if a given modifier was used (except for special cases where there were well-known uses of shift), but rather its terminal descriptions provide the information either by
There are two approaches because the first uses an array of no more than 60 function keys (good enough for shift- and control-combinations), while the other just uses user-defined names).
All of these modified keys give multiple bytes; an application using keypad()
(of course) in ncurses would get a single number. In the latter case, the keycodes are determined at runtime.
That applies mainly to the special keys (function-, editing- and cursor-keys). For regular keys, one might assume that keyname
gives some special behavior, but reading the description it does not:
iscntrl
macro), andxterm
, of the terminals you are likely to use), andOf terminals... all have the modifier information available internally, but terminals generally do not have a way to pass this information to applications. xterm
can do this using the modifyOtherKeys
resource,
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.
which corresponds to a control sequence, seen in XTerm Control Sequences:
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.
but (being an xterm-specific feature), there's no reason to use it in ncurses: it would needlessly complicate getch
.
Upvotes: 6
Reputation: 448
At least for the control modifier there is a simple solution. Curses had been derived from vi source code, in which you find the following (see https://github.com/n-t-roff/ex-1.1/blob/master/ex.h line 77 and https://github.com/n-t-roff/ex-1.1/blob/master/ex_vops.c line 445):
#ifndef CTRL
#define CTRL(c) ((c) & 037)
#endif
switch(getch()) {
case CTRL('r'):
/* key ctrl-r (i.e. ^R) pressed */
Dependend on used includes CTRL
may or may not already been defined in your code.
Upvotes: 13
Reputation: 7897
Amazing how sometimes the right answer gets demoted, and answers that "authoritatively" give up get promoted... With a bit of creativity, key_name actually holds the right key to figuring this out, with one caveat - that SHIFT/ALT/CTRL are pressed with other keys at the same time:
First, for "normal keys" such as the printable ones, you can easily detect shift because it uppercases.
For special keys, e.g. KEY_LEFT, you will see that the code generated when SHIFT is selected is actually KEY_SLEFT. ditto for KEY_RIGHT. Unfortunately, no such luck for KEY_UP/KEY_DOWN , which seem unfazed by SHIFT. So you can distinguish by the returned char from getch() - the KEY_S.. implies shift was pressed.
For ALT (what's not trapped by X or the Aqua Windowmanager, at least), keyname will convert the key to an M... something.
For CTRL you'll get a "^" preceding the actual key name. E.g ^R for key 18
So you can now figure out the key codes for your switch(getch) statements, etc, by a simple snippet:
ch = getch(); endwin(); printf("KEY NAME : %s - %d\n", keyname(ch),ch);
and that's that. Think before definitively saying "can't". Maybe there's a way that's less obvious.
Upvotes: 30
Reputation: 8532
(To roughly copy my answer from How to get Shift+X / Alt+X keys in Curses ?)
Long story short - you cannot. The modifier keys are just that - modifiers. They do not exist in their own right, they modify some other (printing) key that you might press.
That said, if you are feeling especially brave, you can try my libtermkey which will at least correctly parse things like Ctrl-arrow.
Finally if you're feeling even braver you can run the terminal I wrote, pangoterm, which has generic ways to encode any arbitrarily modified Unicode keys, so it can distinguish Ctrl-m from Enter, Ctrl-Shift-a from Ctrl-a, etc...
However, outside of these, the answer remains "you cannot".
Upvotes: 7
Reputation:
You can call key_name( c )
to turn the key generated from getch()
into something that shows you the state of the ctrl-modifier.
For example this code shows "^R" if you press ctrl-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();
}
Upvotes: 2