blob: 23c7e4d1f4b564dbe1c6802ee11f013f5cd8d9a3 [file] [log] [blame] [edit]
/*
* 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 "scr.h"
#include "scr_utils.h"
#include "scr_base.h"
#include "scr_internal.h"
#include "ascii.h"
void
setScreenKeyModifiers (ScreenKey *key, ScreenKey which) {
if (!isSpecialKey(*key)) {
wchar_t character = *key & SCR_KEY_CHAR_MASK;
ScreenKey modifiers = *key & ~SCR_KEY_CHAR_MASK;
if (which & (SCR_KEY_UPPER | SCR_KEY_SHIFT)) {
if (!(modifiers & (SCR_KEY_UPPER | SCR_KEY_SHIFT))) {
if (iswupper(character)) {
character = towlower(character);
if (which & SCR_KEY_UPPER) {
modifiers |= SCR_KEY_UPPER;
} else {
modifiers |= SCR_KEY_SHIFT;
}
}
}
} else {
if (modifiers & (SCR_KEY_UPPER | SCR_KEY_SHIFT)) {
if (iswalpha(character)) {
character = towupper(character);
modifiers &= ~SCR_KEY_SHIFT;
}
modifiers &= ~SCR_KEY_UPPER;
}
}
if (which & SCR_KEY_CONTROL) {
if (!(modifiers & SCR_KEY_CONTROL)) {
if (character < 0X20) {
character |= 0X60;
modifiers |= SCR_KEY_CONTROL;
}
}
} else {
if (modifiers & SCR_KEY_CONTROL) {
if (character <= 0X7F) {
if ((character & 0X6F) == 0X2F) {
character |= 0X50;
} else {
character &= 0X1F;
}
}
modifiers &= ~SCR_KEY_CONTROL;
}
}
ScreenKey newKey = character | modifiers;
if (newKey != *key) {
logMessage(LOG_CATEGORY(SCREEN_DRIVER), "transformed key: 0X%04X -> 0X%04X", *key, newKey);
*key = newKey;
}
}
}
void
mapScreenKey (ScreenKey *key) {
switch (*key & SCR_KEY_CHAR_MASK) {
case '\n':
case '\r': *key = SCR_KEY_ENTER; break;
case '\t': *key = SCR_KEY_TAB; break;
case '\b': *key = SCR_KEY_BACKSPACE; break;
case ASCII_ESC: *key = SCR_KEY_ESCAPE; break;
}
}
static const char text_BaseScreen[] = " ";
static int
currentVirtualTerminal_BaseScreen (void) {
return 0;
}
static int
selectVirtualTerminal_BaseScreen (int vt) {
return 0;
}
static int
switchVirtualTerminal_BaseScreen (int vt) {
return 0;
}
static int
nextVirtualTerminal_BaseScreen (void) {
return currentScreen->switchVirtualTerminal(currentScreen->currentVirtualTerminal() + 1);
}
static int
previousVirtualTerminal_BaseScreen (void) {
return currentScreen->switchVirtualTerminal(currentScreen->currentVirtualTerminal() - 1);
}
static const char *
getTitle_BaseScreen (void) {
return NULL;
}
static void
onForeground_BaseScreen (void) {
}
static void
onBackground_BaseScreen (void) {
}
static int
poll_BaseScreen (void) {
return 0;
}
static int
refresh_BaseScreen (void) {
return 1;
}
static void
describe_BaseScreen (ScreenDescription *description) {
description->rows = 1;
description->cols = strlen(text_BaseScreen);
description->posx = 0;
description->posy = 0;
description->number = currentVirtualTerminal_BaseScreen();
}
static int
readCharacters_BaseScreen (const ScreenBox *box, ScreenCharacter *buffer) {
ScreenDescription description;
describe_BaseScreen(&description);
if (!validateScreenBox(box, description.cols, description.rows)) return 0;
setScreenMessage(box, buffer, text_BaseScreen);
return 1;
}
static int
insertKey_BaseScreen (ScreenKey key) {
return 0;
}
static int
routeCursor_BaseScreen (int column, int row, int screen) {
return 0;
}
static int
highlightRegion_BaseScreen (int left, int right, int top, int bottom) {
return 0;
}
int
unhighlightRegion_BaseScreen (void) {
return 0;
}
static int
getPointer_BaseScreen (int *column, int *row) {
return 0;
}
static int
clearSelection_BaseScreen (void) {
return 0;
}
static int
setSelection_BaseScreen (int startColumn, int startRow, int endColumn, int endRow) {
return 0;
}
static int
handleCommand_BaseScreen (int command) {
return 0;
}
static KeyTableCommandContext
getCommandContext_BaseScreen (void) {
return KTB_CTX_DEFAULT;
}
void
initializeBaseScreen (BaseScreen *base) {
base->getTitle = getTitle_BaseScreen;
base->onForeground = onForeground_BaseScreen;
base->onBackground = onBackground_BaseScreen;
base->poll = poll_BaseScreen;
base->refresh = refresh_BaseScreen;
base->describe = describe_BaseScreen;
base->readCharacters = readCharacters_BaseScreen;
base->insertKey = insertKey_BaseScreen;
base->routeCursor = routeCursor_BaseScreen;
base->highlightRegion = highlightRegion_BaseScreen;
base->unhighlightRegion = unhighlightRegion_BaseScreen;
base->getPointer = getPointer_BaseScreen;
base->clearSelection = clearSelection_BaseScreen;
base->setSelection = setSelection_BaseScreen;
base->currentVirtualTerminal = currentVirtualTerminal_BaseScreen;
base->selectVirtualTerminal = selectVirtualTerminal_BaseScreen;
base->switchVirtualTerminal = switchVirtualTerminal_BaseScreen;
base->nextVirtualTerminal = nextVirtualTerminal_BaseScreen;
base->previousVirtualTerminal = previousVirtualTerminal_BaseScreen;
base->handleCommand = handleCommand_BaseScreen;
base->getCommandContext = getCommandContext_BaseScreen;
}
void
describeBaseScreen (BaseScreen *base, ScreenDescription *description) {
description->unreadable = NULL;
description->quality = SCQ_GOOD;
description->number = 0;
description->cols = description->rows = 1;
description->posx = description->posy = 0;
description->hasCursor = 1;
description->hasSelection = 0;
base->describe(description);
if (description->unreadable) {
description->hasCursor = 0;
}
}
int
validateScreenBox (const ScreenBox *box, int columns, int rows) {
if ((box->left >= 0))
if ((box->width > 0))
if (((box->left + box->width) <= columns))
if ((box->top >= 0))
if ((box->height > 0))
if (((box->top + box->height) <= rows))
return 1;
logMessage(LOG_ERR, "invalid screen area: cols=%d left=%d width=%d rows=%d top=%d height=%d",
columns, box->left, box->width,
rows, box->top, box->height);
return 0;
}
void
setScreenMessage (const ScreenBox *box, ScreenCharacter *buffer, const char *message) {
const ScreenCharacter *end = buffer + box->width;
unsigned int index = 0;
size_t length = strlen(message);
mbstate_t state;
memset(&state, 0, sizeof(state));
clearScreenCharacters(buffer, (box->width * box->height));
while (length) {
wchar_t wc;
size_t result = mbrtowc(&wc, message, length, &state);
if ((ssize_t)result < 1) break;
message += result;
length -= result;
if (index++ >= box->left) {
if (buffer == end) break;
(buffer++)->text = wc;
}
}
}