blob: 44cfb4f0a5b5d1bb1da309e31d38433fec715a11 [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 <string.h>
#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;
}