📄 zhcon.cpp
字号:
// vi:ts=4:shiftwidth=4:expandtab/*************************************************************************** zhcon.cpp - description ------------------- begin : Fri Mar 23 2001 copyright : (C) 2001 by ejoy email : ejoy@users.sourceforge.net ***************************************************************************//*************************************************************************** * * * 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. * * * ***************************************************************************/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <iostream>#include <strstream>#include <unistd.h>#include <cstdlib>#include <cstdio>#include <sys/ioctl.h>#if defined(linux) #include <linux/limits.h> #include <linux/kd.h> #include <linux/vt.h> #include <pty.h>#elif defined(__FreeBSD__) #include <termios.h> //#include <machine/console.h> #include <sys/consio.h> #include <libutil.h> #define TCSETA TIOCSETA#endif#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <signal.h>#include <pwd.h>#include <stdexcept>#include <algorithm>#include <locale.h>#include "global.h"#include "console.h"#include "inputclient.h"#include "inputmanager.h"#include "nativeinputserver.h"#ifdef HAVE_UNICON_LIB #include "uniconinputserver.h"#endif// for termcap, must include after gpm.h, why?#include <term.h>#include "gbkdecoder.h"#include "gbdecoder.h"#include "big5decoder.h"#include "gb2big5decoder.h"#include "big52gbdecoder.h"#include "jisdecoder.h"#include "kscdecoder.h"#include "configfile.h"//#include "fade.h"#include "zhcon.h"#include "basefont.h"//#include "popwin.h"BaseFont* gpHzFont;BaseFont* gpAscFont;#ifndef NDEBUG#include "debug.h"ofstream debug("debug");#endifZhcon* Zhcon::mpZhcon = NULL;int Zhcon::mTtyPid = 0;Zhcon::STATE Zhcon::mState = STOP;char* Zhcon::mpTips[] = {gettext_noop("Please visit zhcon.gnuchina.org for more information."),gettext_noop("Zhcon supports GB2312,GBK,BIG5,JIS,KSC encode."),gettext_noop("You can use CTRL-ALT-0 to toggle prompt bar."),gettext_noop("Press CTRL-ALT-H for online help."),gettext_noop("Zhcon supports 12,14,16,24 pixel fonts,you can change in zhcon.conf"),gettext_noop("You can use 24 pixel font on 17 monitor to get better visual effect."),gettext_noop("Hit CTRL-D to quit zhcon."),gettext_noop("You can find user manual in doc/."),gettext_noop("Zhcon can use input methods from Unicon[TurboLinux],read manual for detail."),gettext_noop("Zhcon is optimized for running under Linux FrameBuffer."),gettext_noop("Start from version 0.2.1,zhcon support gpm mouse in console."),gettext_noop("Press CTRL-F7 to change input style")};void Zhcon::SignalVtLeave(int signo) { if(Zhcon::mpZhcon != NULL) mpZhcon->VtDoLeave();}void Zhcon::SignalVtEnter(int signo) { if(Zhcon::mpZhcon != NULL) mpZhcon->VtDoEnter();}Zhcon::Zhcon(int argc, char* argv[]):mpCon(NULL),mpInputManager(NULL),mShowTips(true),mArgc(argc),mArgv(argv){ Zhcon::mpZhcon = this; mConFd = mTtyFd = -1; random_shuffle(mpTips,mpTips + sizeof(mpTips)/sizeof(char*) );}Zhcon::~Zhcon() { CleanUp(); Zhcon::mpZhcon = NULL;}void Zhcon::Init() { //reading config file string cfgfile = getenv("HOME"); cfgfile += "/.zhconrc"; if (access(cfgfile.c_str(), R_OK) != 0) cfgfile = "/etc/zhcon.conf"; //for debug,a pause enable us to attach zhcon's pid in gdb //char c;cin>>c; ConfigFile f(cfgfile.c_str()); //the InitXXX sequence is important,do not change //unless you know what you are doing InitTty(); // set blank line height, must before init font InitGraphDev(f); GraphMode(); seteuid(getuid()); InitLocale(f); // include init font InitCon(f); InitMisc(f); VtSignalLeave(); InstallSignal(); ForkPty(); // if setlocale run before forkpty, it cause FreeBSD hang SetEncode(mDefaultEncode, mDefaultEncode); InitInputManager(f); if (f.GetOption("startupmsg",true)) StartupMsg();}void Zhcon::Run() { InputEvt evt; Encode e; int t = 0;// fadeout();// fadein(); mState = RUNNING; while (mState == RUNNING) { mpCon->CursorBlink(); mpInputManager->Process(evt); if (evt.oper != InputEvt::Nothing) { DoInputEvt(evt); continue; } if (++t < 10 || mAutoEncode == MANUAL) continue; t = 0; e = mpCon->DetectBufferEncode(); switch (e) { case ASCII: SetEncode(mDefaultEncode, mDefaultEncode); break; case GB2312: SetEncode(GB2312, mAutoEncode == AUTO_BIG5 ? BIG5 : GB2312); break; case BIG5: SetEncode(BIG5, mAutoEncode == AUTO_GB ? GB2312 : BIG5); break; default: assert(!"Wrong encode!"); } } //while}void Zhcon::DoInputEvt(InputEvt &evt) { switch (evt.oper) { case InputEvt::SetEnco: switch (evt.sub) { case 1: SetEncode(GB2312, GB2312); break; case 2: SetEncode(GBK, GBK); break; case 3: SetEncode(BIG5, BIG5); break; case 4: SetEncode(JIS, JIS); break; case 5: SetEncode(KSC, KSC); break; default: break; } break; case InputEvt::AutoEncoSwitch: switch (mAutoEncode) { case AUTO: mAutoEncode = AUTO_GB; break; case AUTO_GB: mAutoEncode = AUTO_BIG5; break; case AUTO_BIG5: mAutoEncode = MANUAL; break; case MANUAL: mAutoEncode = AUTO; break; } mpInputManager->Redraw(); Beep(); break; default: break; }}//fork a new pty to run user's shell//return true if successfully forkvoid Zhcon::ForkPty() { char name[50]; mTtyPid = forkpty(&mTtyFd, name, NULL, NULL); if (mTtyPid == -1) throw runtime_error("forkpty fail!"); ioctl(0, TIOCSCTTY, 0); if (mTtyPid == 0) { //child struct passwd *userpd; if ((userpd = getpwuid(getuid())) == NULL) throw runtime_error("can not get user's shell!"); /* close all opened file */#ifndef OPEN_MAX #warning OPEN_MAX undefined so far,try define it to 64 #define OPEN_MAX 64#endif for (int i = 3; i < OPEN_MAX; i++) close(i); setsid(); //seteuid(getuid()); /* for security */ //TODO: handle error condition if (mArgc > 1) execvp(mArgv[1], &mArgv[1]); else execlp(userpd->pw_shell, userpd->pw_shell, (char *) 0); exit(-1); }}void Zhcon::InstallSignal() { struct sigaction act; act.sa_handler = SignalHandle; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGHUP, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGILL, &act, NULL); sigaction(SIGABRT, &act, NULL); sigaction(SIGIOT, &act, NULL); sigaction(SIGBUS, &act, NULL); sigaction(SIGFPE, &act, NULL); sigaction(SIGTERM, &act, NULL); act.sa_handler = &SignalChild; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGCHLD, &act, NULL); // act.sa_handler = &SignalAlarm; // sigemptyset(&act.sa_mask); // act.sa_flags = 0; // sigaction(SIGALRM, &act, NULL);}//do some clean up before quitvoid Zhcon::CleanUp() { struct sigaction act; /* done in procress and block all serious signal to prevent interrupt */ act.sa_handler = SIG_IGN; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGHUP, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGILL, &act, NULL); sigaction(SIGABRT, &act, NULL); sigaction(SIGIOT, &act, NULL); sigaction(SIGBUS, &act, NULL); sigaction(SIGFPE, &act, NULL); VtSignalClean();#if defined(__FreeBSD__) ioctl(0, VT_RELDISP, 1);#endif GraphDev::Close(); delete gpAscFont; delete gpHzFont; delete gpDecoder; delete mpCon; delete mpInputManager; if (mConFd != -1) { // need restore signal ? tcsetattr(mConFd, TCSAFLUSH, &mOldTermios); // restore console blanking#if defined(linux) write(mConFd, "\033[9;10]",7); // default 10 minutes#elif defined(__FreeBSD__) int BlankTime = 5; // default 5 minutes ioctl(mConFd, CONS_BLANKTIME, &BlankTime);#endif ioctl(mConFd, KDSETMODE, KD_TEXT); // special for vga ioctl(mConFd, TIOCSWINSZ, &mOldWinSize); // for mouse, keep text mode clean // write(mConFd, "\n", 1); // make visible cursor, use termcap "ve" instead //write(mConFd, "\E[?25h\E[?0c", 11); if (mpCapCursorOn) write(mConFd, mpCapCursorOn, strlen(mpCapCursorOn)); close(mConFd); } setenv("LC_ALL", mOldLocale.c_str(), 1);}char Zhcon::mCapBuf[512] = {0};char* Zhcon::mpCapClearScr = NULL;char* Zhcon::mpCapCursorOff = NULL;char* Zhcon::mpCapCursorOn = NULL;void Zhcon::InitTty() { // Using throw cause core dump when call destruct if (!isatty(fileno(stdout))) { printf("This is an interactive api, don't redirect stdout.\r\n"); exit(1); } char *TtyName = ttyname(fileno(stdout)); if (!TtyName) { printf("Can not get current tty name.\r\n"); exit(1); } if (!(strncmp("/dev/tty", TtyName, 8) == 0 || strncmp("/dev/vc/", TtyName, 8) == 0)) { printf("%s is not real tty or vc. Please exit current tty and try again.\r\n", TtyName); exit(1); } mConFd = open(TtyName, O_RDWR); if (mConFd == -1) throw runtime_error("Can not open console!"); if (tcgetattr(mConFd, &mOldTermios) < 0) throw runtime_error("Can't get console termios."); struct termios t; t = mOldTermios; t.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG | NOFLSH); t.c_iflag &= ~(BRKINT | ICRNL | ISTRIP | IXON); t.c_cflag &= ~(CSIZE | PARENB); t.c_cflag |= CS8; t.c_oflag &= ~(OPOST); t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0;#if defined(linux) t.c_line = 0;#elif defined(__FreeBSD__) t.c_cc[VDISCARD] = _POSIX_VDISABLE; t.c_cc[VLNEXT] = _POSIX_VDISABLE; t.c_cc[VSTART] = _POSIX_VDISABLE; t.c_cc[VSTOP] = _POSIX_VDISABLE; t.c_cc[VINTR] = _POSIX_VDISABLE; t.c_cc[VSUSP] = _POSIX_VDISABLE; t.c_cc[VDSUSP] = _POSIX_VDISABLE; t.c_cc[VQUIT] = _POSIX_VDISABLE; setenv("TERM","linux",1);#endif if (tcsetattr(mConFd, TCSAFLUSH, &t) < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -