/* * 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 "alert.h" #include "cmd_queue.h" #include "cmd_override.h" #include "cmd_utils.h" #include "brl_cmds.h" #include "scr.h" #include "prefs.h" #include "core.h" typedef struct { int row; struct { int first; int last; } column; } SelectionEndpoint; typedef struct { struct { SelectionEndpoint start; SelectionEndpoint end; unsigned char started:1; } selection; } OverrideCommandData; static int getSelectionEndpoint (int arg, SelectionEndpoint *endpoint) { return getCharacterCoordinates(arg, &endpoint->row, &endpoint->column.first, &endpoint->column.last, 0); } static int compareSelectionEndpoints (const SelectionEndpoint *endpoint1, const SelectionEndpoint *endpoint2) { if (endpoint1->row < endpoint2->row) return -1; if (endpoint1->row > endpoint2->row) return 1; if (endpoint1->column.first < endpoint2->column.first) return -1; if (endpoint1->column.first > endpoint2->column.first) return 1; return 0; } static int setSelection (const SelectionEndpoint *start, const SelectionEndpoint *end, OverrideCommandData *ocd) { { const SelectionEndpoint *from = start; const SelectionEndpoint *to = end; if (compareSelectionEndpoints(from, to) > 0) { const SelectionEndpoint *temp = from; from = to; to = temp; } if (!setScreenTextSelection(from->column.first, from->row, to->column.last, to->row)) { return 0; } } ocd->selection.start = *start; ocd->selection.end = *end; return 1; } static int startSelection (const SelectionEndpoint *start, OverrideCommandData *ocd) { return setSelection(start, start, ocd); } static int handleOverrideCommands (int command, void *data) { OverrideCommandData *ocd = data; if (!scr.hasSelection) ocd->selection.started = 0; switch (command & BRL_MSK_CMD) { case BRL_CMD_TXTSEL_CLEAR: { if (clearScreenTextSelection()) { ocd->selection.started = 0; } else { alert(ALERT_COMMAND_REJECTED); } break; } default: { int blk = command & BRL_MSK_BLK; int arg = command & BRL_MSK_ARG; int ext = BRL_CODE_GET(EXT, command); switch (blk) { case BRL_CMD_BLK(TXTSEL_SET): { if (ext > arg) { SelectionEndpoint start; if (getSelectionEndpoint(arg, &start)) { SelectionEndpoint end; if (getSelectionEndpoint(ext, &end)) { if (setSelection(&start, &end, ocd)) { ocd->selection.started = 0; break; } } } } alert(ALERT_COMMAND_REJECTED); break; } case BRL_CMD_BLK(TXTSEL_START): { SelectionEndpoint start; if (getSelectionEndpoint(arg, &start)) { if (startSelection(&start, ocd)) { ocd->selection.started = 1; break; } } alert(ALERT_COMMAND_REJECTED); break; } case BRL_CMD_BLK(ROUTE): { if (!ocd->selection.started && !prefs.startSelectionWithRoutingKey) return 0; SelectionEndpoint endpoint; if (getSelectionEndpoint(arg, &endpoint)) { if (ocd->selection.started) {; if (setSelection(&ocd->selection.start, &endpoint, ocd)) break; } else if ((endpoint.row != scr.posy) || !((endpoint.column.first <= scr.posx) && (scr.posx <= endpoint.column.last))) { return 0; } else if (startSelection(&endpoint, ocd)) { ocd->selection.started = 1; break; } } alert(ALERT_COMMAND_REJECTED); break; } default: return 0; } break; } } return 1; } static void destroyOverrideCommandData (void *data) { OverrideCommandData *ocd = data; free(ocd); } int addOverrideCommands (void) { OverrideCommandData *ocd; if ((ocd = malloc(sizeof(*ocd)))) { memset(ocd, 0, sizeof(*ocd)); ocd->selection.started = 0; if (pushCommandHandler("override", KTB_CTX_DEFAULT, handleOverrideCommands, destroyOverrideCommandData, ocd)) { return 1; } free(ocd); } else { logMallocError(); } return 0; }