blob: 1e8e53fcc9b9fc0a8f8c66dd0eac41711eecf59c [file]
/*
* 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 <stdio.h>
#include <string.h>
#include "log.h"
#include "parse.h"
#include "scr.h"
#include "cmd_brlapi.h"
#include "charset.h"
#define BRLAPI_NO_DEPRECATED
#include "brlapi.h"
typedef enum {
PARM_HOST,
PARM_AUTH,
PARM_SPEECH_CHANGES,
} DriverParameter;
#define BRLPARMS "host", "auth", "speechChanges"
#include "brl_driver.h"
#define CHECK(cond, label) \
do { \
if (!(cond)) { \
logMessage(LOG_ERR, "%s", brlapi_strerror(&brlapi_error)); \
goto label; \
} \
} while (0);
static brlapi_param_clientPriority_t currentPriority;
static const brlapi_param_clientPriority_t qualityPriorities[] = {
[SCQ_NONE] = BRLAPI_PARAM_CLIENT_PRIORITY_DISABLE,
[SCQ_LOW] = BRLAPI_PARAM_CLIENT_PRIORITY_DEFAULT - 40,
[SCQ_POOR] = BRLAPI_PARAM_CLIENT_PRIORITY_DEFAULT - 25,
[SCQ_FAIR] = BRLAPI_PARAM_CLIENT_PRIORITY_DEFAULT - 10,
[SCQ_GOOD] = BRLAPI_PARAM_CLIENT_PRIORITY_DEFAULT + 10,
[SCQ_HIGH] = BRLAPI_PARAM_CLIENT_PRIORITY_DEFAULT + 30,
};
static int displaySize;
static unsigned char *prevData;
static wchar_t *prevText;
static int prevCursor;
static int prevShown;
static int restart;
static int
ignoreSpeechChangeCommands (void) {
static const brlapi_keyCode_t commands[] = {
BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_SAY_LOUDER,
BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_SAY_SOFTER,
BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_SAY_FASTER,
BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_SAY_SLOWER,
BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_SAY_HIGHER,
BRLAPI_KEY_TYPE_CMD | BRLAPI_KEY_CMD_SAY_LOWER,
};
CHECK(brlapi_ignoreKeys(brlapi_rangeType_command, commands, ARRAY_COUNT(commands))>=0, failed);
return 1;
failed:
return 0;
}
/* Function : brl_construct */
/* Opens a connection with BrlAPI's server */
static int brl_construct(BrailleDisplay *brl, char **parameters, const char *device)
{
currentPriority = BRLAPI_PARAM_CLIENT_PRIORITY_DEFAULT;
brlapi_connectionSettings_t settings;
settings.host = parameters[PARM_HOST];
settings.auth = parameters[PARM_AUTH];
CHECK((brlapi_openConnection(&settings, &settings)>=0), out);
logMessage(LOG_CATEGORY(BRAILLE_DRIVER),
"connected to %s using %s", settings.host, settings.auth
);
CHECK((brlapi_enterTtyModeWithPath(NULL, 0, NULL)>=0), out0);
logMessage(LOG_CATEGORY(BRAILLE_DRIVER),
"got tty successfully"
);
CHECK((brlapi_getDisplaySize(&brl->textColumns, &brl->textRows)==0), out1);
displaySize = brl->textColumns * brl->textRows;
logMessage(LOG_CATEGORY(BRAILLE_DRIVER),
"got display size: %dx%d", brl->textColumns, brl->textRows
);
{
unsigned int speechChanges = 1;
const char *parameter = parameters[PARM_SPEECH_CHANGES];
if (*parameter) {
if (!validateYesNo(&speechChanges, parameter)) {
logMessage(LOG_WARNING, "%s: %s", "invalid speech changes setting", parameter);
} else if (!speechChanges) {
ignoreSpeechChangeCommands();
}
}
}
brl->hideCursor = 1;
prevData = malloc(displaySize);
CHECK((prevData!=NULL), out1);
memset(prevData, 0, displaySize);
prevText = malloc(displaySize * sizeof(wchar_t));
CHECK((prevText!=NULL), out2);
wmemset(prevText, WC_C(' '), displaySize);
prevShown = 0;
prevCursor = BRL_NO_CURSOR;
restart = 0;
logMessage(LOG_CATEGORY(BRAILLE_DRIVER),
"Memory allocated, returning 1");
return 1;
out2:
free(prevData);
out1:
brlapi_leaveTtyMode();
out0:
brlapi_closeConnection();
out:
logMessage(LOG_CATEGORY(BRAILLE_DRIVER),
"Something went wrong, returning 0");
return 0;
}
/* Function : brl_destruct */
/* Frees memory and closes the connection with BrlAPI */
static void brl_destruct(BrailleDisplay *brl)
{
free(prevData);
free(prevText);
brlapi_closeConnection();
}
static int
setClientPriority (BrailleDisplay *brl) {
unsigned char worst = ARRAY_COUNT(qualityPriorities) - 1;
unsigned char quality = MIN(brl->quality, worst);
brlapi_param_clientPriority_t priority = qualityPriorities[quality];
if (priority != currentPriority) {
int result = brlapi_setParameter(
BRLAPI_PARAM_CLIENT_PRIORITY, 0,
BRLAPI_PARAMF_LOCAL, &priority, sizeof(priority)
);
if (result < 0) return 0;
currentPriority = priority;
}
return 1;
}
/* function : brl_writeWindow */
/* Displays a text on the braille window, only if it's different from */
/* the one already displayed */
static int brl_writeWindow(BrailleDisplay *brl, const wchar_t *text)
{
setClientPriority(brl);
brlapi_writeArguments_t arguments = BRLAPI_WRITEARGUMENTS_INITIALIZER;
int vt = currentVirtualTerminal();
if (vt == SCR_NO_VT) {
/* should leave display */
if (prevShown) {
brlapi_write(&arguments);
prevShown = 0;
}
} else {
if (prevShown &&
(memcmp(prevData,brl->buffer,displaySize) == 0) &&
(!text || (wmemcmp(prevText,text,displaySize) == 0)) &&
(brl->cursor == prevCursor)) {
return 1;
}
unsigned char and[displaySize];
memset(and, 0, sizeof(and));
arguments.andMask = and;
arguments.orMask = brl->buffer;
if (text) {
arguments.text = (char*) text;
arguments.textSize = displaySize * sizeof(wchar_t);
arguments.charset = (char*) getWcharCharset();
}
arguments.regionBegin = 1;
arguments.regionSize = displaySize;
arguments.cursor = (brl->cursor != BRL_NO_CURSOR)? (brl->cursor + 1): BRLAPI_CURSOR_OFF;
if (brlapi_write(&arguments)==0) {
memcpy(prevData,brl->buffer,displaySize);
if (text)
wmemcpy(prevText,text,displaySize);
else
wmemset(prevText,0,displaySize);
prevCursor = brl->cursor;
prevShown = 1;
} else {
logMessage(LOG_ERR, "write: %s", brlapi_strerror(&brlapi_error));
restart = 1;
}
}
return 1;
}
/* Function : brl_readCommand */
/* Reads a command from the braille keyboard */
static int brl_readCommand(BrailleDisplay *brl, KeyTableCommandContext context)
{
brlapi_keyCode_t keycode;
if (restart) return BRL_CMD_RESTARTBRL;
switch (brlapi_readKey(0, &keycode)) {
case 0: return EOF;
case 1: return cmdBrlapiToBrltty(keycode);
default: return BRL_CMD_RESTARTBRL;
}
}