mirror of
				https://gitlab.freedesktop.org/wayland/wayland.git
				synced 2025-11-03 09:01:42 -05:00 
			
		
		
		
	terminal: Special keys
Implements support for function, cursor, and editing keys, with modifiers. Partially implements application keypad mode. Expands control key support. Signed-off-by: Callum Lowcay <callum@callumscode.com>
This commit is contained in:
		
							parent
							
								
									256e72f0e2
								
							
						
					
					
						commit
						7e08e90c74
					
				
					 1 changed files with 174 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -63,6 +63,8 @@ static int option_fullscreen;
 | 
			
		|||
#define MODE_AUTOREPEAT		0x00000008
 | 
			
		||||
#define MODE_LF_NEWLINE		0x00000010
 | 
			
		||||
#define MODE_IRM		0x00000020
 | 
			
		||||
#define MODE_DELETE_SENDS_DEL	0x00000040
 | 
			
		||||
#define MODE_ALT_SENDS_ESC	0x00000080
 | 
			
		||||
 | 
			
		||||
union utf8_char {
 | 
			
		||||
	unsigned char byte[4];
 | 
			
		||||
| 
						 | 
				
			
			@ -229,6 +231,87 @@ apply_char_set(character_set cs, union utf8_char *utf8)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct key_map {
 | 
			
		||||
	int sym;
 | 
			
		||||
	int num;
 | 
			
		||||
	char escape;
 | 
			
		||||
	char code;
 | 
			
		||||
};
 | 
			
		||||
/* Set last key_sub sym to NULL */
 | 
			
		||||
typedef struct key_map *keyboard_mode;
 | 
			
		||||
 | 
			
		||||
static struct key_map KM_NORMAL[] = {
 | 
			
		||||
	{XK_Left,  1, '[', 'D'},
 | 
			
		||||
	{XK_Right, 1, '[', 'C'},
 | 
			
		||||
	{XK_Up,    1, '[', 'A'},
 | 
			
		||||
	{XK_Down,  1, '[', 'B'},
 | 
			
		||||
	{XK_Home,  1, '[', 'H'},
 | 
			
		||||
	{XK_End,   1, '[', 'F'},
 | 
			
		||||
	{0, 0, 0, 0}
 | 
			
		||||
};
 | 
			
		||||
static struct key_map KM_APPLICATION[] = {
 | 
			
		||||
	{XK_Left,          1, 'O', 'D'},
 | 
			
		||||
	{XK_Right,         1, 'O', 'C'},
 | 
			
		||||
	{XK_Up,            1, 'O', 'A'},
 | 
			
		||||
	{XK_Down,          1, 'O', 'B'},
 | 
			
		||||
	{XK_Home,          1, 'O', 'H'},
 | 
			
		||||
	{XK_End,           1, 'O', 'F'},
 | 
			
		||||
	{XK_KP_Enter,      1, 'O', 'M'},
 | 
			
		||||
	{XK_KP_Multiply,   1, 'O', 'j'},
 | 
			
		||||
	{XK_KP_Add,        1, 'O', 'k'},
 | 
			
		||||
	{XK_KP_Separator,  1, 'O', 'l'},
 | 
			
		||||
	{XK_KP_Subtract,   1, 'O', 'm'},
 | 
			
		||||
	{XK_KP_Divide,     1, 'O', 'o'},
 | 
			
		||||
	{0, 0, 0, 0}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
function_key_response(char escape, int num, uint32_t modifiers,
 | 
			
		||||
		      char code, char *response)
 | 
			
