📄 terminal.c
字号:
/*
* KON2 - Kanji ON Console -
* Copyright (C) 1992-1996 Takashi MANABE (manabe@papilio.tutics.tut.ac.jp)
*
* CCE - Console Chinese Environment -
* Copyright (C) 1998-1999 Rui He (herui@cs.duke.edu)
*
* VCOnGUI - Virtual Console On MiniGUi -
* Copyright (C) 1999 Wei Yongming (ymwei@263.net)
*
*/
/*
** This source 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 software 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 library; if not, write to the Free
** Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
** MA 02111-1307, USA
*/
// Create date: 1999.09.23
//
// Modify records:
//
// Who When Where For What Status
//-----------------------------------------------------------------------------
//
// TODO:
//
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <minigui/common.h>
#include <minigui/minigui.h>
#include <minigui/gdi.h>
#include <minigui/window.h>
#include <minigui/control.h>
#include "vcongui.h"
#include "defs.h"
#include "error.h"
#include "vc.h"
#include "child.h"
#include "terminal.h"
#include "vt.h"
static pthread_key_t con_key;
/* Once-only initialisation of the key */
static pthread_once_t con_key_once = PTHREAD_ONCE_INIT;
static pthread_once_t sig_handler_once = PTHREAD_ONCE_INIT;
/* Allocate the key */
static void con_key_alloc()
{
pthread_key_create (&con_key, NULL);
}
/* Set console info */
void set_coninfo (void* data)
{
pthread_once (&con_key_once, con_key_alloc);
pthread_setspecific (con_key, data);
}
void SigChildHandler (int signo)
{
int status;
PCONINFO con;
con = (PCONINFO) pthread_getspecific (con_key);
if (!con) return;
if (waitpid (con->childPid, &status, WNOHANG))
con->terminate = 1;
}
static void InstallSignalHandlers ()
{
struct sigaction siga;
siga.sa_handler = SigChildHandler;
siga.sa_flags = 0;
memset (&siga.sa_mask, 0, sizeof (sigset_t));
sigaction (SIGCHLD, &siga, NULL);
}
static void SetSignalHandlers (void)
{
pthread_once (&sig_handler_once, InstallSignalHandlers);
}
BOOL TerminalStart (PCONINFO con, PCHILDINFO pChildInfo)
{
sigset_t sa_mask;
// We must handle SIGCHLD.
// We handle coninfo as a thread-specific data
set_coninfo (con);
SetSignalHandlers ();
sigemptyset (&sa_mask);
sigaddset (&sa_mask, SIGCHLD);
pthread_sigmask (SIG_UNBLOCK, &sa_mask, NULL);
return OpenTerminal (con, pChildInfo);
}
void TerminalCleanup (PCONINFO con)
{
CloseTerminal (con);
}
BOOL OpenTerminal (PCONINFO con, PCHILDINFO pChildInfo)
{
int iRet;
if ((iRet = TermFork (con, pChildInfo)) < 0)
return FALSE;
if (iRet) {
// In parent process.
VtStart (con);
}
return TRUE;
}
void CloseTerminal (PCONINFO con)
{
close (con->masterPty);
VtCleanup (con);
}
int TermFork (PCONINFO con, PCHILDINFO pChildInfo)
{
char ls, ln;
// 1. Looking for unused PTY/TTY Master/Slave
/* Open PTY(master) from [pqrs][5-F], in fact p-z is ok? */
/* MasterPty: pty[p-z][5-f] pty[a-e][5-f] 16*16=256
SlaveTty: tty[p-z][5-f] tty[a-e][5-f] 16*16=256 */
for (ls = 'p'; ls <= 's'; ls ++) {
for (ln = 5; ln <= 0xF; ln ++) {
sprintf(con->ptyName, "/dev/pty%1c%1x", ls, ln);
if ((con->masterPty = open (con->ptyName, O_RDWR)) >= 0)
break;
}
if (con->masterPty >= 0)
break;
}
if (con->masterPty < 0) {
myMessage ("can not get master pty!\n");
Perror (con->ptyName);
return -1;
}
con->ptyName[5] = 't'; /* slave tty */
if ((con->childPid = fork()) < 0) {
Perror ("fork");
return -1;
}
else if (con->childPid == 0) {
// in child process
int errfd, slavePty;
FILE *errfp;
struct winsize twinsz;
errfd = dup (2);
errfp = fdopen (errfd, "w");
/* I'm child, make me process leader */
setsid ();
// close any no used fd here!!
close (con->masterPty);
/* Open TTY(slave) */
if ((slavePty = open (con->ptyName, O_RDWR)) < 0)
PerrorExit (con->ptyName);
// Set new TTY's termio with parent's termio.
tcsetattr (slavePty, TCSANOW, (struct termios*)GetOriginalTermIO ());
// Set new terminal window size
twinsz.ws_row = con->rows;
twinsz.ws_col = con->cols;
ioctl (slavePty, TIOCSWINSZ, &twinsz);
/* Set std??? to pty, dup2 (oldfd, newfd) */
dup2 (slavePty, 0);
dup2 (slavePty, 1);
dup2 (slavePty, 2);
close (slavePty);
// execute the shell
ChildStart (con, errfp, pChildInfo->startupMessage,
pChildInfo->startupStr,
pChildInfo->execProg,
pChildInfo->execArgs);
}
return 1; // parent process
}
void ReadMasterPty (PCONINFO con)
{
BYTE buff [BUFSIZ + 1];
int nRead;
struct pollfd fd = {con->masterPty, POLLIN, 0};
int ret;
ret = poll (&fd, 1, 10); // about 0.01s
if (ret == 0) {
return;
}
else if (ret > 0) {
if ((nRead = read (con->masterPty, buff, BUFSIZ)) > 0) {
VtWrite (con, buff, nRead);
TextRefresh (con, true);
}
}
}
void HandleInputChar (PCONINFO con, WPARAM wParam, LPARAM lParam)
{
u_char ch;
if (HIBYTE (wParam)) {
u_char buff [2];
buff [0] = LOBYTE (wParam);
buff [1] = HIBYTE (wParam);
write (con->masterPty, buff, 2);
}
else {
ch = LOBYTE (wParam);
write (con->masterPty, &ch, 1);
}
}
void HandleInputKeyDown (PCONINFO con, WPARAM wParam, LPARAM lParam)
{
char buff [50];
con->kinfo.state = lParam;
con->kinfo.buff = buff;
con->kinfo.pos = 0;
handle_scancode_on_keydown (wParam, &con->kinfo);
if (con->kinfo.pos != 0)
write (con->masterPty, buff, con->kinfo.pos);
}
void HandleInputKeyUp (PCONINFO con, WPARAM wParam, LPARAM lParam)
{
char buff [50];
con->kinfo.state = lParam;
con->kinfo.buff = buff;
con->kinfo.pos = 0;
handle_scancode_on_keyup (wParam, &con->kinfo);
if (con->kinfo.pos != 0)
write (con->masterPty, buff, con->kinfo.pos);
con->kinfo.oldstate = con->kinfo.state;
}
static inline u_int TextAddress (CONINFO *con, u_int x, u_int y)
{
return (con->textHead + x + y * con->dispxmax) % con->textSize;
}
static inline bool IsKanji (CONINFO *con, u_int x, u_int y)
{
return(*(con->flagBuff + TextAddress (con, x, y)) & CODEIS_1);
}
static inline bool IsKanji2 (CONINFO *con, u_int x, u_int y)
{
return(*(con->flagBuff + TextAddress (con, x, y)) & CODEIS_2);
}
static inline void KanjiAdjust (CONINFO *con, int *x, int *y)
{
if (IsKanji2 (con, *x, *y))
--*x;
}
void HandleMouseLeftDownWhenCaptured (PCONINFO con, int x, int y, WPARAM wParam)
{
if (con->m_origx != -1) {
TextRefresh (con, true);
con->m_origx = con->m_origy = -1;
}
x = x / GetCharWidth ();
y = y / GetCharHeight ();
KanjiAdjust (con, &x, &y);
con->m_origx = con->m_oldx = x;
con->m_origy = con->m_oldy = y;
}
void HandleMouseMoveWhenCaptured (PCONINFO con, int x, int y, WPARAM wParam)
{
x /= GetCharWidth ();
y /= GetCharHeight ();
if ( x < 0 || y < 0 || x >= con->dispxmax || y >= con->dispymax)
return;
if (x != con->m_oldx || y != con->m_oldy) {
TextReverse (con, &con->m_origx, &con->m_origy, &x, &y);
TextRefresh (con, true);
TextReverse (con, &con->m_origx, &con->m_origy, &x, &y);
con->m_oldx = x;
con->m_oldy = y;
}
}
void HandleMouseLeftUpWhenCaptured (PCONINFO con, int x, int y, WPARAM wParam)
{
x /= GetCharWidth ();
y /= GetCharHeight ();
TextCopy (con, con->m_origx, con->m_origy, x, y);
con->m_oldx = x;
con->m_oldy = y;
}
void HandleMouseBothDown (PCONINFO con, int x, int y, WPARAM wParam)
{
TextPaste (con);
}
void HandleMouseRightUp (PCONINFO con, int x, int y, WPARAM wParam)
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -