int AgiEngine::getKeypress() { int k; while (_keyQueueStart == _keyQueueEnd) // block pollTimer(); keyDequeue(k); return k; }
int AgiEngine::waitKey() { int key = 0; clearKeyQueue(); debugC(3, kDebugLevelInput, "waiting..."); while (!(shouldQuit() || _restartGame || getflag(fRestoreJustRan))) { pollTimer(); key = doPollKeyboard(); if (key == KEY_ENTER || key == KEY_ESCAPE || key == BUTTON_LEFT) break; pollTimer(); updateTimer(); _gfx->doUpdate(); } // Have to clear it as original did not set this variable, and we do it in doPollKeyboard() // Fixes bug #2823759 _game.keypress = 0; return key; }
int AgiEngine::waitAnyKey() { int key = 0; clearKeyQueue(); debugC(3, kDebugLevelInput, "waiting... (any key)"); while (!(shouldQuit() || _restartGame)) { pollTimer(); key = doPollKeyboard(); if (key) break; _gfx->doUpdate(); } // Have to clear it as original did not set this variable, and we do it in doPollKeyboard() _game.keypress = 0; return key; }
void* CMMDVMController::Entry() { wxLogMessage(wxT("Starting MMDVM Controller thread")); // Clock every 5ms-ish CTimer pollTimer(200U, 0U, 100U); pollTimer.start(); unsigned char writeType = DSMTT_NONE; unsigned char writeLength = 0U; unsigned char* writeBuffer = new unsigned char[BUFFER_LENGTH]; unsigned int space = 0U; while (!m_stopped) { // Poll the modem status every 100ms if (pollTimer.hasExpired()) { bool ret = readStatus(); if (!ret) { ret = findModem(); if (!ret) { wxLogError(wxT("Stopping MMDVM Controller thread")); return NULL; } } pollTimer.start(); } unsigned int length; RESP_TYPE_MMDVM type = getResponse(m_buffer, length); switch (type) { case RTDVM_TIMEOUT: break; case RTDVM_ERROR: { bool ret = findModem(); if (!ret) { wxLogError(wxT("Stopping MMDVM Controller thread")); return NULL; } } break; case RTDVM_DSTAR_HEADER: { // CUtils::dump(wxT("RT_DSTAR_HEADER"), m_buffer, length); wxMutexLocker locker(m_mutex); unsigned char data[2U]; data[0U] = DSMTT_HEADER; data[1U] = RADIO_HEADER_LENGTH_BYTES; m_rxData.addData(data, 2U); m_rxData.addData(m_buffer + 3U, RADIO_HEADER_LENGTH_BYTES); m_rx = true; } break; case RTDVM_DSTAR_DATA: { // CUtils::dump(wxT("RT_DSTAR_DATA"), m_buffer, length); wxMutexLocker locker(m_mutex); unsigned char data[2U]; data[0U] = DSMTT_DATA; data[1U] = DV_FRAME_LENGTH_BYTES; m_rxData.addData(data, 2U); m_rxData.addData(m_buffer + 3U, DV_FRAME_LENGTH_BYTES); m_rx = true; } break; case RTDVM_DSTAR_EOT: { // wxLogMessage(wxT("RT_DSTAR_EOT")); wxMutexLocker locker(m_mutex); unsigned char data[2U]; data[0U] = DSMTT_EOT; data[1U] = 0U; m_rxData.addData(data, 2U); m_rx = false; } break; case RTDVM_DSTAR_LOST: { // wxLogMessage(wxT("RT_DSTAR_LOST")); wxMutexLocker locker(m_mutex); unsigned char data[2U]; data[0U] = DSMTT_LOST; data[1U] = 0U; m_rxData.addData(data, 2U); m_rx = false; } break; case RTDVM_GET_STATUS: { bool dstar = (m_buffer[3U] & 0x01U) == 0x01U; if (!dstar) { wxLogError(wxT("D-Star not enabled in the MMDVM!!!")); wxLogError(wxT("Stopping MMDVM Controller thread")); return NULL; } m_tx = (m_buffer[5U] & 0x01U) == 0x01U; space = m_buffer[6U]; // CUtils::dump(wxT("GET_STATUS"), m_buffer, length); // wxLogMessage(wxT("PTT=%d space=%u"), int(m_tx), space); } break; // These should not be received in this loop, but don't complain if we do case RTDVM_GET_VERSION: case RTDVM_ACK: break; case RTDVM_NAK: { switch (m_buffer[3U]) { case MMDVM_DSTAR_HEADER: wxLogWarning(wxT("Received a header NAK from the MMDVM, reason = %u"), m_buffer[4U]); break; case MMDVM_DSTAR_DATA: wxLogWarning(wxT("Received a data NAK from the MMDVM, reason = %u"), m_buffer[4U]); break; case MMDVM_DSTAR_EOT: wxLogWarning(wxT("Received an EOT NAK from the MMDVM, reason = %u"), m_buffer[4U]); break; default: wxLogWarning(wxT("Received a NAK from the MMDVM, command = 0x%02X, reason = %u"), m_buffer[3U], m_buffer[4U]); break; } } break; default: wxLogMessage(wxT("Unknown message, type: %02X"), m_buffer[2U]); CUtils::dump(wxT("Buffer dump"), m_buffer, length); break; } if (writeType == DSMTT_NONE && m_txData.hasData()) { wxMutexLocker locker(m_mutex); m_txData.getData(&writeType, 1U); m_txData.getData(&writeLength, 1U); m_txData.getData(writeBuffer, writeLength); } if (space >= 4U && writeType == DSMTT_HEADER) { // CUtils::dump(wxT("Write Header"), writeBuffer, writeLength); int ret = m_serial.write(writeBuffer, writeLength); if (ret != int(writeLength)) wxLogWarning(wxT("Error when writing the header to the MMDVM")); writeType = DSMTT_NONE; space -= 4U; } if (space >= 1U && (writeType == DSMTT_DATA || writeType == DSMTT_EOT)) { // CUtils::dump(wxT("Write Data"), writeBuffer, writeLength); int ret = m_serial.write(writeBuffer, writeLength); if (ret != int(writeLength)) wxLogWarning(wxT("Error when writing data to the MMDVM")); writeType = DSMTT_NONE; space--; } Sleep(5UL); pollTimer.clock(); } wxLogMessage(wxT("Stopping MMDVM Controller thread")); delete[] writeBuffer; m_serial.close(); return NULL; }
void* CDVRPTRV3Controller::Entry() { wxLogMessage(wxT("Starting DV-RPTR3 Modem Controller thread")); // Clock every 5ms-ish CTimer pollTimer(200U, 0U, 250U); pollTimer.start(); unsigned int space = 0U; while (!m_stopped) { // Poll the modem status every 250ms if (pollTimer.hasExpired()) { bool ret = readSpace(); if (!ret) { ret = findModem(); if (!ret) { wxLogMessage(wxT("Stopping DV-RPTR3 Modem Controller thread")); return NULL; } } pollTimer.start(); } unsigned int length; RESP_TYPE_V3 type = getResponse(m_buffer, length); switch (type) { case RT3_TIMEOUT: break; case RT3_ERROR: { bool ret = findModem(); if (!ret) { wxLogMessage(wxT("Stopping DV-RPTR3 Modem Controller thread")); return NULL; } } break; case RT3_HEADER: { // CUtils::dump(wxT("RT3_HEADER"), m_buffer, length); wxMutexLocker locker(m_mutex); unsigned char data[2U]; data[0U] = DSMTT_HEADER; data[1U] = RADIO_HEADER_LENGTH_BYTES; m_rxData.addData(data, 2U); m_rxData.addData(m_buffer + 9U, RADIO_HEADER_LENGTH_BYTES - 2U); // Dummy checksum data[0U] = 0xFFU; data[1U] = 0xFFU; m_rxData.addData(data, 2U); data[0U] = DSMTT_DATA; data[1U] = DV_FRAME_LENGTH_BYTES; m_rxData.addData(data, 2U); m_rxData.addData(m_buffer + 51U, DV_FRAME_LENGTH_BYTES); m_rx = true; } break; case RT3_DATA: { // CUtils::dump(wxT("RT3_DATA"), m_buffer, length); wxMutexLocker locker(m_mutex); unsigned char data[2U]; data[0U] = DSMTT_DATA; data[1U] = DV_FRAME_LENGTH_BYTES; m_rxData.addData(data, 2U); m_rxData.addData(m_buffer + 5U, DV_FRAME_LENGTH_BYTES); m_rx = true; // End of transmission? bool end = (m_buffer[19U] & 0x40U) == 0x40U; if (end) { data[0U] = DSMTT_EOT; data[1U] = 0U; m_rxData.addData(data, 2U); m_rx = false; } } break; case RT3_SPACE: space = m_buffer[9U]; // CUtils::dump(wxT("RT3_SPACE"), m_buffer, length); break; // These should not be received in this loop, but don't complain if we do case RT3_QUERY: case RT3_CONFIG: break; default: wxLogMessage(wxT("Unknown DV-RPTR3 message, type")); CUtils::dump(wxT("Buffer dump"), m_buffer, length); break; } if (space > 0U) { if (m_txData.hasData()) { unsigned char len = 0U; unsigned char data[200U]; { wxMutexLocker locker(m_mutex); m_txData.getData(&len, 1U); m_txData.getData(data, len); } // CUtils::dump(wxT("Write"), data, len); bool ret = writeModem(data, len); if (!ret) { bool ret = findModem(); if (!ret) { wxLogMessage(wxT("Stopping DV-RPTR3 Modem Controller thread")); return NULL; } } else { space--; } } } Sleep(5UL); pollTimer.clock(); } wxLogMessage(wxT("Stopping DV-RPTR3 Modem Controller thread")); closeModem(); return NULL; }
void* CDVRPTRControllerV2::Entry() { wxLogMessage(wxT("Starting DV-RPTR2 Modem Controller thread")); // Clock every 5ms-ish CTimer pollTimer(200U, 0U, 250U); pollTimer.start(); while (!m_stopped) { // Poll the modem status every 250ms if (pollTimer.hasExpired()) { bool ret = getSpace(); if (!ret) { ret = findModem(); if (!ret) { wxLogMessage(wxT("Stopping DV-RPTR2 Modem Controller thread")); return NULL; } } pollTimer.reset(); } unsigned int length; RESP_TYPE_V2 type = getResponse(m_buffer, length); switch (type) { case RT2_TIMEOUT: break; case RT2_ERROR: { bool ret = findModem(); if (!ret) { wxLogMessage(wxT("Stopping DV-RPTR2 Modem Controller thread")); return NULL; } } break; case RT2_HEADER: { // CUtils::dump(wxT("RT2_HEADER"), m_buffer, length); m_mutex.Lock(); unsigned int space = m_rxData.freeSpace(); if (space < 57U) { wxLogMessage(wxT("Out of space in the DV-RPTR RX queue")); } else { unsigned char data[2U]; data[0U] = DQT_HEADER; data[1U] = RADIO_HEADER_LENGTH_BYTES; m_rxData.addData(data, 2U); m_rxData.addData(m_buffer + 9U, RADIO_HEADER_LENGTH_BYTES - 2U); // Dummy checksum data[0U] = 0xFFU; data[1U] = 0xFFU; m_rxData.addData(data, 2U); data[0U] = DQT_DATA; data[1U] = DV_FRAME_LENGTH_BYTES; m_rxData.addData(data, 2U); m_rxData.addData(m_buffer + 51U, DV_FRAME_LENGTH_BYTES); m_rx = true; } m_mutex.Unlock(); } break; case RT2_DATA: { // CUtils::dump(wxT("RT2_DATA"), m_buffer, length); m_mutex.Lock(); unsigned int space = m_rxData.freeSpace(); if (space < 16U) { wxLogMessage(wxT("Out of space in the DV-RPTR RX queue")); } else { unsigned char data[2U]; data[0U] = DQT_DATA; data[1U] = DV_FRAME_LENGTH_BYTES; m_rxData.addData(data, 2U); m_rxData.addData(m_buffer + 51U, DV_FRAME_LENGTH_BYTES); m_rx = true; // End of transmission? if ((m_buffer[50U] & 0x40U) == 0x40) { data[0U] = DQT_EOT; data[1U] = 0U; m_rxData.addData(data, 2U); m_rx = false; } } m_mutex.Unlock(); } break; case RT2_SPACE: m_space = m_buffer[9U]; // CUtils::dump(wxT("RT2_SPACE"), m_buffer, length); break; // These should not be received in this loop, but don't complain if we do case RT2_QUERY: case RT2_CONFIG: break; default: wxLogMessage(wxT("Unknown DV-RPTR2 message, type")); CUtils::dump(wxT("Buffer dump"), m_buffer, length); break; } if (m_space > 0U) { if (!m_txData.isEmpty()) { m_mutex.Lock(); unsigned char len = 0U; m_txData.getData(&len, 1U); unsigned char data[200U]; m_txData.getData(data, len); m_mutex.Unlock(); // CUtils::dump(wxT("Write"), data, len); int ret = m_serial.write(data, len); if (ret == -1) { bool ret = findModem(); if (!ret) { wxLogMessage(wxT("Stopping DV-RPTR2 Modem Controller thread")); return NULL; } } else { m_space--; } } } Sleep(5UL); pollTimer.clock(); } wxLogMessage(wxT("Stopping DV-RPTR2 Modem Controller thread")); m_serial.close(); return NULL; }
/** * Execute a logic script * @param n Number of the logic resource to execute */ int AgiEngine::runLogic(int n) { AgiGame *state = &_game; uint8 op = 0; uint8 p[CMD_BSIZE] = { 0 }; int num = 0; ScriptPos sp; //int logic_index = 0; state->logic_list[0] = 0; state->max_logics = 0; debugC(2, kDebugLevelScripts, "================="); debugC(2, kDebugLevelScripts, "runLogic(%d)", n); sp.script = n; sp.curIP = 0; _game.execStack.push_back(sp); // If logic not loaded, load it if (~_game.dirLogic[n].flags & RES_LOADED) { debugC(4, kDebugLevelScripts, "logic %d not loaded!", n); agiLoadResource(rLOGIC, n); } _game.lognum = n; _game._curLogic = &_game.logics[_game.lognum]; _game._curLogic->cIP = _game._curLogic->sIP; _timerHack = 0; while (ip < _game.logics[n].size && !(shouldQuit() || _restartGame)) { if (_debug.enabled) { if (_debug.steps > 0) { if (_debug.logic0 || n) { debugConsole(n, lCOMMAND_MODE, NULL); _debug.steps--; } } else { _sprites->blitBoth(); _sprites->commitBoth(); do { mainCycle(); } while (!_debug.steps && _debug.enabled); _sprites->eraseBoth(); } } _game.execStack.back().curIP = ip; char st[101]; int sz = MIN(_game.execStack.size(), 100u); memset(st, '.', sz); st[sz] = 0; switch (op = *(code + ip++)) { case 0xff: // if (open/close) testIfCode(n); break; case 0xfe: // goto // +2 covers goto size ip += 2 + ((int16)READ_LE_UINT16(code + ip)); // timer must keep running even in goto loops, // but AGI engine can't do that :( if (_timerHack > 20) { pollTimer(); updateTimer(); _timerHack = 0; } break; case 0x00: // return debugC(2, kDebugLevelScripts, "%sreturn() // Logic %d", st, n); debugC(2, kDebugLevelScripts, "================="); // if (getVersion() < 0x2000) { // if (logic_index < state->max_logics) { // n = state->logic_list[++logic_index]; // state->_curLogic = &state->logics[n]; // state->lognum = n; // ip = 2; // warning("running logic %d\n", n); // break; // } // _v[13]=0; // } _game.execStack.pop_back(); return 1; default: num = logicNamesCmd[op].argumentsLength(); memmove(p, code + ip, num); memset(p + num, 0, CMD_BSIZE - num); debugC(2, kDebugLevelScripts, "%s%s(%d %d %d)", st, logicNamesCmd[op].name, p[0], p[1], p[2]); _agiCommands[op](&_game, p); ip += num; } // if ((op == 0x0B || op == 0x3F || op == 0x40) && logic_index < state->max_logics) { // n = state->logic_list[++logic_index]; // state->_curLogic = &state->logics[n]; // state->lognum = n; // ip = 2; // warning("running logic %d\n", n); // } if (_game.exitAllLogics) break; } _game.execStack.pop_back(); return 0; // after executing new.room() }
bool AgiEngine::predictiveDialog() { int key = 0, active = -1, lastactive = 0; bool rc = false; uint8 x; int y; int bx[17], by[17]; Common::String prefix; char temp[MAXWORDLEN + 1], repeatcount[MAXWORDLEN]; AgiBlock tmpwindow; bool navigationwithkeys = false; bool processkey; const char *buttonStr[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" }; const char *buttons[] = { "(1)'-.&", "(2)abc", "(3)def", "(4)ghi", "(5)jkl", "(6)mno", "(7)pqrs", "(8)tuv", "(9)wxyz", "(#)next", "add", "<", "Cancel", "OK", "Pre", "(0) ", NULL }; const int colors[] = { 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 0, 15, 12, 15, 12, 15, 0, 15, 0, 15, 0, 14, 0, 15, 0, 0, 0 }; const char *modes[] = { "(*)Pre", "(*)123", "(*)Abc" }; // FIXME: Move this to a more appropriate place. if (!_predictiveDictText) { loadDict(); if (!_predictiveDictText) return false; } _predictiveDictActLine = NULL; uint8 numMatchingWords = 0; _predictiveDialogRunning = true; _system->setFeatureState(OSystem::kFeatureDisableKeyFiltering, true); memset(repeatcount, 0, sizeof(repeatcount)); // show the predictive dialog. // if another window is already in display, save its state into tmpwindow memset(&tmpwindow, 0, sizeof(tmpwindow)); tmpwindow.active = false; if (_game.window.active) memcpy(&tmpwindow, &(_game.window), sizeof(AgiBlock)); drawWindow(50, 40, 269, 159); _gfx->drawRectangle(62, 54, 249, 66, MSG_BOX_TEXT); _gfx->flushBlock(62, 54, 249, 66); bx[15] = 73; // Zero/space by[15] = 120; bx[9] = 110; // next by[9] = 120; bx[10] = 172; // add by[10] = 120; bx[14] = 200; // Mode by[14] = 120; bx[11] = 252; // Backspace by[11] = 57; bx[12] = 180; // Cancel by[12] = 140; bx[13] = 240; // OK by[13] = 140; x = 73; y = 75; for (int i = 0; i < 9; i++) { bx[i] = x; by[i] = y; x += 60; if (i % 3 == 2) { y += 15; x = 73; } } clearKeyQueue(); prefix.clear(); _currentCode.clear(); _currentWord.clear(); _wordNumber = 0; int mode = kModePre; bool needRefresh = true; for (;;) { if (needRefresh) { for (int i = 0; buttons[i]; i++) { int color1 = colors[i * 2]; int color2 = colors[i * 2 + 1]; if (i == 9 && !((mode != kModeAbc && _predictiveDictActLine && numMatchingWords > 1) || (mode == kModeAbc && _currentWord.size() && _currentWord.lastChar() != ' '))) { // Next color2 = 7; } // needs fixing, or remove it! bool _addIsActive = false; // FIXME: word adding is not implemented if (i == 10 && !_addIsActive) { // Add color2 = 7; } if (i == 14) { _gfx->drawDefaultStyleButton(bx[i], by[i], modes[mode], i == active, 0, color1, color2); } else { _gfx->drawDefaultStyleButton(bx[i], by[i], buttons[i], i == active, 0, color1, color2); } } Common::strlcpy(temp, prefix.c_str(), sizeof(temp)); Common::strlcat(temp, _currentWord.c_str(), sizeof(temp)); for (int i = prefix.size() + _currentCode.size(); i < MAXWORDLEN; i++) temp[i] = ' '; temp[MAXWORDLEN] = 0; printText(temp, 0, 8, 7, MAXWORDLEN, 15, 0); _gfx->flushBlock(62, 54, 249, 66); if (active >= 0 && !navigationwithkeys) { // provide visual feedback only when not navigating with the arrows // so that the user can see the active button. active = -1; needRefresh = true; } else needRefresh = false; _gfx->doUpdate(); } pollTimer(); key = doPollKeyboard(); processkey = false; switch (key) { case KEY_ENTER: if (navigationwithkeys) { // when the user has utilized arrow key navigation, // interpret enter as 'click' on the active button active = lastactive; } else { // else it is a shortcut for 'Ok' active = 13; } processkey = true; break; case KEY_ESCAPE: rc = false; goto getout; case BUTTON_LEFT: navigationwithkeys = false; for (int i = 0; buttons[i]; i++) { if (_gfx->testButton(bx[i], by[i], buttons[i])) { active = i; processkey = true; break; } } break; case KEY_BACKSPACE: active = 11; processkey = true; break; case '#': active = 9; processkey = true; break; case '*': active = 14; processkey = true; break; case 0x09: // Tab navigationwithkeys = true; debugC(3, kDebugLevelText, "Focus change"); lastactive = active = lastactive + 1; active %= ARRAYSIZE(buttons) - 1; needRefresh = true; break; case KEY_LEFT: navigationwithkeys = true; if (lastactive == 0 || lastactive == 3 || lastactive == 6) active = lastactive + 2; else if (lastactive == 9) active = 15; else if (lastactive == 11) active = 11; else if (lastactive == 12) active = 13; else if (lastactive == 14) active = 10; else active = lastactive - 1; lastactive = active; needRefresh = true; break; case KEY_RIGHT: navigationwithkeys = true; if (lastactive == 2 || lastactive == 5 || lastactive == 8) active = lastactive - 2; else if (lastactive == 10) active = 14; else if (lastactive == 11) active = 11; else if (lastactive == 13) active = 12; else if (lastactive == 15) active = 9; else active = lastactive + 1; lastactive = active; needRefresh = true; break; case KEY_UP: navigationwithkeys = true; if (lastactive <= 2) active = 11; else if (lastactive == 9 || lastactive == 10) active = lastactive - 2; else if (lastactive == 11) active = 13; else if (lastactive == 14) active = 8; else if (lastactive == 15) active = 6; else active = lastactive - 3; lastactive = active; needRefresh = true; break; case KEY_DOWN: navigationwithkeys = true; if (lastactive == 6) active = 15; else if (lastactive == 7 || lastactive == 8) active = lastactive + 2; else if (lastactive == 11) active = 0; else if (lastactive == 12 || lastactive == 13) active = 11; else if (lastactive == 14 || lastactive == 15) active = lastactive - 2; else active = lastactive + 3; lastactive = active; needRefresh = true; break; default: // handle numeric buttons if (key >= '1' && key <= '9') { active = key - '1'; processkey = true; } else if (key == '0') { active = 15; processkey = true; } break; } if (processkey) { if (active >= 0) { needRefresh = true; lastactive = active; if (active == 15 && mode != kModeNum) { // Space // bring MRU word at the top of the list when changing words if (mode == kModePre && _predictiveDictActLine && numMatchingWords > 1 && _wordNumber != 0) bringWordtoTop(_predictiveDictActLine, _wordNumber); strncpy(temp, _currentWord.c_str(), _currentCode.size()); temp[_currentCode.size()] = 0; prefix += temp; prefix += " "; _currentCode.clear(); _currentWord.clear(); numMatchingWords = 0; memset(repeatcount, 0, sizeof(repeatcount)); } else if (active < 9 || active == 11 || active == 15) { // number or backspace if (active == 11) { // backspace if (_currentCode.size()) { repeatcount[_currentCode.size() - 1] = 0; _currentCode.deleteLastChar(); } else { if (prefix.size()) prefix.deleteLastChar(); } } else if (prefix.size() + _currentCode.size() < MAXWORDLEN - 1) { // don't overflow the dialog line if (active == 15) { // zero _currentCode += buttonStr[9]; } else { _currentCode += buttonStr[active]; } } switch (mode) { case kModeNum: _currentWord = _currentCode; break; case kModePre: if (!matchWord() && _currentCode.size()) { _currentCode.deleteLastChar(); matchWord(); } numMatchingWords = countWordsInString(_predictiveDictActLine); break; case kModeAbc: for (x = 0; x < _currentCode.size(); x++) if (_currentCode[x] >= '1') temp[x] = buttons[_currentCode[x] - '1'][3 + repeatcount[x]]; temp[_currentCode.size()] = 0; _currentWord = temp; } } else if (active == 9) { // next if (mode == kModePre) { if (_predictiveDictActLine && numMatchingWords > 1) { _wordNumber = (_wordNumber + 1) % numMatchingWords; char tmp[MAXLINELEN]; strncpy(tmp, _predictiveDictActLine, MAXLINELEN); tmp[MAXLINELEN - 1] = 0; char *tok = strtok(tmp, " "); for (uint8 i = 0; i <= _wordNumber; i++) tok = strtok(NULL, " "); _currentWord = Common::String(tok, _currentCode.size()); } } else if (mode == kModeAbc){ x = _currentCode.size(); if (x) { if (_currentCode.lastChar() == '1' || _currentCode.lastChar() == '7' || _currentCode.lastChar() == '9') repeatcount[x - 1] = (repeatcount[x - 1] + 1) % 4; else repeatcount[x - 1] = (repeatcount[x - 1] + 1) % 3; if (_currentCode.lastChar() >= '1') _currentWord.setChar(buttons[_currentCode[x - 1] - '1'][3 + repeatcount[x - 1]], x-1); } } } else if (active == 10) { // add debug(0, "add"); } else if (active == 13) { // Ok // bring MRU word at the top of the list when ok'ed out of the dialog if (mode == kModePre && _predictiveDictActLine && numMatchingWords > 1 && _wordNumber != 0) bringWordtoTop(_predictiveDictActLine, _wordNumber); rc = true; goto press; } else if (active == 14) { // Mode mode++; if (mode > kModeAbc) mode = kModePre; // truncate current input at mode change strncpy(temp, _currentWord.c_str(), _currentCode.size()); temp[_currentCode.size()] = 0; prefix += temp; _currentCode.clear(); _currentWord.clear(); memset(repeatcount, 0, sizeof(repeatcount)); } else { goto press; } } } } press: Common::strlcpy(_predictiveResult, prefix.c_str(), sizeof(_predictiveResult)); Common::strlcat(_predictiveResult, _currentWord.c_str(), sizeof(_predictiveResult)); getout: // if another window was shown, bring it up again if (!tmpwindow.active) closeWindow(); else { _gfx->restoreBlock(_game.window.x1, _game.window.y1, _game.window.x2, _game.window.y2, _game.window.buffer); free(_game.window.buffer); memcpy(&(_game.window), &tmpwindow, sizeof(AgiBlock)); _gfx->doUpdate(); } _system->setFeatureState(OSystem::kFeatureDisableKeyFiltering, false); _predictiveDialogRunning = false; return rc; }
/** * Display a message box with buttons. * This function displays the specified message in a text box * centered in the screen and waits until a button is pressed. * @param p The text to be displayed * @param b NULL-terminated list of button labels */ int AgiEngine::selectionBox(const char *m, const char **b) { int numButtons = 0; int x, y, i, s; int key, active = 0; int rc = -1; int bx[5], by[5]; _noSaveLoadAllowed = true; _sprites->eraseBoth(); blitTextbox(m, -1, -1, -1); x = _game.window.x1 + 5 * CHAR_COLS / 2; y = _game.window.y2 - 5 * CHAR_LINES / 2; s = _game.window.x2 - _game.window.x1 + 1 - 5 * CHAR_COLS; debugC(3, kDebugLevelText, "selectionBox(): s = %d", s); // Automatically position buttons for (i = 0; b[i]; i++) { numButtons++; s -= CHAR_COLS * strlen(b[i]); } if (i > 1) { debugC(3, kDebugLevelText, "selectionBox(): s / %d = %d", i - 1, s / (i - 1)); s /= (i - 1); } else { x += s / 2; } for (i = 0; b[i]; i++) { bx[i] = x; by[i] = y; x += CHAR_COLS * strlen(b[i]) + s; } _sprites->blitBoth(); clearKeyQueue(); AllowSyntheticEvents on(this); debugC(4, kDebugLevelText, "selectionBox(): waiting..."); while (!(shouldQuit() || _restartGame)) { for (i = 0; b[i]; i++) _gfx->drawCurrentStyleButton(bx[i], by[i], b[i], i == active, false, i == 0); pollTimer(); key = doPollKeyboard(); switch (key) { case KEY_ENTER: rc = active; goto press; case KEY_ESCAPE: rc = -1; goto getout; case KEY_RIGHT: active++; if (active >= numButtons) active = 0; break; case KEY_LEFT: active--; if (active < 0) active = numButtons - 1; break; case BUTTON_LEFT: for (i = 0; b[i]; i++) { if (_gfx->testButton(bx[i], by[i], b[i])) { rc = active = i; goto press; } } break; case 0x09: // Tab debugC(3, kDebugLevelText, "selectionBox(): Focus change"); active++; active %= i; break; } _gfx->doUpdate(); } press: debugC(4, kDebugLevelText, "selectionBox(): Button pressed: %d", rc); getout: closeWindow(); debugC(2, kDebugLevelText, "selectionBox(): Result = %d", rc); _noSaveLoadAllowed = false; return rc; }
// If main_cycle returns false, don't process more events! int AgiEngine::mainCycle() { unsigned int key, kascii; VtEntry *v = &_game.viewTable[0]; pollTimer(); updateTimer(); key = doPollKeyboard(); // In AGI Mouse emulation mode we must update the mouse-related // vars in every interpreter cycle. // // We run AGIMOUSE always as a side effect if (getFeatures() & GF_AGIMOUSE || true) { _game.vars[28] = _mouse.x / 2; _game.vars[29] = _mouse.y; } if (key == KEY_PRIORITY) { _sprites->eraseBoth(); _debug.priority = !_debug.priority; _picture->showPic(); _sprites->blitBoth(); _sprites->commitBoth(); key = 0; } if (key == KEY_STATUSLN) { _debug.statusline = !_debug.statusline; writeStatus(); key = 0; } // Click-to-walk mouse interface if (_game.playerControl && v->flags & ADJ_EGO_XY) { int toX = v->parm1; int toY = v->parm2; // AGI Mouse games use ego's sprite's bottom left corner for mouse walking target. // Amiga games use ego's sprite's bottom center for mouse walking target. // TODO: Check what Atari ST AGI and Apple IIGS AGI use for mouse walking target. if (getPlatform() == Common::kPlatformAmiga) toX -= (v->xSize / 2); // Center ego's sprite horizontally // Adjust ego's sprite's mouse walking target position (These parameters are // controlled with the adj.ego.move.to.x.y-command). Note that these values rely // on the horizontal centering of the ego's sprite at least on the Amiga platform. toX += _game.adjMouseX; toY += _game.adjMouseY; v->direction = getDirection(v->xPos, v->yPos, toX, toY, v->stepSize); if (v->direction == 0) inDestination(v); } kascii = KEY_ASCII(key); if (kascii) setvar(vKey, kascii); process_key: switch (_game.inputMode) { case INPUT_NORMAL: if (!handleController(key)) { if (key == 0 || !_game.inputEnabled) break; handleKeys(key); // if ESC pressed, activate menu before // accept.input from the interpreter cycle // sets the input mode to normal again // (closes: #540856) if (key == KEY_ESCAPE) { key = 0; goto process_key; } // commented out to close Sarien bug #438872 //if (key) // _game.keypress = key; } break; case INPUT_GETSTRING: handleController(key); handleGetstring(key); setvar(vKey, 0); // clear ENTER key break; case INPUT_MENU: _menu->keyhandler(key); _gfx->doUpdate(); return false; case INPUT_NONE: handleController(key); if (key) _game.keypress = key; break; } _gfx->doUpdate(); if (_game.msgBoxTicks > 0) _game.msgBoxTicks--; return true; }
void CYSFReflector::run() { bool ret = m_conf.read(); if (!ret) { ::fprintf(stderr, "YSFRefector: cannot read the .ini file\n"); return; } ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel()); if (!ret) { ::fprintf(stderr, "YSFReflector: unable to open the log file\n"); return; } #if !defined(_WIN32) && !defined(_WIN64) bool m_daemon = m_conf.getDaemon(); if (m_daemon) { // Create new process pid_t pid = ::fork(); if (pid == -1) { ::LogWarning("Couldn't fork() , exiting"); return; } else if (pid != 0) exit(EXIT_SUCCESS); // Create new session and process group if (::setsid() == -1) { ::LogWarning("Couldn't setsid(), exiting"); return; } // Set the working directory to the root directory if (::chdir("/") == -1) { ::LogWarning("Couldn't cd /, exiting"); return; } ::close(STDIN_FILENO); ::close(STDOUT_FILENO); ::close(STDERR_FILENO); //If we are currently root... if (getuid() == 0) { struct passwd* user = ::getpwnam("mmdvm"); if (user == NULL) { ::LogError("Could not get the mmdvm user, exiting"); return; } uid_t mmdvm_uid = user->pw_uid; gid_t mmdvm_gid = user->pw_gid; //Set user and group ID's to mmdvm:mmdvm if (setgid(mmdvm_gid) != 0) { ::LogWarning("Could not set mmdvm GID, exiting"); return; } if (setuid(mmdvm_uid) != 0) { ::LogWarning("Could not set mmdvm UID, exiting"); return; } //Double check it worked (AKA Paranoia) if (setuid(0) != -1) { ::LogWarning("It's possible to regain root - something is wrong!, exiting"); return; } } } #endif CNetwork network(m_conf.getNetworkPort(), m_conf.getName(), m_conf.getDescription(), m_conf.getNetworkDebug()); ret = network.open(); if (!ret) return; CStopWatch stopWatch; stopWatch.start(); CTimer dumpTimer(1000U, 120U); dumpTimer.start(); CTimer pollTimer(1000U, 5U); pollTimer.start(); LogMessage("Starting YSFReflector-%s", VERSION); CTimer watchdogTimer(1000U, 0U, 1500U); unsigned char tag[YSF_CALLSIGN_LENGTH]; unsigned char src[YSF_CALLSIGN_LENGTH]; unsigned char dst[YSF_CALLSIGN_LENGTH]; for (;;) { unsigned char buffer[200U]; unsigned int len = network.readData(buffer); if (len > 0U) { if (!watchdogTimer.isRunning()) { ::memcpy(tag, buffer + 4U, YSF_CALLSIGN_LENGTH); if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0) ::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH); else ::memcpy(src, "??????????", YSF_CALLSIGN_LENGTH); if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0) ::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH); else ::memcpy(dst, "??????????", YSF_CALLSIGN_LENGTH); LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U); } else { if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) { bool changed = false; if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(src, "??????????", YSF_CALLSIGN_LENGTH) == 0) { ::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH); changed = true; } if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(dst, "??????????", YSF_CALLSIGN_LENGTH) == 0) { ::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH); changed = true; } if (changed) LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U); } } // Only accept transmission from an already accepted repeater if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) { watchdogTimer.start(); std::string callsign = std::string((char*)(buffer + 4U), YSF_CALLSIGN_LENGTH); CYSFRepeater* rpt = findRepeater(callsign); if (rpt != NULL) { for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) { if ((*it)->m_callsign != callsign) network.writeData(buffer, (*it)->m_address, (*it)->m_port); } } if ((buffer[34U] & 0x01U) == 0x01U) { LogMessage("Received end of transmission"); watchdogTimer.stop(); } } } // Refresh/add repeaters based on their polls std::string callsign; in_addr address; unsigned int port; bool ret = network.readPoll(callsign, address, port); if (ret) { CYSFRepeater* rpt = findRepeater(callsign); if (rpt == NULL) { LogMessage("Adding %s", callsign.c_str()); rpt = new CYSFRepeater; rpt->m_timer.start(); rpt->m_callsign = callsign; rpt->m_address = address; rpt->m_port = port; m_repeaters.push_back(rpt); network.setCount(m_repeaters.size()); } else { rpt->m_timer.start(); rpt->m_address = address; rpt->m_port = port; } } unsigned int ms = stopWatch.elapsed(); stopWatch.start(); network.clock(ms); pollTimer.clock(ms); if (pollTimer.hasExpired()) { for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) network.writePoll((*it)->m_address, (*it)->m_port); pollTimer.start(); } // Remove any repeaters that haven't reported for a while for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) (*it)->m_timer.clock(ms); for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) { if ((*it)->m_timer.hasExpired()) { LogMessage("Removing %s", (*it)->m_callsign.c_str()); m_repeaters.erase(it); network.setCount(m_repeaters.size()); break; } } watchdogTimer.clock(ms); if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) { LogMessage("Network watchdog has expired"); watchdogTimer.stop(); } dumpTimer.clock(ms); if (dumpTimer.hasExpired()) { dumpRepeaters(); dumpTimer.start(); } if (ms < 5U) { #if defined(_WIN32) || defined(_WIN64) ::Sleep(5UL); // 5ms #else ::usleep(5000); // 5ms #endif } } network.close(); ::LogFinalise(); }
int AgiEngine::selectSlot() { int i, key, active = 0; int rc = -1; int hm = 1, vm = 3; // box margins int xmin, xmax, slotClicked; char desc[NUM_VISIBLE_SLOTS][40]; int textCenter, buttonLength, buttonX[2], buttonY; const char *buttonText[] = { " OK ", "Cancel", NULL }; _noSaveLoadAllowed = true; for (i = 0; i < NUM_VISIBLE_SLOTS; i++) { getSavegameDescription(_firstSlot + i, desc[i]); } textCenter = GFX_WIDTH / CHAR_LINES / 2; buttonLength = 6; buttonX[0] = (textCenter - 3 * buttonLength / 2) * CHAR_COLS; buttonX[1] = (textCenter + buttonLength / 2) * CHAR_COLS; buttonY = (vm + 17) * CHAR_LINES; for (i = 0; i < 2; i++) _gfx->drawCurrentStyleButton(buttonX[i], buttonY, buttonText[i], false, false, i == 0); AllowSyntheticEvents on(this); int oldFirstSlot = _firstSlot + 1; int oldActive = active + 1; while (!(shouldQuit() || _restartGame)) { int sbPos = 0; // Use the extreme scrollbar positions only if the extreme // slots are in sight. (We have to calculate this even if we // don't redraw the save slots, because it's also used for // clicking in the scrollbar. if (_firstSlot == 0) sbPos = 1; else if (_firstSlot == NUM_SLOTS - NUM_VISIBLE_SLOTS) sbPos = NUM_VISIBLE_SLOTS - 2; else { sbPos = 2 + (_firstSlot * (NUM_VISIBLE_SLOTS - 4)) / (NUM_SLOTS - NUM_VISIBLE_SLOTS - 1); if (sbPos >= NUM_VISIBLE_SLOTS - 3) sbPos = NUM_VISIBLE_SLOTS - 3; } if (oldFirstSlot != _firstSlot || oldActive != active) { char dstr[64]; for (i = 0; i < NUM_VISIBLE_SLOTS; i++) { sprintf(dstr, "[%2d. %-28.28s]", i + _firstSlot, desc[i]); printText(dstr, 0, hm + 1, vm + 4 + i, (40 - 2 * hm) - 1, i == active ? MSG_BOX_COLOR : MSG_BOX_TEXT, i == active ? MSG_BOX_TEXT : MSG_BOX_COLOR); } char upArrow[] = "^"; char downArrow[] = "v"; char scrollBar[] = " "; for (i = 1; i < NUM_VISIBLE_SLOTS - 1; i++) printText(scrollBar, 35, hm + 1, vm + 4 + i, 1, MSG_BOX_COLOR, 7, true); printText(upArrow, 35, hm + 1, vm + 4, 1, 8, 7); printText(downArrow, 35, hm + 1, vm + 4 + NUM_VISIBLE_SLOTS - 1, 1, 8, 7); printText(scrollBar, 35, hm + 1, vm + 4 + sbPos, 1, MSG_BOX_COLOR, MSG_BOX_TEXT); oldActive = active; oldFirstSlot = _firstSlot; } pollTimer(); key = doPollKeyboard(); // It may happen that somebody will open GMM while // this dialog is open, and load a game // We are processing it here, effectively jumping // out of the dead loop if (getflag(fRestoreJustRan)) { rc = -2; goto getout; } switch (key) { case KEY_ENTER: rc = active; strncpy(_game.strings[MAX_STRINGS], desc[i], MAX_STRINGLEN); goto press; case KEY_ESCAPE: rc = -1; goto getout; case BUTTON_LEFT: if (_gfx->testButton(buttonX[0], buttonY, buttonText[0])) { rc = active; strncpy(_game.strings[MAX_STRINGS], desc[i], MAX_STRINGLEN); goto press; } if (_gfx->testButton(buttonX[1], buttonY, buttonText[1])) { rc = -1; goto getout; } slotClicked = ((int)_mouse.y - 1) / CHAR_COLS - (vm + 4); xmin = (hm + 1) * CHAR_COLS; xmax = xmin + CHAR_COLS * 34; if ((int)_mouse.x >= xmin && (int)_mouse.x <= xmax) { if (slotClicked >= 0 && slotClicked < NUM_VISIBLE_SLOTS) active = slotClicked; } xmin = (hm + 36) * CHAR_COLS; xmax = xmin + CHAR_COLS; if ((int)_mouse.x >= xmin && (int)_mouse.x <= xmax) { if (slotClicked >= 0 && slotClicked < NUM_VISIBLE_SLOTS) { if (slotClicked == 0) keyEnqueue(KEY_UP); else if (slotClicked == NUM_VISIBLE_SLOTS - 1) keyEnqueue(KEY_DOWN); else if (slotClicked < sbPos) keyEnqueue(KEY_UP_RIGHT); else if (slotClicked > sbPos) keyEnqueue(KEY_DOWN_RIGHT); } } break; case KEY_DOWN: active++; if (active >= NUM_VISIBLE_SLOTS) { if (_firstSlot + NUM_VISIBLE_SLOTS < NUM_SLOTS) { _firstSlot++; for (i = 1; i < NUM_VISIBLE_SLOTS; i++) memcpy(desc[i - 1], desc[i], sizeof(desc[0])); getSavegameDescription(_firstSlot + NUM_VISIBLE_SLOTS - 1, desc[NUM_VISIBLE_SLOTS - 1]); } active = NUM_VISIBLE_SLOTS - 1; } break; case KEY_UP: active--; if (active < 0) { active = 0; if (_firstSlot > 0) { _firstSlot--; for (i = NUM_VISIBLE_SLOTS - 1; i > 0; i--) memcpy(desc[i], desc[i - 1], sizeof(desc[0])); getSavegameDescription(_firstSlot, desc[0]); } } break; // Page Up/Down and mouse wheel scrolling all leave 'active' // unchanged so that a visible slot will remain selected. case WHEEL_DOWN: if (_firstSlot < NUM_SLOTS - NUM_VISIBLE_SLOTS) { _firstSlot++; for (i = 1; i < NUM_VISIBLE_SLOTS; i++) memcpy(desc[i - 1], desc[i], sizeof(desc[0])); getSavegameDescription(_firstSlot + NUM_VISIBLE_SLOTS - 1, desc[NUM_VISIBLE_SLOTS - 1]); } break; case WHEEL_UP: if (_firstSlot > 0) { _firstSlot--; for (i = NUM_VISIBLE_SLOTS - 1; i > 0; i--) memcpy(desc[i], desc[i - 1], sizeof(desc[0])); getSavegameDescription(_firstSlot, desc[0]); } break; case KEY_DOWN_RIGHT: // This is probably triggered by Page Down. _firstSlot += NUM_VISIBLE_SLOTS; if (_firstSlot > NUM_SLOTS - NUM_VISIBLE_SLOTS) { _firstSlot = NUM_SLOTS - NUM_VISIBLE_SLOTS; } for (i = 0; i < NUM_VISIBLE_SLOTS; i++) getSavegameDescription(_firstSlot + i, desc[i]); break; case KEY_UP_RIGHT: // This is probably triggered by Page Up. _firstSlot -= NUM_VISIBLE_SLOTS; if (_firstSlot < 0) { _firstSlot = 0; } for (i = 0; i < NUM_VISIBLE_SLOTS; i++) getSavegameDescription(_firstSlot + i, desc[i]); break; } _gfx->doUpdate(); } press: debugC(8, kDebugLevelMain | kDebugLevelInput, "Button pressed: %d", rc); getout: closeWindow(); _noSaveLoadAllowed = false; return rc; }