		||||
{
 | 
			
		||||
	int mod_num = 0;
 | 
			
		||||
	int len;
 | 
			
		||||
 | 
			
		||||
	if (modifiers & WINDOW_MODIFIER_SHIFT) mod_num   |= 1;
 | 
			
		||||
	if (modifiers & WINDOW_MODIFIER_ALT) mod_num     |= 2;
 | 
			
		||||
	if (modifiers & WINDOW_MODIFIER_CONTROL) mod_num |= 4;
 | 
			
		||||
 | 
			
		||||
	if (mod_num != 0)
 | 
			
		||||
		len = snprintf(response, MAX_RESPONSE, "\e[%d;%d%c",
 | 
			
		||||
			       num, mod_num + 1, code);
 | 
			
		||||
	else if (code != '~')
 | 
			
		||||
		len = snprintf(response, MAX_RESPONSE, "\e%c%c",
 | 
			
		||||
			       escape, code);
 | 
			
		||||
	else
 | 
			
		||||
		len = snprintf(response, MAX_RESPONSE, "\e%c%d%c",
 | 
			
		||||
			       escape, num, code);
 | 
			
		||||
 | 
			
		||||
	if (len >= MAX_RESPONSE)	return MAX_RESPONSE - 1;
 | 
			
		||||
	else				return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* returns the number of bytes written into response,
 | 
			
		||||
 * which must have room for MAX_RESPONSE bytes */
 | 
			
		||||
static int
 | 
			
		||||
apply_key_map(keyboard_mode mode, int sym, uint32_t modifiers, char *response)
 | 
			
		||||
{
 | 
			
		||||
	struct key_map map;
 | 
			
		||||
	int len = 0;
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	
 | 
			
		||||
	while (mode[i].sym) {
 | 
			
		||||
		map = mode[i++];
 | 
			
		||||
		if (sym == map.sym) {
 | 
			
		||||
			len = function_key_response(map.escape, map.num,
 | 
			
		||||
						    modifiers, map.code,
 | 
			
		||||
						    response);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct terminal_color { double r, g, b, a; };
 | 
			
		||||
struct attr {
 | 
			
		||||
	unsigned char fg, bg;
 | 
			
		||||
| 
						 | 
				
			
			@ -267,6 +350,7 @@ struct terminal {
 | 
			
		|||
	int margin_top, margin_bottom;
 | 
			
		||||
	character_set cs, g0, g1;
 | 
			
		||||
	character_set saved_cs, saved_g0, saved_g1;
 | 
			
		||||
	keyboard_mode key_mode;
 | 
			
		||||
	int data_pitch, attr_pitch;  /* The width in bytes of a line */
 | 
			
		||||
	int width, height, start, row, column;
 | 
			
		||||
	int saved_row, saved_column;
 | 
			
		||||
| 
						 | 
				
			
			@ -309,6 +393,7 @@ terminal_init(struct terminal *terminal)
 | 
			
		|||
	terminal->origin_mode = 0;
 | 
			
		||||
	terminal->mode = MODE_SHOW_CURSOR |
 | 
			
		||||
			 MODE_AUTOREPEAT |
 | 
			
		||||
			 MODE_ALT_SENDS_ESC |
 | 
			
		||||
			 MODE_AUTOWRAP;
 | 
			
		||||
 | 
			
		||||
	terminal->row = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -317,6 +402,7 @@ terminal_init(struct terminal *terminal)
 | 
			
		|||
	terminal->g0 = CS_US;
 | 
			
		||||
	terminal->g1 = CS_US;
 | 
			
		||||
	terminal->cs = terminal->g0;
 | 
			
		||||
	terminal->key_mode = KM_NORMAL;
 | 
			
		||||
 | 
			
		||||
	terminal->saved_g0 = terminal->g0;
 | 
			
		||||
	terminal->saved_g1 = terminal->g1;
 | 
			
		||||
| 
						 | 
				
			
			@ -787,6 +873,10 @@ handle_term_parameter(struct terminal *terminal, int code, int sr)
 | 
			
		|||
 | 
			
		||||
	if (terminal->qmark_flag) {
 | 
			
		||||
		switch(code) {
 | 
			
		||||
		case 1:  /* DECCKM */
 | 
			
		||||
			if (sr)	terminal->key_mode = KM_APPLICATION;
 | 
			
		||||
			else	terminal->key_mode = KM_NORMAL;
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:  /* DECANM */
 | 
			
		||||
			/* No VT52 support yet */
 | 
			
		||||
			terminal->g0 = CS_US;
 | 
			
		||||
| 
						 | 
				
			
			@ -832,6 +922,14 @@ handle_term_parameter(struct terminal *terminal, int code, int sr)
 | 
			
		|||
			if (sr)	terminal->mode |=  MODE_SHOW_CURSOR;
 | 
			
		||||
			else	terminal->mode &= ~MODE_SHOW_CURSOR;
 | 
			
		||||
			break;
 | 
			
		||||
		case 1037:   /* deleteSendsDel */
 | 
			
		||||
			if (sr)	terminal->mode |=  MODE_DELETE_SENDS_DEL;
 | 
			
		||||
			else	terminal->mode &= ~MODE_DELETE_SENDS_DEL;
 | 
			
		||||
			break;
 | 
			
		||||
		case 1039:   /* altSendsEscape */
 | 
			
		||||
			if (sr)	terminal->mode |=  MODE_ALT_SENDS_ESC;
 | 
			
		||||
			else	terminal->mode &= ~MODE_ALT_SENDS_ESC;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			fprintf(stderr, "Unknown parameter: ?%d\n", code);
 | 
			
		||||
			break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1239,6 +1337,12 @@ handle_non_csi_escape(struct terminal *terminal, char code)
 | 
			
		|||
		terminal->g0 = terminal->saved_g0;
 | 
			
		||||
		terminal->g1 = terminal->saved_g1;
 | 
			
		||||
		break;
 | 
			
		||||
	case '=':    /* DECPAM */
 | 
			
		||||
		terminal->key_mode = KM_APPLICATION;
 | 
			
		||||
		break;
 | 
			
		||||
	case '>':    /* DECPNM */
 | 
			
		||||
		terminal->key_mode = KM_NORMAL;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		fprintf(stderr, "Unknown escape code: %c\n", code);
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1583,8 +1687,6 @@ key_handler(struct window *window, uint32_t key, uint32_t sym,
 | 
			
		|||
		window_schedule_redraw(terminal->window);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case XK_Delete:
 | 
			
		||||
		sym = 0x04;
 | 
			
		||||
	case XK_BackSpace:
 | 
			
		||||
	case XK_Tab:
 | 
			
		||||
	case XK_Linefeed:
 | 
			
		||||
| 
						 | 
				
			
			@ -1613,11 +1715,78 @@ key_handler(struct window *window, uint32_t key, uint32_t sym,
 | 
			
		|||
	case XK_Alt_R:
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case XK_Insert:
 | 
			
		||||
		len = function_key_response('[', 2, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_Delete:
 | 
			
		||||
		if (terminal->mode & MODE_DELETE_SENDS_DEL) {
 | 
			
		||||
			ch[len++] = '\x04';
 | 
			
		||||
		} else {
 | 
			
		||||
			len = function_key_response('[', 3, modifiers, '~', ch);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_Page_Up:
 | 
			
		||||
		len = function_key_response('[', 5, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_Page_Down:
 | 
			
		||||
		len = function_key_response('[', 6, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F1:
 | 
			
		||||
		len = function_key_response('O', 1, modifiers, 'P', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F2:
 | 
			
		||||
		len = function_key_response('O', 1, modifiers, 'Q', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F3:
 | 
			
		||||
		len = function_key_response('O', 1, modifiers, 'R', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F4:
 | 
			
		||||
		len = function_key_response('O', 1, modifiers, 'S', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F5:
 | 
			
		||||
		len = function_key_response('[', 15, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F6:
 | 
			
		||||
		len = function_key_response('[', 17, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F7:
 | 
			
		||||
		len = function_key_response('[', 18, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F8:
 | 
			
		||||
		len = function_key_response('[', 19, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F9:
 | 
			
		||||
		len = function_key_response('[', 20, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F10:
 | 
			
		||||
		len = function_key_response('[', 21, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	case XK_F12:
 | 
			
		||||
		len = function_key_response('[', 24, modifiers, '~', ch);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		if (modifiers & WINDOW_MODIFIER_CONTROL)
 | 
			
		||||
			sym = sym & 0x1f;
 | 
			
		||||
		else if (modifiers & WINDOW_MODIFIER_ALT)
 | 
			
		||||
		/* Handle special keys with alternate mappings */
 | 
			
		||||
		len = apply_key_map(terminal->key_mode, sym, modifiers, ch);
 | 
			
		||||
		if (len != 0) break;
 | 
			
		||||
		
 | 
			
		||||
		if (modifiers & WINDOW_MODIFIER_CONTROL) {
 | 
			
		||||
			if (sym >= '3' && sym <= '7')
 | 
			
		||||
				sym = (sym & 0x1f) + 8;
 | 
			
		||||
 | 
			
		||||
			if (!((sym >= '!' && sym <= '/') ||
 | 
			
		||||
				(sym >= '8' && sym <= '?') ||
 | 
			
		||||
				(sym >= '0' && sym <= '2'))) sym = sym & 0x1f;
 | 
			
		||||
			else if (sym == '2') sym = 0x00;
 | 
			
		||||
			else if (sym == '/') sym = 0x1F;
 | 
			
		||||
			else if (sym == '8' || sym == '?') sym = 0x7F;
 | 
			
		||||
		} else if ((terminal->mode & MODE_ALT_SENDS_ESC) && 
 | 
			
		||||
			(modifiers & WINDOW_MODIFIER_ALT))
 | 
			
		||||
		{
 | 
			
		||||
			ch[len++] = 0x1b;
 | 
			
		||||
		} else if (modifiers & WINDOW_MODIFIER_ALT) {
 | 
			
		||||
			sym = sym | 0x80;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (sym < 256)
 | 
			
		||||
			ch[len++] = sym;
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue