📄 pgpkbunix.c
字号:
/*
* pgpKBUnix.c - Unix keyboard input routines.
*
* Copyright (C) 1996,1997 Network Associates Inc. and affiliated companies. All rights reserved.
*
* $Id: pgpKBUnix.c,v 1.3 1999/03/10 02:51:59 heller Exp $
*/
#if HAVE_CONFIG_H
#include "pgpConfig.h"
#endif
#include "pgpPubTypes.h"
/*
* Define NOTERMIO if you don't have the termios stuff
*/
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
/* How to get cbreak mode */
#if defined(NOTERMIO)
#include <sgtty.h> /* No termio: Use ioctl() TIOCGETP and TIOCSETP */
#elif defined(SVR2)
#include <termio.h> /* SVR2: Use ioctl() TCGETA and TCSETAF */
#else /* Usual case */
#include <termios.h> /* Posix: use tcgetattr/tcsetattr */
#endif
#ifdef sun /* including ioctl.h and termios.h gives a lot of warnings on sun */
#include <sys/filio.h>
#else
#include <sys/ioctl.h> /* for FIONREAD */
#endif /* sun */
#ifndef FIONREAD
#define FIONREAD TIOCINQ
#endif
#include "pgpPOSIX.h" /* For read(), sleep() */
#include "pgpKB.h"
#if UNITTEST /* Dummy out some functions for unit testing */
#define pgpRandPoolKeystroke(c) (void)c
#else
#include "pgpRandomPool.h"
#endif
#ifndef STDIN_FILENO
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#endif
/* The structure to hold the keyuboard's state */
#if defined(NOTERMIO)
static struct sgttyb kbState0, kbState1;
#ifndef CBREAK
#define CBREAK RAW
#endif
#define KB_GET_STATE(fd,s) ioctl(fd, TIOCGETP, s)
#define KB_ALTER_STATE(s) ((s)->sg_flags |= CBREAK, (s)->sg_flags &= ~ECHO)
#define KB_SET_STATE(fd,s) ioctl(fd, TIOCSETP, s)
#elif defined(SVR2)
static struct termio kbState0, kbState1;
#define KB_GET_STATE(fd,s) ioctl(fd, TCGETA, s)
#define KB_ALTER_STATE(s) \
((s)->c_cc[VMIN]=1, (s)->c_cc[VTIME]=0, (s)->c_lflag &= ~(ECHO|ICANON))
#define KB_SET_STATE(fd,s) ioctl(fd, TCSETA, s)
#else
static struct termios kbState0, kbState1;
#define KB_GET_STATE(fd,s) tcgetattr(fd, s)
#define KB_ALTER_STATE(s) ((s)->c_cc[VMIN]=1, (s)->c_cc[VTIME]=0, \
(s)->c_lflag &= ~(ECHO|ICANON))
#define KB_SET_STATE(fd,s) tcsetattr(fd, TCSAFLUSH, s)
#endif
static int kbStateFetched = 0;
/* The basic task of getting the terminal into CBREAK mode. */
static void
kbInternalCbreak(int fd)
{
if (!kbStateFetched) {
if (KB_GET_STATE(fd, &kbState0) < 0)
return; /* Trouble - what to do? */
kbState1 = kbState0;
KB_ALTER_STATE(&kbState1);
kbStateFetched = 1;
}
KB_SET_STATE(fd, &kbState1);
}
/* Restore the terminal to normal operation */
static void
kbInternalNorm(int fd)
{
if (kbStateFetched)
KB_SET_STATE(fd, &kbState0);
}
/* State variables */
static volatile int kbCbreakFlag = 0;
static int kbFd = -1;
#ifdef SVR2
static int (*savesig)(int);
#else
static void (*savesig)(int);
#endif
/* A wrapper around SIGINT and SIGCONT to restore the terminal modes. */
static void
kbSig1(int sig)
{
if (kbCbreakFlag)
kbInternalNorm(kbFd);
if (sig == SIGINT)
signal(sig, savesig);
else
signal(sig, SIG_DFL);
raise(sig); /* Re-send the signal */
}
static void
kbAddSigs(void);
/* Resume cbreak after SIGCONT */
static void
kbSig2(int sig)
{
(void)sig;
if (kbCbreakFlag)
kbInternalCbreak(kbFd);
else
kbAddSigs();
}
static void
kbAddSigs(void)
{
savesig = signal (SIGINT, kbSig1);
#ifdef SIGTSTP
signal (SIGCONT, kbSig2);
signal (SIGTSTP, kbSig1);
#endif
}
static void
kbRemoveSigs(void)
{
signal (SIGINT, savesig);
#ifdef SIGTSTP
signal (SIGCONT, SIG_DFL);
signal (SIGTSTP, SIG_DFL);
#endif
}
/* Now, at last, the externally callable functions */
int kbOpenKbd(int flags, int InBatchmode) {
int lkbFD = -1;
if(!InBatchmode) {
if((lkbFD = open("/dev/tty", flags)) < 0) {
lkbFD = STDIN_FILENO;
}
}
else {
lkbFD = STDIN_FILENO;
}
return(lkbFD);
}
int kbCloseKbd(int fd) {
int ReturnCode = 0;
if(fd != STDIN_FILENO) /*We don't actually want to close STDIN*/
ReturnCode = close(fd);
return(ReturnCode);
}
void
kbCbreak(int InBatchmode)
{
if(kbFd < 0) {
kbFd = kbOpenKbd(O_RDWR, InBatchmode);
}
if(!InBatchmode)
{
kbAddSigs();
kbCbreakFlag = 1;
kbInternalCbreak(kbFd);
}
}
void
kbNorm(void)
{
kbInternalNorm(kbFd);
kbCbreakFlag = 0;
kbRemoveSigs();
}
int
kbGet(void)
{
int i;
char c;
i = read(kbFd, &c, 1);
if (i < 1)
return -1;
PGPGlobalRandomPoolAddKeystroke(c);
return (unsigned char)c;
}
/*
* Flush any pending input. If "thorough" is set, tries to be more
* thorough about it. Ideally, wait for 1 second of quiet, but we
* may do something more primitive.
*
* kbCbreak() has the side effect of flushing the inout queue, so this
* is not too critical.
*/
void
kbFlush(int thorough)
{
if (thorough)
sleep(1);
#if defined(TCIFLUSH)
tcflush(kbFd, TCIFLUSH);
#elif defined(TIOCFLUSH)
#ifndef FREAD
#define FREAD 1 /* The usual value */
#endif
ioctl(kbFd, TIOCFLUSH, FREAD);
#endif
}
#if UNITTEST /* Self-contained test driver */
#include <ctype.h>
int
main(void)
{
int c;
puts("Going to cbreak mode...");
kbCbreak( 0 );
puts("In cbreak mode. Please type.");
for (;;) {
c = kbGet();
if (c == '\n' || c == '\r')
break;
printf("c = %d = '%c'\n", c, c);
kbFlush(isupper(c));
}
puts("Returning to normal mode...");
kbNorm();
puts("Done.");
return 0;
}
#endif /* UNITTEST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -