| /* |
| * 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; |
| } |
| } |
| } |