⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kbd.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Support for keyboard interface *//* $Id: kbd.c,v 1.112.6.7 2005/06/11 16:22:29 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdlib.h>#include <string.h>#ifdef HAVE_TERMIOS_H#include <termios.h>#endif#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef __hpux__#include <limits.h>#define HPUX_PIPE	(len > PIPE_BUF || errno != EAGAIN)#else#define HPUX_PIPE	1#endif#include "elinks.h"#include "config/options.h"#include "intl/gettext/libintl.h"#include "lowlevel/select.h"#include "osdep/ascii.h"#include "osdep/osdep.h"#include "terminal/hardio.h"#include "terminal/kbd.h"#include "terminal/mouse.h"#include "terminal/terminal.h"#include "util/error.h"#include "util/memory.h"#include "util/string.h"#define OUT_BUF_SIZE	16384#define IN_BUF_SIZE	16#define TW_BUTT_LEFT	1#define TW_BUTT_MIDDLE	2#define TW_BUTT_RIGHT	4struct itrm {	int std_in;	int std_out;	int sock_in;	int sock_out;	int ctl_in;	/* Input queue */	unsigned char kqueue[IN_BUF_SIZE];	int qlen;	/* Output queue */	unsigned char *ev_queue;	int eqlen;	int timer;			/* ESC timeout timer */	struct termios t;		/* For restoring original attributes */	void *mouse_h;			/* Mouse handle */	unsigned char *orig_title;	/* For restoring window title */	unsigned int blocked:1;		/* Whether it was blocked */	unsigned int altscreen:1;	/* Whether to use alternate screen */	unsigned int touched_title:1;	/* Whether the term title was changed */};static struct itrm *ditrm = NULL;static void free_trm(struct itrm *);static void in_kbd(struct itrm *);static void in_sock(struct itrm *);static int process_queue(struct itrm *);intis_blocked(void){	return ditrm && ditrm->blocked;}voidfree_all_itrms(void){	if (ditrm) free_trm(ditrm);}static voidwrite_ev_queue(struct itrm *itrm){	int written;	int qlen = int_min(itrm->eqlen, 128);	assertm(qlen, "event queue empty");	if_assert_failed return;	written = safe_write(itrm->sock_out, itrm->ev_queue, qlen);	if (written <= 0) {		if (written < 0) free_trm(itrm); /* write error */		return;	}	itrm->eqlen -= written;	if (itrm->eqlen == 0) {		set_handlers(itrm->sock_out,			     get_handler(itrm->sock_out, H_READ),			     NULL,			     get_handler(itrm->sock_out, H_ERROR),			     get_handler(itrm->sock_out, H_DATA));	} else {		assert(itrm->eqlen > 0);		memmove(itrm->ev_queue, itrm->ev_queue + written, itrm->eqlen);	}}static voidqueue_event(struct itrm *itrm, unsigned char *data, int len){	int w = 0;	if (!len) return;	if (!itrm->eqlen && can_write(itrm->sock_out)) {		w = safe_write(itrm->sock_out, data, len);		if (w <= 0 && HPUX_PIPE) {			/* free_trm(itrm); */			register_bottom_half((void (*)(void *)) free_trm, itrm);			return;		}	}	if (w < len) {		int left = len - w;		unsigned char *c = mem_realloc(itrm->ev_queue,					       itrm->eqlen + left);		if (!c) {			free_trm(itrm);			return;		}		itrm->ev_queue = c;		memcpy(itrm->ev_queue + itrm->eqlen, data + w, left);		itrm->eqlen += left;		set_handlers(itrm->sock_out,			     get_handler(itrm->sock_out, H_READ),			     (void (*)(void *)) write_ev_queue,			     (void (*)(void *)) free_trm, itrm);	}}voidkbd_ctrl_c(void){	struct term_event ev = INIT_TERM_EVENT(EVENT_KBD, KBD_CTRL_C, 0, 0);	if (!ditrm) return;	queue_event(ditrm, (unsigned char *) &ev, sizeof(ev));}#define write_sequence(fd, seq) \	hard_write(fd, seq, sizeof(seq) / sizeof(unsigned char) - 1)#define INIT_TERMINAL_SEQ	"\033)0\0337"	/* Special Character and Line Drawing Set, Save Cursor */#define INIT_TWIN_MOUSE_SEQ	"\033[?9h"	/* Send MIT Mouse Row & Column on Button Press */#define INIT_XWIN_MOUSE_SEQ	"\033[?1000h"	/* Send Mouse X & Y on button press and release */#define INIT_ALT_SCREEN_SEQ	"\033[?47h"	/* Use Alternate Screen Buffer */static voidsend_init_sequence(int h, int altscreen){	write_sequence(h, INIT_TERMINAL_SEQ);	/* If alternate screen is supported switch to it. */	if (altscreen) {		write_sequence(h, INIT_ALT_SCREEN_SEQ);	}#ifdef CONFIG_MOUSE	write_sequence(h, INIT_TWIN_MOUSE_SEQ);	write_sequence(h, INIT_XWIN_MOUSE_SEQ);#endif}#define DONE_CLS_SEQ		"\033[2J"	/* Erase in Display, Clear All */#define DONE_TERMINAL_SEQ	"\0338\r \b"	/* Restore Cursor (DECRC) + ??? */#define DONE_TWIN_MOUSE_SEQ	"\033[?9l"	/* Don't Send MIT Mouse Row & Column on Button Press */#define DONE_XWIN_MOUSE_SEQ	"\033[?1000l"	/* Don't Send Mouse X & Y on button press and release */#define DONE_ALT_SCREEN_SEQ	"\033[?47l"	/* Use Normal Screen Buffer */static voidsend_done_sequence(int h, int altscreen){	write_sequence(h, DONE_CLS_SEQ);#ifdef CONFIG_MOUSE	/* This is a hack to make xterm + alternate screen working,	 * if we send only DONE_XWIN_MOUSE_SEQ, mouse is not totally	 * released it seems, in rxvt and xterm... --Zas */	write_sequence(h, DONE_TWIN_MOUSE_SEQ);	write_sequence(h, DONE_XWIN_MOUSE_SEQ);#endif	/* Switch from alternate screen. */	if (altscreen) {		write_sequence(h, DONE_ALT_SCREEN_SEQ);	}	write_sequence(h, DONE_TERMINAL_SEQ);}#undef write_sequencevoidresize_terminal(void){	struct term_event ev = INIT_TERM_EVENT(EVENT_RESIZE, 0, 0, 0);	int width, height;	get_terminal_size(ditrm->std_out, &width, &height);	ev.info.size.width = width;	ev.info.size.height = height;	queue_event(ditrm, (char *) &ev, sizeof(ev));}static voidset_terminal_name(unsigned char name[MAX_TERM_LEN]){	unsigned char *term = getenv("TERM");	int i;	memset(name, 0, MAX_TERM_LEN);	if (!term) return;	for (i = 0; term[i] != 0 && i < MAX_TERM_LEN - 1; i++)		name[i] = isident(term[i]) ? term[i] : '-';}static intsetraw(int fd, struct termios *p){	struct termios t;	memset(&t, 0, sizeof(t));	if (tcgetattr(fd, &t)) return -1;	if (p) copy_struct(p, &t);	elinks_cfmakeraw(&t);	t.c_lflag |= ISIG;#ifdef TOSTOP	t.c_lflag |= TOSTOP;#endif	t.c_oflag |= OPOST;	if (tcsetattr(fd, TCSANOW, &t)) return -1;	return 0;}voidhandle_trm(int std_in, int std_out, int sock_in, int sock_out, int ctl_in,	   void *init_string, int init_len, int remote){	struct itrm *itrm;	struct terminal_info info;	struct term_event_size *size = &info.event.info.size;	unsigned char *ts;	memset(&info, 0, sizeof(info));	get_terminal_size(ctl_in, &size->width, &size->height);	info.event.ev = EVENT_INIT;	info.system_env = get_system_env();	info.length = init_len;	if (remote) {		info.session_info = remote;		info.magic = INTERLINK_REMOTE_MAGIC;	} else {		info.session_info = get_cmd_opt_int("base-session");		info.magic = INTERLINK_NORMAL_MAGIC;	}	itrm = mem_calloc(1, sizeof(*itrm));	if (!itrm) return;	ditrm = itrm;	itrm->std_in = std_in;	itrm->std_out = std_out;	itrm->sock_in = sock_in;	itrm->sock_out = sock_out;	itrm->ctl_in = ctl_in;	itrm->timer = -1;	/* FIXME: Combination altscreen + xwin does not work as it should,	 * mouse clicks are reportedly partially ignored. */	if (info.system_env & (ENV_SCREEN | ENV_XWIN))		itrm->altscreen = 1;	if (ctl_in >= 0) setraw(ctl_in, &itrm->t);	set_handlers(std_in, (void (*)(void *)) in_kbd,		     NULL, (void (*)(void *)) free_trm, itrm);	if (sock_in != std_out)		set_handlers(sock_in, (void (*)(void *)) in_sock,			     NULL, (void (*)(void *)) free_trm, itrm);	handle_terminal_resize(ctl_in, resize_terminal);	set_terminal_name(info.name);	ts = get_cwd();	if (ts) {		memcpy(info.cwd, ts, int_min(strlen(ts), MAX_CWD_LEN));		mem_free(ts);	}	queue_event(itrm, (char *) &info, TERMINAL_INFO_SIZE);	queue_event(itrm, (char *) init_string, init_len);	send_init_sequence(std_out, itrm->altscreen);	itrm->mouse_h = handle_mouse(0, (void (*)(void *, unsigned char *, int)) queue_event, itrm);}static voidunblock_itrm_x(void *h){	close_handle(h);	if (!ditrm) return;	unblock_itrm(0);	resize_terminal();}intunblock_itrm(int fd){	struct itrm *itrm = ditrm;	if (!itrm) return -1;	if (itrm->ctl_in >= 0 && setraw(itrm->ctl_in, NULL)) return -1;	itrm->blocked = 0;	send_init_sequence(itrm->std_out, itrm->altscreen);	set_handlers(itrm->std_in, (void (*)(void *)) in_kbd, NULL,		     (void (*)(void *)) free_trm, itrm);	resume_mouse(itrm->mouse_h);	handle_terminal_resize(itrm->ctl_in, resize_terminal);	unblock_stdin();	return 0;}voidblock_itrm(int fd){	struct itrm *itrm = ditrm;	if (!itrm) return;	itrm->blocked = 1;	block_stdin();	unhandle_terminal_resize(itrm->ctl_in);	send_done_sequence(itrm->std_out, itrm->altscreen);	tcsetattr(itrm->ctl_in, TCSANOW, &itrm->t);	set_handlers(itrm->std_in, NULL, NULL,		     (void (*)(void *)) free_trm, itrm);	suspend_mouse(itrm->mouse_h);}static voidfree_trm(struct itrm *itrm){	if (!itrm) return;	if (itrm->orig_title && *itrm->orig_title) {		set_window_title(itrm->orig_title);	} else if (itrm->touched_title) {		/* Set the window title to the value of $TERM if X11 wasn't		 * compiled in. Should hopefully make at least half the users		 * happy. (debian bug #312955) */		unsigned char title[MAX_TERM_LEN];		set_terminal_name(title);		if (*title)			set_window_title(title);	}	mem_free_set(&itrm->orig_title, NULL);	unhandle_terminal_resize(itrm->ctl_in);	unhandle_mouse(itrm->mouse_h);	send_done_sequence(itrm->std_out,itrm->altscreen);	tcsetattr(itrm->ctl_in, TCSANOW, &itrm->t);	clear_handlers(itrm->std_in);	clear_handlers(itrm->sock_in);	clear_handlers(itrm->std_out);	clear_handlers(itrm->sock_out);	if (itrm->timer != -1)		kill_timer(itrm->timer);	if (itrm == ditrm) ditrm = NULL;	mem_free_if(itrm->ev_queue);	mem_free(itrm);}/* Resize terminal to dimensions specified by @text string. * @text should look like "width,height,old-width,old-height" where width and * height are integers. */static inline voidresize_terminal_from_str(unsigned char *text){	enum { NEW_WIDTH = 0, NEW_HEIGHT, OLD_WIDTH, OLD_HEIGHT, NUMBERS } i;	int numbers[NUMBERS];	assert(text && *text);	if_assert_failed return;	for (i = 0; i < NUMBERS; i++) {		unsigned char *p = strchr(text, ',');		if (p) {			*p++ = '\0';		} else if (i < OLD_HEIGHT) {			return;		}		numbers[i] = atoi(text);		if (p) text = p;	}	resize_window(numbers[NEW_WIDTH], numbers[NEW_HEIGHT],		      numbers[OLD_WIDTH], numbers[OLD_HEIGHT]);	resize_terminal();}voiddispatch_special(unsigned char *text){	switch (text[0]) {		case TERM_FN_TITLE:			if (ditrm) {				if (!ditrm->orig_title)					ditrm->orig_title = get_window_title();				ditrm->touched_title = 1;			}			set_window_title(text + 1);			break;		case TERM_FN_RESIZE:			resize_terminal_from_str(text + 1);			break;	}}static void inlinesafe_hard_write(int fd, unsigned char *buf, int len){	if (is_blocked()) return;	want_draw();	hard_write(fd, buf, len);	done_draw();}static voidin_sock(struct itrm *itrm){	struct string path;	struct string delete;	char ch;	int fg;	int bytes_read, i, p;	unsigned char buf[OUT_BUF_SIZE];	bytes_read = safe_read(itrm->sock_in, buf, OUT_BUF_SIZE);	if (bytes_read <= 0) goto free_and_return;qwerty:	for (i = 0; i < bytes_read; i++)		if (!buf[i])			goto has_nul_byte;	safe_hard_write(itrm->std_out, buf, bytes_read);	return;has_nul_byte:	if (i) safe_hard_write(itrm->std_out, buf, i);	i++;	assert(OUT_BUF_SIZE - i > 0);	memmove(buf, buf + i, OUT_BUF_SIZE - i);	bytes_read -= i;	p = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -