static int getCurrentPosition (RoutingData *routing) { ScreenDescription description; describeScreen(&description); if (description.number != routing->screenNumber) { logRouting("screen changed: num=%d", description.number); routing->screenNumber = description.number; return 0; } if (!routing->rowBuffer) { routing->screenRows = description.rows; routing->screenColumns = description.cols; routing->verticalDelta = 0; if (!(routing->rowBuffer = calloc(routing->screenColumns, sizeof(*routing->rowBuffer)))) { logMallocError(); goto error; } logRouting("screen: num=%d cols=%d rows=%d", routing->screenNumber, routing->screenColumns, routing->screenRows); } else if ((routing->screenRows != description.rows) || (routing->screenColumns != description.cols)) { logRouting("size changed: cols=%d rows=%d", description.cols, description.rows); goto error; } routing->cury = description.posy - routing->verticalDelta; routing->curx = description.posx; if (readScreenRow(routing, NULL, description.posy)) return 1; logRouting("read failed: row=%d", description.posy); error: routing->screenNumber = -1; return 0; }
static void moveCursor (RoutingData *routing, const CursorDirectionEntry *direction) { #ifdef SIGUSR1 sigset_t oldMask; sigprocmask(SIG_BLOCK, &routing->signalMask, &oldMask); #endif /* SIGUSR1 */ logRouting("move: %s", direction->name); insertScreenKey(direction->key); #ifdef SIGUSR1 sigprocmask(SIG_SETMASK, &oldMask, NULL); #endif /* SIGUSR1 */ }
static RoutingStatus doRouting (int column, int row, int screen) { RoutingData routing; #ifdef SIGUSR1 /* Set up the signal mask. */ sigemptyset(&routing.signalMask); sigaddset(&routing.signalMask, SIGUSR1); sigprocmask(SIG_UNBLOCK, &routing.signalMask, NULL); #endif /* SIGUSR1 */ /* initialize the routing data structure */ routing.screenNumber = screen; routing.rowBuffer = NULL; routing.timeSum = ROUTING_TIMEOUT; routing.timeCount = 1; if (getCurrentPosition(&routing)) { logRouting("from: [%d,%d]", routing.curx, routing.cury); if (column < 0) { adjustCursorVertically(&routing, 0, row); } else { if (adjustCursorVertically(&routing, -1, row) != CRR_FAIL) if (adjustCursorHorizontally(&routing, 0, row, column) == CRR_NEAR) if (routing.cury < row) if (adjustCursorVertically(&routing, 1, routing.cury+1) != CRR_FAIL) adjustCursorHorizontally(&routing, 0, row, column); } } if (routing.rowBuffer) free(routing.rowBuffer); if (routing.screenNumber != screen) return ROUTING_ERROR; if (routing.cury != row) return ROUTING_WRONG_ROW; if ((column >= 0) && (routing.curx != column)) return ROUTING_WRONG_COLUMN; return ROUTING_DONE; }
static RoutingResult adjustCursorPosition (RoutingData *routing, int where, int trgy, int trgx, const CursorAxisEntry *axis) { logRouting("to: [%d,%d]", trgx, trgy); while (1) { int dify = trgy - routing->cury; int difx = (trgx < 0)? 0: (trgx - routing->curx); int dir; /* determine which direction the cursor needs to move in */ if (dify) { dir = (dify > 0)? 1: -1; } else if (difx) { dir = (difx > 0)? 1: -1; } else { return CRR_DONE; } /* tell the cursor to move in the needed direction */ moveCursor(routing, ((dir > 0)? axis->forward: axis->backward)); if (!awaitCursorMotion(routing, dir)) return CRR_FAIL; if (routing->cury != routing->oldy) { if (routing->oldy != trgy) { if (((routing->cury - routing->oldy) * dir) > 0) { int dif = trgy - routing->cury; if ((dif * dify) >= 0) continue; if (where > 0) { if (routing->cury > trgy) return CRR_NEAR; } else if (where < 0) { if (routing->cury < trgy) return CRR_NEAR; } else { if ((dif * dif) < (dify * dify)) return CRR_NEAR; } } } } else if (routing->curx != routing->oldx) { if (((routing->curx - routing->oldx) * dir) > 0) { int dif = trgx - routing->curx; if (routing->cury != trgy) continue; if ((dif * difx) >= 0) continue; if (where > 0) { if (routing->curx > trgx) return CRR_NEAR; } else if (where < 0) { if (routing->curx < trgx) return CRR_NEAR; } else { if ((dif * dif) < (difx * difx)) return CRR_NEAR; } } } else { return CRR_NEAR; } /* We're getting farther from our target. Before giving up, let's * try going back to the previous position since it was obviously * the nearest ever reached. */ moveCursor(routing, ((dir > 0)? axis->backward: axis->forward)); return awaitCursorMotion(routing, -dir)? CRR_NEAR: CRR_FAIL; } }
static int awaitCursorMotion (RoutingData *routing, int direction) { int oldx = (routing->oldx = routing->curx); int oldy = (routing->oldy = routing->cury); long timeout = routing->timeSum / routing->timeCount; int moved = 0; TimeValue start; getCurrentTime(&start); while (1) { long time; approximateDelay(ROUTING_INTERVAL); time = millisecondsSince(&start) + 1; { int row = routing->cury + routing->verticalDelta; int bestRow = row; int bestLength = 0; do { ScreenCharacter buffer[routing->screenColumns]; if (!readScreenRow(routing, buffer, row)) break; { int before = routing->curx; int after = before; while (buffer[before].text == routing->rowBuffer[before].text) if (--before < 0) break; while (buffer[after].text == routing->rowBuffer[after].text) if (++after >= routing->screenColumns) break; { int length = after - before - 1; if (length > bestLength) { bestRow = row; if ((bestLength = length) == routing->screenColumns) break; } } } row -= direction; } while ((row >= 0) && (row < routing->screenRows)); routing->verticalDelta = bestRow - routing->cury; } oldy = routing->cury; oldx = routing->curx; if (!getCurrentPosition(routing)) return 0; if ((routing->cury != oldy) || (routing->curx != oldx)) { logRouting("moved: [%d,%d] -> [%d,%d]", oldx, oldy, routing->curx, routing->cury); if (!moved) { moved = 1; timeout = time * 2; routing->timeSum += time * 8; routing->timeCount += 1; } } else if (time > timeout) { if (!moved) { logRouting("timed out"); } break; } } return 1; }
static int awaitCursorMotion (RoutingData *routing, int direction, const CursorAxisEntry *axis) { int moved = 0; long int timeout = routing->timeSum / routing->timeCount; TimeValue start; int trgy = routing->cury; int trgx = routing->curx; routing->oldy = routing->cury; routing->oldx = routing->curx; axis->adjustCoordinate(&trgy, &trgx, direction); getMonotonicTime(&start); while (1) { long int time; TimeValue now; int oldy; int oldx; approximateDelay(ROUTING_INTERVAL); getMonotonicTime(&now); time = millisecondsBetween(&start, &now) + 1; { int row = routing->cury + routing->verticalDelta; int bestRow = row; int bestLength = 0; do { ScreenCharacter buffer[routing->screenColumns]; if (!readScreenRow(routing, buffer, row)) break; { int before = routing->curx; int after = before; while (buffer[before].text == routing->rowBuffer[before].text) if (--before < 0) break; while (buffer[after].text == routing->rowBuffer[after].text) if (++after >= routing->screenColumns) break; { int length = after - before - 1; if (length > bestLength) { bestRow = row; if ((bestLength = length) == routing->screenColumns) break; } } } row -= direction; } while ((row >= 0) && (row < routing->screenRows)); routing->verticalDelta = bestRow - routing->cury; } oldy = routing->cury; oldx = routing->curx; if (!getCurrentPosition(routing)) return 0; if ((routing->cury != oldy) || (routing->curx != oldx)) { logRouting("moved: [%d,%d] -> [%d,%d] (%dms)", oldx, oldy, routing->curx, routing->cury, time); if (!moved) { moved = 1; timeout = (time * 2) + 1; routing->timeSum += time * 8; routing->timeCount += 1; } if ((routing->cury == trgy) && (routing->curx == trgx)) break; if (ROUTING_INTERVAL) { start = now; } else { approximateDelay(1); getMonotonicTime(&start); } } else if (time > timeout) { if (!moved) logRouting("timed out: %ldms", timeout); break; } } return 1; }