blob: 00c2c553d875b66aeffa122b8807c3d768c9f1e1 [file] [log] [blame]
/*
* BRLTTY - A background process providing access to the console screen (when in
* text mode) for a blind person using a refreshable braille display.
*
* Copyright (C) 1995-2023 by The BRLTTY Developers.
*
* BRLTTY comes with ABSOLUTELY NO WARRANTY.
*
* This is free software, placed under the terms of the
* GNU Lesser General Public License, as published by the Free Software
* Foundation; either version 2.1 of the License, or (at your option) any
* later version. Please see the file LICENSE-LGPL for details.
*
* Web Page: http://brltty.app/
*
* This software is maintained by Dave Mielke <dave@mielke.cc>.
*/
#include "prologue.h"
#include <string.h>
#include <fcntl.h>
#include "log.h"
#include "pty_object.h"
#include "scr_types.h"
struct PtyObjectStruct {
char *path;
int master;
unsigned char logLevel;
unsigned char logInput:1;
};
PtyObject *
ptyNewObject (void) {
PtyObject *pty;
if ((pty = malloc(sizeof(*pty)))) {
memset(pty, 0, sizeof(*pty));
pty->path = NULL;
pty->master = INVALID_FILE_DESCRIPTOR;
pty->logLevel = LOG_DEBUG;
pty->logInput = 0;
if ((pty->master = posix_openpt(O_RDWR)) != -1) {
if ((pty->path = ptsname(pty->master))) {
if ((pty->path = strdup(pty->path))) {
if (grantpt(pty->master) != -1) {
if (unlockpt(pty->master) != -1) {
return pty;
} else {
logSystemError("unlockpt");
}
} else {
logSystemError("grantpt");
}
free(pty->path);
} else {
logMallocError();
}
} else {
logSystemError("ptsname");
}
close(pty->master);
} else {
logSystemError("posix_openpt");
}
free(pty);
} else {
logMallocError();
}
return NULL;
}
const char *
ptyGetPath (const PtyObject *pty) {
return pty->path;
}
int
ptyGetMaster (const PtyObject *pty) {
return pty->master;
}
void
ptySetLogLevel (PtyObject *pty, unsigned char level) {
pty->logLevel = level;
}
void
ptySetLogInput (PtyObject *pty, int yes) {
pty->logInput = yes;
}
int
ptyWriteInputData (PtyObject *pty, const void *data, size_t length) {
if (pty->logInput) {
logBytes(pty->logLevel, "pty input", data, length);
}
if (write(pty->master, data, length) != -1) return 1;
logSystemError("pty write input");
return 0;
}
int
ptyWriteInputCharacter (PtyObject *pty, wchar_t character, int kxMode) {
if (!isSpecialKey(character)) {
char buffer[MB_CUR_MAX];
int count = wctomb(buffer, character);
if (count == -1) return 0;
return ptyWriteInputData(pty, buffer, count);
}
const char *sequence = NULL;
char buffer[0X20];
#define KEY(key, seq) case SCR_KEY_##key: sequence = seq; break;
switch (character) {
KEY(ENTER , "\r")
KEY(TAB , "\t")
KEY(BACKSPACE , "\x7F")
KEY(ESCAPE , "\x1B")
KEY(CURSOR_UP , "\x1BOA")
KEY(CURSOR_DOWN , "\x1BOB")
KEY(CURSOR_RIGHT, "\x1BOC")
KEY(CURSOR_LEFT , "\x1BOD")
KEY(HOME , "\x1B[1~")
KEY(INSERT , "\x1B[2~")
KEY(DELETE , "\x1B[3~")
KEY(END , "\x1B[4~")
KEY(PAGE_UP , "\x1B[5~")
KEY(PAGE_DOWN , "\x1B[6~")
KEY(F1 , "\x1BOP")
KEY(F2 , "\x1BOQ")
KEY(F3 , "\x1BOR")
KEY(F4 , "\x1BOS")
KEY(F5 , "\x1B[15~")
KEY(F6 , "\x1B[17~")
KEY(F7 , "\x1B[18~")
KEY(F8 , "\x1B[19~")
KEY(F9 , "\x1B[20~")
KEY(F10 , "\x1B[21~")
KEY(F11 , "\x1B[23~")
KEY(F12 , "\x1B[24~")
default:
logMessage(LOG_WARNING, "unsupported pty screen key: %04X", character);
break;
}
#undef KEY
if (sequence) {
switch (character) {
case SCR_KEY_CURSOR_LEFT:
case SCR_KEY_CURSOR_RIGHT:
case SCR_KEY_CURSOR_UP:
case SCR_KEY_CURSOR_DOWN:
strcpy(buffer, sequence);
buffer[1] = kxMode? 'O': '[';
sequence = buffer;
break;
}
if (!ptyWriteInputData(pty, sequence, strlen(sequence))) {
return 0;
}
}
return 1;
}
void
ptyCloseMaster (PtyObject *pty) {
if (pty->master != INVALID_FILE_DESCRIPTOR) {
close(pty->master);
pty->master = INVALID_FILE_DESCRIPTOR;
}
}
int
ptyOpenSlave (const PtyObject *pty, int *fileDescriptor) {
int result = open(pty->path, O_RDWR);
int opened = result != INVALID_FILE_DESCRIPTOR;
if (opened) {
*fileDescriptor = result;
} else {
logSystemError("pty slave open");
}
return opened;
}
void
ptyDestroyObject (PtyObject *pty) {
ptyCloseMaster(pty);
free(pty->path);
free(pty);
}