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

📄 key.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Keyboard support routines.

   Copyright (C) 1994,1995 the Free Software Foundation.

   Written by: 1994, 1995 Miguel de Icaza.
               1994, 1995 Janne Kukonlehto.
	       1995  Jakub Jelinek.
	       1997  Norbert Warmuth

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif
#include <sys/types.h>		/* FD_ZERO et al */
#ifndef SCO_FLAVOR
	/* alex: sys/select.h defines struct timeval */
#	include <sys/time.h>		/* struct timeval */
#endif /* SCO_FLAVOR */
#if HAVE_SYS_SELECT_H
#   include <sys/select.h>
#endif
#include "tty.h"
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include "util.h"		/* For xmalloc prototype */
#include "mad.h"		/* The memory debugger */
#include "global.h"
#include "mouse.h"
#include "key.h"
#include "main.h"
#include "file.h"
#include "win.h"
#include "cons.saver.h"
#include "../vfs/vfs.h"

#ifdef __linux__
#    if defined(__GLIBC__) && (__GLIBC__ < 2)
#        include <linux/termios.h>	/* This is needed for TIOCLINUX */
#    else
#        include <termios.h>
#    endif
#    include <sys/ioctl.h>
#endif

#include "x.h"

/* "$Id: key.c 15091 2005-05-07 21:24:31Z sedwards $" */

/* This macros were stolen from gpm 0.15 */
#define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
#define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
			 (t2.tv_usec-t1.tv_usec)/1000)

/* timeout for old_esc_mode in usec */
#define ESCMODE_TIMEOUT 1000000

int mou_auto_repeat = 100;
int double_click_speed = 250;
int old_esc_mode = 0;

int use_8th_bit_as_meta = 1;

#ifndef HAVE_X
typedef struct key_def {
    char ch;			/* Holds the matching char code */
    int code;			/* The code returned, valid if child == NULL */
    struct key_def *next;
    struct key_def *child;	/* sequence continuation */
    int action;			/* optional action to be done. Now used only
                                   to mark that we are just after the first
                                   Escape */
} key_def;

/* This holds all the key definitions */
static key_def *keys = 0;
#endif

static int input_fd;
static fd_set select_set;
static int disabled_channels = 0; /* Disable channels checking */
int xgetch_second (void);

#ifndef PORT_HAS_FILE_HANDLERS
/* File descriptor monitoring add/remove routines */
typedef struct SelectList {
    int fd;
    select_fn callback;
    void *info;
    struct SelectList *next;
} SelectList;

SelectList *select_list = 0;

void add_select_channel (int fd, select_fn callback, void *info)
{
    SelectList *new;

    new = xmalloc (sizeof (SelectList), "add_select_channel");
    new->fd = fd;
    new->callback = callback;
    new->info = info;
    new->next = select_list;
    select_list = new;
}

void delete_select_channel (int fd)
{
    SelectList *p = select_list;
    SelectList *prev = 0;

    while (p){
	if (p->fd == fd){
	    if (prev)
		prev->next = p->next;
	    else
		select_list = p->next;
	    free (p);
	}
	prev = p;
	p = p->next;
    }
}

inline static int add_selects (fd_set *select_set)
{
    SelectList *p;
    int        top_fd = 0;

    if (disabled_channels)
	return 0;

    for (p = select_list; p; p = p->next){
	FD_SET (p->fd, select_set);
	if (p->fd > top_fd)
	    top_fd = p->fd;
    }
    return top_fd;
}

static void check_selects (fd_set *select_set)
{
    SelectList *p;

    if (disabled_channels)
	return;

    for (p = select_list; p; p = p->next)
	if (FD_ISSET (p->fd, select_set))
	    (*p->callback)(p->fd, p->info);
}
#endif

void channels_down (void)
{
    disabled_channels ++;
}

void channels_up (void)
{
    if (!disabled_channels)
	fprintf (stderr,
		 "Error: channels_up called with disabled_channels = 0\n");
    disabled_channels--;
}

typedef struct {
    int code;
    char *seq;
    int action;
} key_define_t;

#ifndef HAVE_X
key_define_t mc_bindings [] = {
    { KEY_END,    ESC_STR ">", MCKEY_NOACTION },
    { KEY_HOME,   ESC_STR "<", MCKEY_NOACTION },

#ifdef linux
    /* Incredible, but many Linuxes still have old databases */
    { KEY_IC,     ESC_STR "[2~", MCKEY_NOACTION },
#endif
    { 0, 0, MCKEY_NOACTION },
};

/* Broken terminfo and termcap databases on xterminals */
key_define_t xterm_key_defines [] = {
    { KEY_F(1),   ESC_STR "OP",   MCKEY_NOACTION },
    { KEY_F(2),   ESC_STR "OQ",   MCKEY_NOACTION },
    { KEY_F(3),   ESC_STR "OR",   MCKEY_NOACTION },
    { KEY_F(4),   ESC_STR "OS",   MCKEY_NOACTION },
    { KEY_F(1),   ESC_STR "[11~", MCKEY_NOACTION },
    { KEY_F(2),   ESC_STR "[12~", MCKEY_NOACTION },
    { KEY_F(3),   ESC_STR "[13~", MCKEY_NOACTION },
    { KEY_F(4),   ESC_STR "[14~", MCKEY_NOACTION },
    { KEY_F(5),   ESC_STR "[15~", MCKEY_NOACTION },
    { KEY_F(6),   ESC_STR "[17~", MCKEY_NOACTION },
    { KEY_F(7),   ESC_STR "[18~", MCKEY_NOACTION },
    { KEY_F(8),   ESC_STR "[19~", MCKEY_NOACTION },
    { KEY_F(9),   ESC_STR "[20~", MCKEY_NOACTION },
    { KEY_F(10),  ESC_STR "[21~", MCKEY_NOACTION },
    { 0, 0, MCKEY_NOACTION },
};

key_define_t mc_default_keys [] = {
    { ESC_CHAR,	ESC_STR, MCKEY_ESCAPE },
    { ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION },
    { 0, 0, MCKEY_NOACTION },
};
#endif

void define_sequences (key_define_t *kd)
{
#ifndef HAVE_X
    int i;

    for (i = 0; kd [i].code; i++)
	define_sequence(kd [i].code, kd [i].seq, kd [i].action);
#endif
}

/* This has to be called before slang_init or whatever routine
   calls any define_sequence */
void init_key (void)
{
#ifndef HAVE_X
    char *term = (char *) getenv ("TERM");

    /* This has to be the first define_sequence */
    /* So, we can assume that the first keys member has ESC */
    define_sequences (mc_default_keys);

    /* Terminfo on irix does not have some keys */
    if ((!strncmp (term, "iris-ansi", 9)) || (!strncmp (term, "xterm", 5)))
	define_sequences (xterm_key_defines);

    define_sequences (mc_bindings);

    /* load some additional keys (e.g. direct Alt-? support) */
    load_xtra_key_defines();

#ifdef __QNX__
    if (strncmp(term, "qnx", 3) == 0){
	/* Modify the default value of use_8th_bit_as_meta: we would
	 * like to provide a working mc for a newbie who knows nothing
	 * about [Options|Display bits|Full 8 bits input]...
	 *
	 * Don't use 'meta'-bit, when we are dealing with a
	 * 'qnx*'-type terminal: clear the default value!
	 * These terminal types use 0xFF as an escape character,
	 * so use_8th_bit_as_meta==1 must not be enabled!
	 *
	 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
	 * is not used now (doesn't even depend on use_8th_bit_as_meta
	 * as in mc-3.1.2)...GREAT!...no additional code is required!]
	 */
	use_8th_bit_as_meta = 0;
    }
#endif /* __QNX__ */
#endif /* !HAVE_X */
}

/* This has to be called after SLang_init_tty/slint_init */
void init_key_input_fd (void)
{
#ifndef HAVE_X
#ifdef HAVE_SLANG
    input_fd = SLang_TT_Read_FD;
#endif
#endif /* !HAVE_X */
}


#ifndef HAVE_X
void xmouse_get_event (Gpm_Event *ev)
{
    int btn;
    static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
    static struct timeval tv2;
    static int clicks;

    /* Decode Xterm mouse information to a GPM style event */

    /* Variable btn has following meaning: */
    /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
    btn = xgetch () - 32;

    /* There seems to be no way of knowing which button was released */
    /* So we assume all the buttons were released */

    if (btn == 3){
        ev->type = GPM_UP | (GPM_SINGLE << clicks);
        ev->buttons = 0;
	GET_TIME (tv1);
	clicks = 0;
    } else {
        ev->type = GPM_DOWN;
	GET_TIME (tv2);
	if (tv1.tv_sec && (DIF_TIME (tv1,tv2) < double_click_speed)){
	    clicks++;
	    clicks %= 3;
	} else
	    clicks = 0;

        switch (btn) {
	case 0:
            ev->buttons = GPM_B_LEFT;
            break;
	case 1:
            ev->buttons = GPM_B_MIDDLE;
            break;
	case 2:
            ev->buttons = GPM_B_RIGHT;
            break;
	default:
            /* Nothing */
            break;
        }
    }
    /* Coordinates are 33-based */
    /* Transform them to 1-based */
    ev->x = xgetch () - 32;
    ev->y = xgetch () - 32;
}

static key_def *create_sequence (char *seq, int code, int action)
{
    key_def *base, *p, *attach;

    for (base = attach = NULL; *seq; seq++){
	p = xmalloc (sizeof (key_def), "create_sequence");
	if (!base) base = p;
	if (attach) attach->child = p;

	p->ch   = *seq;
	p->code = code;
	p->child = p->next = NULL;
	if (!seq[1])
	    p->action = action;
	else
	    p->action = MCKEY_NOACTION;
	attach = p;
    }
    return base;
}

/* The maximum sequence length (32 + null terminator) */
static int seq_buffer [33];
static int *seq_append = 0;

static int push_char (int c)
{
    if (!seq_append)
	seq_append = seq_buffer;

    if (seq_append == &(seq_buffer [sizeof (seq_buffer)-2]))
	return 0;
    *(seq_append++) = c;
    *seq_append = 0;
    return 1;
}
#endif /* !HAVE_X */

void define_sequence (int code, char *seq, int action)
{
#ifndef HAVE_X
    key_def *base;

    if (strlen (seq) > sizeof (seq_buffer)-1)
	return;

    for (base = keys; (base != 0) && *seq; ){
	if (*seq == base->ch){
	    if (base->child == 0){
		if (*(seq+1)){
		    base->child = create_sequence (seq+1, code, action);
		    return;
		} else {
		    /* The sequence clashes */
		    return;
		}
	    } else {
		base = base->child;
		seq++;
	    }
	} else {
	    if (base->next)
		base = base->next;
	    else {
		base->next = create_sequence (seq, code, action);
		return;
	    }
	}
    }
    keys = create_sequence (seq, code, action);
#endif
}

#ifndef HAVE_X
static int *pending_keys;
#endif

int correct_key_code (int c)
{
    /* This is needed on some OS that do not support ncurses and */
    /* do some magic after read()ing the data */
    if (c == '\r')
	return '\n';

#ifdef IS_AIX
    if (c == KEY_SCANCEL)
	return '\t';
#endif

    if (c == KEY_F(0))
	return KEY_F(10);

    if (!alternate_plus_minus)
        switch (c) {
            case KEY_KP_ADD: c = '+'; break;
            case KEY_KP_SUBTRACT: c = '-'; break;
            case KEY_KP_MULTIPLY: c = '*'; break;
        }

    return c;
}

int get_key_code (int no_delay)
{
#ifndef HAVE_X
    int c;
    static key_def *this = NULL, *parent;
    static struct timeval esctime = { -1, -1 };
    static int lastnodelay = -1;

    if (no_delay != lastnodelay) {
        this = NULL;
        lastnodelay = no_delay;
    }

 pend_send:
    if (pending_keys){
	int d = *pending_keys++;
 check_pend:
	if (!*pending_keys){
	    pending_keys = 0;
	    seq_append = 0;
	}
	if (d == ESC_CHAR && pending_keys){
	    d = ALT(*pending_keys++);
	    goto check_pend;
	}
	if ((d & 0x80) && use_8th_bit_as_meta)
	    d = ALT(d & 0x7f);
	this = NULL;
	return correct_key_code (d);
    }

 nodelay_try_again:
    if (no_delay) {
#ifdef BUGGY_CURSES
        wtimeout(stdscr, 500);
#else
        nodelay (stdscr, TRUE);
#endif
    }
    c = xgetch ();
    if (no_delay) {
#ifdef BUGGY_CURSES
        notimeout (stdscr, TRUE);
#else
        nodelay (stdscr, FALSE);
#endif
        if (c == ERR) {
            if (this != NULL && parent != NULL &&
                parent->action == MCKEY_ESCAPE && old_esc_mode) {
                struct timeval current, timeout;

                if (esctime.tv_sec == -1)
                    return ERR;
                GET_TIME (current);
                timeout.tv_sec = ESCMODE_TIMEOUT / 1000000 + esctime.tv_sec;
                timeout.tv_usec = ESCMODE_TIMEOUT % 1000000 + esctime.tv_usec;
                if (timeout.tv_usec > 1000000) {
                    timeout.tv_usec -= 1000000;
                    timeout.tv_sec++;
                }
                if (current.tv_sec < timeout.tv_sec)
                    return ERR;
                if (current.tv_sec == timeout.tv_sec &&
                    current.tv_usec < timeout.tv_usec)
                    return ERR;
                this = NULL;
		pending_keys = seq_append = NULL;
		return ESC_CHAR;

⌨️ 快捷键说明

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