/* * 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 "log.h" #include "cmd_utils.h" #include "cmd_queue.h" #include "cmd_touch.h" #include "brl_cmds.h" #include "brl_utils.h" #include "report.h" #include "bitmask.h" #include "prefs.h" typedef struct { struct { ReportListenerInstance *brailleWindowUpdated; } reportListeners; BITMASK(touched, 88, int); unsigned char cells[88]; unsigned int count; unsigned int activeCells; unsigned int lastActive; int lastTouched; } TouchCommandData; static void resetTouched (TouchCommandData *tcd) { tcd->activeCells = 0; tcd->lastTouched = -1; BITMASK_ZERO(tcd->touched); for (int i = 0; i < tcd->count; ++i) { if (tcd->cells[i]) { BITMASK_SET(tcd->touched, i); tcd->lastActive = i; tcd->activeCells += 1; } } } static void handleTouchAt (int offset, TouchCommandData *tcd) { tcd->lastTouched = offset; BITMASK_CLEAR(tcd->touched, offset); } static void handleTouchOff (TouchCommandData *tcd) { int ok = 0; if (prefs.touchNavigation && (tcd->lastTouched > ((int)tcd->lastActive - 2))) { BITMASK_COUNT(tcd->touched, unread); if (tcd->activeCells && unread == 0) { ok = 1; } if (!ok && tcd->activeCells && unread) { float factor = (float)tcd->activeCells / unread; if (factor > 6) ok = 1; } } if (ok) { resetTouched(tcd); handleCommand(BRL_CMD_NXNBWIN); } } static void handleBrailleWindowUpdated ( const BrailleWindowUpdatedReport *report, TouchCommandData *tcd ) { if (cellsHaveChanged(&tcd->cells[0], report->cells, report->count, NULL, NULL, NULL)) { tcd->count = report->count; resetTouched(tcd); } } REPORT_LISTENER(brailleWindowUpdatedListener) { TouchCommandData *tcd = parameters->listenerData; const BrailleWindowUpdatedReport *report = parameters->reportData; handleBrailleWindowUpdated(report, tcd); } static TouchCommandData * newTouchCommandData (void) { TouchCommandData *tcd; if ((tcd = malloc(sizeof(*tcd)))) { memset(tcd, 0, sizeof(*tcd)); if ((tcd->reportListeners.brailleWindowUpdated = registerReportListener(REPORT_BRAILLE_WINDOW_UPDATED, brailleWindowUpdatedListener, tcd))) { return tcd; } free(tcd); } else { logMallocError(); } return NULL; } static void destroyTouchCommandData (TouchCommandData *tcd) { unregisterReportListener(tcd->reportListeners.brailleWindowUpdated); free(tcd); } static int handleTouchCommands (int command, void *data) { switch (command & BRL_MSK_BLK) { case BRL_CMD_BLK(TOUCH_AT): { int arg = command & BRL_MSK_ARG; if (arg == BRL_MSK_ARG) { handleTouchOff(data); } else { int at; if (isTextOffset(arg, &at, NULL, 0)) handleTouchAt(at, data); } break; } default: return 0; } return 1; } static void destructTouchCommandData (void *data) { TouchCommandData *tcd = data; destroyTouchCommandData(tcd); } int addTouchCommands (void) { TouchCommandData *tcd; if ((tcd = newTouchCommandData())) { if (pushCommandHandler("touch", KTB_CTX_DEFAULT, handleTouchCommands, destructTouchCommandData, tcd)) { return 1; } destroyTouchCommandData(tcd); } return 0; }