Пример #1
0
static void console_buffer_add_string(char *buf, size_t *bytes_read, size_t *count, char *str, size_t size)
{
	while (*count > 0 && size > 0)
	{
		buf[(*bytes_read)++] = *str;
		(*count)--;
		str++;
		size--;
	}
	if (size > 0)
		console_add_input(str, size);
}
Пример #2
0
static size_t console_read(struct file *f, char *buf, size_t count)
{
	struct console_file *console_file = (struct console_file *)f;

	console_lock();
	console_retrieve_state();

	size_t bytes_read = 0;
	while (console->input_buffer_head != console->input_buffer_tail && count > 0)
	{
		count--;
		buf[bytes_read++] = console->input_buffer[console->input_buffer_tail];
		console->input_buffer_tail = (console->input_buffer_tail + 1) % MAX_INPUT;
	}
	if (console->termios.c_lflag & ICANON)
	{
		char line[MAX_CANON + 1]; /* One more for storing CR or LF */
		size_t len = 0;
		while (count > 0)
		{
			INPUT_RECORD ir;
			DWORD read;
			ReadConsoleInputA(console->in, &ir, 1, &read);
			if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown)
			{
				switch (ir.Event.KeyEvent.wVirtualKeyCode)
				{
				case VK_RETURN:
				{
					if (!(console->termios.c_iflag & IGNCR))
						line[len++] = console->termios.c_iflag & ICRNL ? '\n' : '\r';
					size_t r = min(count, len);
					memcpy(buf + bytes_read, line, r);
					bytes_read += r;
					count -= r;
					if (r < len)
					{
						/* Some bytes not fit, add to input buffer */
						console_add_input(line + r, len - r);
					}
					if (console->termios.c_lflag & ECHO)
						crnl();
					goto read_done;
				}

				case VK_BACK:
				{
					if (len > 0)
					{
						len--;
						if (console->termios.c_lflag & ECHO)
							backspace(TRUE);
					}
				}
				default:
				{
					char ch = ir.Event.KeyEvent.uChar.AsciiChar;
					if (ch >= 0x20)
					{
						if (len < MAX_CANON)
						{
							line[len++] = ch;
							if (console->termios.c_lflag & ECHO)
								write_normal(&ch, 1);
						}
					}
				}
				}
			}
		}
	}
	else /* Non canonical mode */
	{
		int vtime = console->termios.c_cc[VTIME];
		int vmin = console->termios.c_cc[VMIN];
		while (count > 0)
		{
			if (bytes_read > 0 && bytes_read >= vmin)
				break;
			/* If vmin > 0 and vtime == 0, it is a blocking read, otherwise we need to poll first */
			if (vtime > 0 || (vmin == 0 && vtime == 0))
			{
				if (WaitForSingleObject(console->in, vtime * 100) == WAIT_TIMEOUT)
					break;
			}
			INPUT_RECORD ir;
			DWORD read;
			ReadConsoleInputA(console->in, &ir, 1, &read);
			if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown)
			{
				switch (ir.Event.KeyEvent.wVirtualKeyCode)
				{
				case VK_UP:
					console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOA" : "\x1B[A", 3);
					break;

				case VK_DOWN:
					console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOB" : "\x1B[B", 3);
					break;

				case VK_RIGHT:
					console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOC" : "\x1B[C", 3);
					break;

				case VK_LEFT:
					console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOD" : "\x1B[D", 3);
					break;

				case VK_HOME:
					console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOH" : "\x1B[H", 3);
					break;

				case VK_END:
					console_buffer_add_string(buf, &bytes_read, &count, console->cursor_key_mode ? "\x1BOF" : "\x1B[F", 3);
					break;

				case VK_INSERT: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[2~", 4); break;
				case VK_DELETE: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[3~", 4); break;
				case VK_PRIOR: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[5~", 4); break;
				case VK_NEXT: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[6~", 4); break;

				case VK_F1: console_buffer_add_string(buf, &bytes_read, &count, "\x1BOP", 3); break;
				case VK_F2: console_buffer_add_string(buf, &bytes_read, &count, "\x1BOQ", 3); break;
				case VK_F3: console_buffer_add_string(buf, &bytes_read, &count, "\x1BOR", 3); break;
				case VK_F4: console_buffer_add_string(buf, &bytes_read, &count, "\x1BOS", 3); break;
				case VK_F5: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[15~", 5); break;
				case VK_F6: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[17~", 5); break;
				case VK_F7: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[18~", 5); break;
				case VK_F8: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[19~", 5); break;
				case VK_F9: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[20~", 5); break;
				case VK_F10: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[21~", 5); break;
				case VK_F11: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[23~", 5); break;
				case VK_F12: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[24~", 5); break;
				case VK_F13: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[25~", 5); break;
				case VK_F14: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[26~", 5); break;
				case VK_F15: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[28~", 5); break;
				case VK_F16: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[29~", 5); break;
				case VK_F17: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[31~", 5); break;
				case VK_F18: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[32~", 5); break;
				case VK_F19: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[33~", 5); break;
				case VK_F20: console_buffer_add_string(buf, &bytes_read, &count, "\x1B[34~", 5); break;

				default:
				{
					char ch = ir.Event.KeyEvent.uChar.AsciiChar;
					if (ch == '\r' && console->termios.c_iflag & IGNCR)
						break;
					if (ch == '\r' && console->termios.c_iflag & ICRNL)
						ch = '\n';
					else if (ch == '\n' && console->termios.c_iflag & ICRNL)
						ch = '\r';
					if (ch > 0)
					{
						count--;
						buf[bytes_read++] = ch;
						if (console->termios.c_lflag & ECHO)
							write_normal(&ch, 1);
					}
				}
				}
			}
			else
			{
				/* TODO: Other types of input */
			}
		}
	}
read_done:
	/* This will make the caret immediately visible */
	set_pos(console->x, console->y);
	console_unlock();
	return bytes_read;
}
Пример #3
0
/* Handler for control sequencie introducer, "ESC [" */
static void control_escape_csi(char ch)
{
	switch (ch)
	{
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		console->params[console->param_count] = 10 * console->params[console->param_count] + (ch - '0');
		break;

	case ';':
		if (console->param_count + 1 == CONSOLE_MAX_PARAMS)
			log_error("Too many console parameters.\n");
		else
			console->param_count++;
		break;

	case 'A': /* CUU */
		move_up(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case 'B': /* CUD */
	case 'e': /* VPR */
		move_down(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case 'C': /* CUF */
	case 'a': /* HPR */
		move_right(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case 'D': /* CUB */
		move_left(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case 'd': /* VPA */
	{
		int y = console->params[0]? console->params[0]: 1;
		if (y > console->height)
			y = console->height;
		set_pos(console->x, y - 1);
		console->processor = NULL;
		break;
	}

	case 'G': /* CHA */
	case '`': /* HPA */
	{
		int x = console->params[0] ? console->params[0] : 1;
		if (x > console->width)
			x = console->width;
		set_pos(x - 1, console->y);
		console->processor = NULL;
		break;
	}

	case 'H':
	case 'f':
		/* Zero or one both represents the first row/column */
		if (console->params[0] > 0)
			console->params[0]--;
		if (console->params[1] > 0)
			console->params[1]--;
		if (console->origin_mode)
			set_pos(console->params[1], console->scroll_top + console->params[0]);
		else
			set_pos(console->params[1], console->params[0]);
		console->processor = NULL;
		break;

	case 'h':
		if (console->csi_prefix == '?')
			for (int i = 0; i <= console->param_count; i++)
				change_private_mode(console->params[i], 1);
		else
			for (int i = 0; i <= console->param_count; i++)
				change_mode(console->params[i], 1);
		console->processor = NULL;
		break;

	case 'J':
		erase_screen(console->params[0]);
		console->processor = NULL;
		break;

	case 'K':
		erase_line(console->params[0]);
		console->processor = NULL;
		break;

	case 'l':
		if (console->csi_prefix == '?')
			for (int i = 0; i <= console->param_count; i++)
				change_private_mode(console->params[i], 0);
		else
			for (int i = 0; i <= console->param_count; i++)
				change_mode(console->params[i], 0);
		console->processor = NULL;
		break;

	case 'L': /* IL */
		insert_line(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case 'M': /* DL */
		delete_line(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case '@': /* ICH */
		insert_character(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case 'P': /* DCH */
		delete_character(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case 'c':
		if (console->csi_prefix == '>') /* DA2 */
		{
			if (console->params[0] == 0)
				console_add_input("\x1B[>61;95;0c", 11);
			else
				log_warning("DA2 parameter is not zero.\n");
		}
		else /* DA1 */
		{
			if (console->params[0] == 0)
				log_error("DA1 not supported.\n");
			else
				log_warning("DA1 parameter is not zero.\n");
		}
		console->processor = NULL;
		break;

	case 'm':
		for (int i = 0; i <= console->param_count; i++)
		{
			switch (console->params[i])
			{
			case 0: /* Reset */
				console->bright = 0;
				console->reverse = 0;
				console->foreground = 7;
				console->background = 0;
				break;

			case 1:
				console->bright = 1;
				break;

			case 2:
				console->bright = 0;
				break;

			case 7:
				console->reverse = 1;
				break;

			case 27:
				console->reverse = 0;
				break;

			case 30:
			case 31:
			case 32:
			case 33:
			case 34:
			case 35:
			case 36:
			case 37:
				console->foreground = console->params[i] - 30;
				break;

			case 40:
			case 41:
			case 42:
			case 43:
			case 44:
			case 45:
			case 46:
			case 47:
				console->background = console->params[i] - 40;
				break;

			default:
				log_error("Unknown console attribute: %d\n", console->params[i]);
			}
		}
		/* Set updated text attribute */
		SetConsoleTextAttribute(console->out, get_text_attribute(console));
		console->processor = NULL;
		break;

	case 'r':
		if (console->params[0] == 0)
			console->params[0] = 1;
		if (console->params[1] == 0)
			console->params[1] = console->height;
		console->scroll_full_screen = (console->params[0] == 1 && console->params[1] == console->height);
		console->scroll_top = console->params[0] - 1;
		console->scroll_bottom = console->params[1] - 1;
		set_pos(0, 0);
		console->processor = NULL;
		break;

	case 'S': /* SU */
		scroll_up(console->params[0]? console->params[0]: 1);
		console->processor = NULL;
		break;

	case '?':
		console->csi_prefix = '?';
		break;

	case '>':
		console->csi_prefix = '?';
		break;

	default:
		log_error("control_escape_csi(): Unhandled character %c\n", ch);
		console->processor = NULL;
	}
}