/* * 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-2021 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 . */ #include "prologue.h" #include #include #include #include #include "log.h" #include "parameters.h" #include "charset.h" #include "unicode.h" #include "brl.h" #include "ttb.h" #include "ktb.h" #include "queue.h" void constructBrailleDisplay (BrailleDisplay *brl) { brl->data = NULL; brl->refreshBrailleDisplay = NULL; brl->refreshBrailleRow = NULL; brl->setBrailleFirmness = NULL; brl->setTouchSensitivity = NULL; brl->setAutorepeatProperties = NULL; brl->textColumns = 0; brl->textRows = 1; brl->statusColumns = 0; brl->statusRows = 0; brl->cellSize = 8; brl->keyBindings = "all"; brl->keyNames = NULL; brl->keyTable = NULL; brl->gioEndpoint = NULL; brl->writeDelay = 0; brl->buffer = NULL; brl->quality = 0; brl->isCoreBuffer = 0; brl->bufferResized = NULL; brl->resizeRequired = 0; brl->cursor = BRL_NO_CURSOR; brl->noDisplay = 0; brl->hasFailed = 0; brl->isOffline = 0; brl->isSuspended = 0; brl->hideCursor = 0; brl->acknowledgements.messages = NULL; brl->acknowledgements.alarm = NULL; brl->acknowledgements.missing.timeout = BRAILLE_MESSAGE_ACKNOWLEDGEMENT_TIMEOUT; brl->acknowledgements.missing.count = 0; brl->acknowledgements.missing.limit = BRAILLE_MESSAGE_UNACKNOWLEDGEED_LIMIT; } void destructBrailleDisplay (BrailleDisplay *brl) { if (brl->acknowledgements.alarm) { asyncCancelRequest(brl->acknowledgements.alarm); brl->acknowledgements.alarm = NULL; } if (brl->acknowledgements.messages) { deallocateQueue(brl->acknowledgements.messages); brl->acknowledgements.messages = NULL; } if (brl->keyTable) { destroyKeyTable(brl->keyTable); brl->keyTable = NULL; } if (brl->buffer) { if (brl->isCoreBuffer) free(brl->buffer); brl->buffer = NULL; } } static void fillRegion ( wchar_t *text, unsigned char *dots, unsigned int start, unsigned int count, unsigned int columns, unsigned int rows, void *data, unsigned int length, void (*fill) (wchar_t *text, unsigned char *dots, void *data) ) { text += start; dots += start; while (rows > 0) { unsigned int index = 0; size_t amount = length; if (amount > count) amount = count; while (index < amount) { fill(&text[index], &dots[index], data); index += 1; } length -= amount; amount = count - index; wmemset(&text[index], WC_C(' '), amount); memset(&dots[index], 0, amount); text += columns; dots += columns; rows -= 1; } } static void fillText (wchar_t *text, unsigned char *dots, void *data) { wchar_t **character = data; *dots = convertCharacterToDots(textTable, (*text = *(*character)++)); } void fillTextRegion ( wchar_t *text, unsigned char *dots, unsigned int start, unsigned int count, unsigned int columns, unsigned int rows, const wchar_t *characters, size_t length ) { fillRegion(text, dots, start, count, columns, rows, &characters, length, fillText); } static void fillDots (wchar_t *text, unsigned char *dots, void *data) { unsigned char **cell = data; *text = UNICODE_BRAILLE_ROW | (*dots = *(*cell)++); } void fillDotsRegion ( wchar_t *text, unsigned char *dots, unsigned int start, unsigned int count, unsigned int columns, unsigned int rows, const unsigned char *cells, size_t length ) { fillRegion(text, dots, start, count, columns, rows, &cells, length, fillDots); } int setStatusText (BrailleDisplay *brl, const char *text) { unsigned int length = brl->statusColumns * brl->statusRows; if (braille->writeStatus && (length > 0)) { unsigned char cells[length]; { unsigned int index = 0; while (index < length) { char c; wint_t wc; if (!(c = text[index])) break; if ((wc = convertCharToWchar(c)) == WEOF) wc = WC_C('?'); cells[index++] = convertCharacterToDots(textTable, wc); } memset(&cells[index], 0, length-index); } if (!braille->writeStatus(brl, cells)) return 0; } return 1; } int clearStatusCells (BrailleDisplay *brl) { return setStatusText(brl, ""); } static void brailleBufferResized (BrailleDisplay *brl, int infoLevel) { logMessage(infoLevel, "Braille Display Dimensions: %d %s, %d %s", brl->textColumns, ((brl->textColumns == 1)? "column": "columns"), brl->textRows, ((brl->textRows == 1)? "row": "rows") ); memset(brl->buffer, 0, brl->textColumns*brl->textRows); if (brl->bufferResized) brl->bufferResized(brl->textRows, brl->textColumns); } static int resizeBrailleBuffer (BrailleDisplay *brl, int resized, int infoLevel) { if (brl->resizeRequired) { brl->resizeRequired = 0; resized = 1; if (brl->isCoreBuffer) { size_t newSize = brl->textColumns * brl->textRows; unsigned char *newAddress = malloc(newSize); if (!newAddress) { logMallocError(); return 0; } if (brl->buffer) free(brl->buffer); brl->buffer = newAddress; } } if (resized) brailleBufferResized(brl, infoLevel); return 1; } int ensureBrailleBuffer (BrailleDisplay *brl, int infoLevel) { brl->resizeRequired = brl->isCoreBuffer = !brl->buffer; if ((brl->noDisplay = !brl->textColumns)) brl->textColumns = 1; return resizeBrailleBuffer(brl, 1, infoLevel); } int readBrailleCommand (BrailleDisplay *brl, KeyTableCommandContext context) { int command = braille->readCommand(brl, context); resizeBrailleBuffer(brl, 0, LOG_INFO); return command; } int canRefreshBrailleDisplay (BrailleDisplay *brl) { return brl->refreshBrailleDisplay != NULL; } int refreshBrailleDisplay (BrailleDisplay *brl) { if (!canRefreshBrailleDisplay(brl)) return 0; logMessage(LOG_DEBUG, "refreshing braille display"); return brl->refreshBrailleDisplay(brl); } int canRefreshBrailleRow (BrailleDisplay *brl) { return brl->refreshBrailleRow != NULL; } int refreshBrailleRow (BrailleDisplay *brl, int row) { if (!canRefreshBrailleRow(brl)) return 0; logMessage(LOG_DEBUG, "refreshing braille row: %d", row); return brl->refreshBrailleRow(brl, row); } int canSetBrailleFirmness (BrailleDisplay *brl) { return brl->setBrailleFirmness != NULL; } int setBrailleFirmness (BrailleDisplay *brl, BrailleFirmness setting) { if (!canSetBrailleFirmness(brl)) return 0; logMessage(LOG_DEBUG, "setting braille firmness: %d", setting); return brl->setBrailleFirmness(brl, setting); } int canSetTouchSensitivity (BrailleDisplay *brl) { return brl->setTouchSensitivity != NULL; } int setTouchSensitivity (BrailleDisplay *brl, TouchSensitivity setting) { if (!canSetTouchSensitivity(brl)) return 0; logMessage(LOG_DEBUG, "setting touch sensitivity: %d", setting); return brl->setTouchSensitivity(brl, setting); } int canSetAutorepeatProperties (BrailleDisplay *brl) { return brl->setAutorepeatProperties != NULL; } int setAutorepeatProperties (BrailleDisplay *brl, int on, int delay, int interval) { if (!canSetAutorepeatProperties(brl)) return 0; logMessage(LOG_DEBUG, "setting autorepeat properties: %s Delay:%d Interval:%d", (on? "on": "off"), delay, interval); return brl->setAutorepeatProperties(brl, on, delay, interval); }