void inputUpdate() { inputPoll(); for(int i = 0; i < 32; i++) { if(!inputIsHeld((Button) (1 << i))) { keysForceReleased &= ~(1 << i); } } if(accelPadMode && inputIsPressed(BUTTON_TOUCH) && inputGetTouch().x <= gputGetStringWidth("Exit", 8) && inputGetTouch().y <= gputGetStringHeight("Exit", 8)) { inputKeyRelease(BUTTON_TOUCH); accelPadMode = false; consoleClear(); } }
int main(int argc, char **argv) { if(!platformInit(argc)) { return 0; } const std::string title = "CTRX SD Explorer v0.8.7"; const u64 tapDelay = 240; bool launcher = platformHasLauncher(); bool exit = false; Mode mode = M_BROWSER; u64 inputRHoldTime = 0; u64 inputXHoldTime = 0; u64 inputYHoldTime = 0; std::string currentDir = ""; SelectableElement currentFile = { "", "" }; std::set<SelectableElement*>* markedElements = NULL; std::vector<SelectableElement> clipboard; u64 freeSpace = fsGetFreeSpace(SD); u32 dummySize = (u32) -1; int dummyContent = 0x00; u32 hvStoredOffset = (u32) -1; auto processAction = [&](Action action, bool &updateList, bool &resetCursor) { const std::string alphabet = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz(){}[]'`^,~!@#$%&0123456789=+-_."; switch(action) { case A_DELETE: { if((*markedElements).empty()) { if(currentFile.name.compare("..") != 0) { std::string confirmMsg = "Delete \"" + uiTruncateString(currentFile.name, 24, -8) + "\"?" + "\n"; if(uiPrompt(TOP_SCREEN, confirmMsg, true)) { if(!fsPathDelete(currentFile.id)) { uiErrorPrompt(TOP_SCREEN, "Deleting", currentFile.name, true, false); } } freeSpace = fsGetFreeSpace(SD); updateList = true; resetCursor = false; } } else { int failCount = 0; std::stringstream object; if((*markedElements).size() == 1) { object << "\"" << uiTruncateString((**((*markedElements).begin())).name, 24, -8) << "\""; } else object << (*markedElements).size() << " paths"; std::string confirmMsg = "Delete " + object.str() + "?" + "\n"; if(uiPrompt(TOP_SCREEN, confirmMsg, true)) { for(std::set<SelectableElement*>::iterator it = (*markedElements).begin(); it != (*markedElements).end(); it++) { if(!fsPathDelete((**it).id)) { std::set<SelectableElement*>::iterator next = it; next++; failCount++; if (!uiErrorPrompt(TOP_SCREEN, "Deleting", (**it).name, true, next != (*markedElements).end())) break; } } if((failCount > 0) && ((*markedElements).size() > 1)) { std::stringstream errorMsg; errorMsg << "Deleted" << ((*markedElements).size() - failCount) << " of " << (*markedElements).size() << " paths!" << "\n"; uiPrompt(TOP_SCREEN, errorMsg.str(), false); } freeSpace = fsGetFreeSpace(SD); (*markedElements).clear(); updateList = true; resetCursor = false; } } break; } case A_RENAME: { if(currentFile.name.compare("..") != 0) { // RENAME std::string confirmMsg = "Rename \"" + uiTruncateString(currentFile.name, 24, -8) + "\"?\nEnter new name below:\n"; std::string name = uiStringInput(TOP_SCREEN, currentFile.name, alphabet, confirmMsg); if(!name.empty()) { if(!fsPathRename(currentFile.id, currentDir + "/" + name)) { uiErrorPrompt(TOP_SCREEN, "Renaming", currentFile.name, true, false); } else { updateList = true; resetCursor = false; } } } break; } case A_COPY: case A_MOVE: { if(!clipboard.empty()) { int failCount = 0; std::stringstream object; if(clipboard.size() == 1) object << "\"" << uiTruncateString(clipboard.at(0).name, 18, -8) << "\""; else object << clipboard.size() << " paths"; std::string confirmMsg = ((action == A_COPY) ? "Copy " : "Move ") + object.str() + " to this destination?" + "\n"; if(uiPrompt(TOP_SCREEN, confirmMsg, true)) { bool fail = false; for(std::vector<SelectableElement>::iterator it = clipboard.begin(); it != clipboard.end(); it++) { const std::string dest = (currentDir.compare("/") == 0) ? "/" + (*it).name : currentDir + "/" + (*it).name; fail = (action == A_COPY) ? !fsPathCopy((*it).id, dest, true) : !fsPathRename((*it).id, dest); if(fail) { failCount++; std::string operationStr = (action == A_COPY) ? "Copying" : "Moving"; if (!uiErrorPrompt(TOP_SCREEN, operationStr, (*it).name, true, it + 1 != clipboard.end())) break; } } if((failCount > 0) && (clipboard.size() > 1)) { std::stringstream errorMsg; errorMsg << ((action == A_COPY) ? "Copied " : "Moved "); errorMsg << (clipboard.size() - failCount) << " of " << clipboard.size() << " paths!" << "\n"; uiPrompt(TOP_SCREEN, errorMsg.str(), false); } freeSpace = fsGetFreeSpace(SD); clipboard.clear(); updateList = true; resetCursor = false; } } break; } case A_CREATE_DIR: { std::string confirmMsg = "Create new folder here?\nEnter name below:\n"; std::string name = uiStringInput(TOP_SCREEN, "newdir", alphabet, confirmMsg); if(!name.empty()) { if(!fsCreateDir(currentDir + "/" + name)) { uiErrorPrompt(TOP_SCREEN, "Create Folder", name, true, false); } updateList = true; resetCursor = false; } break; } case A_CREATE_DUMMY: { std::stringstream object; if(dummySize == 0) object << "zero byte dummy file"; else object << uiFormatBytes(dummySize) << " dummy file"; std::string confirmMsg = "Generate " + object.str() + " here?\nEnter name below:\n"; std::string name = uiStringInput(TOP_SCREEN, "dummy.bin", alphabet, confirmMsg); if(!name.empty()) { if(!fsCreateDummyFile(currentDir + "/" + name, dummySize, dummyContent, true)) { uiErrorPrompt(TOP_SCREEN, "Generating", name, true, false); } freeSpace = fsGetFreeSpace(SD); updateList = true; resetCursor = false; } break; } default: break; } }; auto instructionBlockBrowser = [&]() { std::stringstream stream; stream << "L - MARK files (use with " << (char) 0x018 << (char) 0x19 << (char) 0x1A << (char) 0x1B << ")" << "\n"; if(dummySize == (u32) -1) stream << "R - [t] CREATE folder / [h] file" << "\n"; else { stream << "R - [r] GENERATE " << ((dummySize == 0) ? "zero byte" : uiFormatBytes(dummySize)) << " dummy file"; if(dummySize > 0) { if(dummyContent > 0xFF) stream << " (XX)"; else stream << " (" << std::uppercase << std::setfill('0') << std::hex << std::setw(2) << (dummyContent & 0xFF) << std::nouppercase << ")"; } stream << "\n"; } stream << "X - [t] DELETE / [h] RENAME selected" << "\n"; if(clipboard.empty()) stream << "Y - COPY/MOVE selected " << (((*markedElements).size() > 1) ? "files" : "file") << "\n"; else stream << "Y - [t] COPY / [h] MOVE to this folder" << "\n"; if(clipboard.size() > 0) stream << "SELECT - Clear Clipboard" << "\n"; return stream.str(); }; auto instructionBlockHexViewer = [&]() { std::stringstream stream; stream << std::setfill('0'); stream << "L/R - Move to beginning / end" << "\n"; stream << "X - Go to ... ([t] hex / [h] dec)" << "\n"; if(hvStoredOffset != (u32) -1) { stream << "Y - Return to offset "; stream << std::hex << std::uppercase << std::setw(8) << hvStoredOffset << std::nouppercase << "\n"; } stream << "B - Exit to file browser" << "\n"; return stream.str(); }; auto onLoopDisplay = [&]() { gpuViewport(TOP_SCREEN, 0, 0, TOP_WIDTH, TOP_HEIGHT); gputOrtho(0, TOP_WIDTH, 0, TOP_HEIGHT, -1, 1); gpuClear(); std::string str; u32 screenWidth = gpuGetViewportWidth(); u32 screenHeight = gpuGetViewportHeight(); u32 vpos0 = screenHeight - 1 - 12 - 4; u32 vpos1 = vpos0 - 11; u32 cbDisplay = 10; u8 gr = 0x9F; // TOP BAR -> CURRENT DIRECTORY & FREE SPACE uiDrawRectangle(0, (screenHeight - 1) - 12, screenWidth, 12); str = uiTruncateString(currentDir, 36, 0); // current directory gputDrawString(str, 0, (screenHeight - 1) - 10, 8, 8, 0x00, 0x00, 0x00); str = uiFormatBytes(freeSpace) + " free"; // free space gputDrawString(str, (screenWidth - 1) - gputGetStringWidth(str, 8), (screenHeight - 1) - 10, 8, 8, 0x00, 0x00, 0x00); // CURRENT FILE DETAILS if(currentFile.name.compare("..") != 0) { str = "[SELECTED]"; gputDrawString(str, 0, vpos0 - 8, 8, 8); str = uiTruncateString(currentFile.name, 22, -8); gputDrawString(str, 0, vpos1 - 8, 8, 8); u32 vpos = vpos1 - 9; for(std::vector<std::string>::iterator it = currentFile.details.begin(); it != currentFile.details.end(); it++, vpos -= 9) { gputDrawString(*it, 0, vpos - 8, 8, 8, gr, gr, gr); } } // CLIPBOARD DETAILS if(clipboard.size() > 0) { std::stringstream stream; stream << "[CLIPBOARD(" << clipboard.size() << ")]"; str = stream.str(); gputDrawString(str, (screenWidth - 1) - gputGetStringWidth(str, 8), vpos0 - 8, 8, 8); u32 vpos = vpos1; for(u32 i = 0; (i < clipboard.size()) && (i < cbDisplay); i++, vpos -= 9) { str = uiTruncateString(clipboard.at(i).name, 22, -8); gputDrawString(str, (screenWidth - 1) - gputGetStringWidth(str, 8), vpos - 8, 8, 8); } if(clipboard.size() > cbDisplay) { stream.str(""); stream << "(+ " << clipboard.size() - cbDisplay << " more files)"; str = stream.str(); gputDrawString(str, (screenWidth - 1) - gputGetStringWidth(str, 8), vpos - 8, 8, 8, gr, gr, gr); } else if(clipboard.size() == 1) { for(std::vector<std::string>::iterator it = clipboard.at(0).details.begin(); it != clipboard.at(0).details.end(); it++, vpos -= 9) { gputDrawString(*it, (screenWidth - 1) - gputGetStringWidth(*it, 8), vpos - 8, 8, 8, gr, gr, gr); } } } // INSTRUCTIONS BLOCK str = title + "\n" + ((mode == M_BROWSER) ? instructionBlockBrowser() : instructionBlockHexViewer()); if(launcher) str += "START - Exit to launcher\n"; gputDrawString(str, (screenWidth - 320) / 2, 4, 8, 8); gpuFlush(); gpuFlushBuffer(); return; }; auto onLoopBrowser = [&](bool &updateList, bool &resetCursor) { bool breakLoop = false; onLoopDisplay(); // START - EXIT TO HB LAUNCHER if(inputIsPressed(BUTTON_START) && launcher) { exit = true; return true; } // SELECT - CLEAR CLIPBOARD if(inputIsPressed(BUTTON_SELECT)) { clipboard.clear(); } // R - (TAP) CREATE DIRECTORY / (HOLD) GENERATE DUMMY FILE if(inputIsHeld(BUTTON_R) && (inputRHoldTime != (u64) -1)) { if(inputRHoldTime == 0) inputRHoldTime = platformGetTime(); else if(platformGetTime() - inputRHoldTime >= tapDelay) { const u64 scrollDelay = 120; u64 lastChangeTime = 0; dummySize = 0; dummyContent = 0x00; while(platformIsRunning() && inputIsHeld(BUTTON_R)) { if(inputIsHeld(BUTTON_DOWN) || inputIsHeld(BUTTON_UP) || inputIsHeld(BUTTON_LEFT) || inputIsHeld(BUTTON_RIGHT)) { if(lastChangeTime == 0 || platformGetTime() - lastChangeTime >= scrollDelay) { if(inputIsHeld(BUTTON_DOWN)) { dummyContent--; if(dummyContent < 0x00) dummyContent = 0x100; } if(inputIsHeld(BUTTON_UP)) { dummyContent++; if(dummyContent > 0x100) dummyContent = 0x00; } if(inputIsHeld(BUTTON_RIGHT) && (dummySize < 1 << 30)) { dummySize = (dummySize == 0) ? 1 : dummySize << 1; } if(inputIsHeld(BUTTON_LEFT) && (dummySize > 0)) { dummySize = (dummySize == 1) ? 0 : dummySize >> 1; } lastChangeTime = platformGetTime(); } } else if (lastChangeTime != 0) lastChangeTime = 0; onLoopDisplay(); gpuSwapBuffers(true); inputPoll(); } processAction(A_CREATE_DUMMY, updateList, resetCursor); inputRHoldTime = 0; dummySize = (u32) -1; } }
int inputGetMotionSensorX() { int accelX = accelPadMode ? (inputIsHeld(BUTTON_TOUCH) ? 160 - inputGetTouch().x : 0) : 0; return 2047 + accelX; }
int inputGetMotionSensorY() { int accelY = accelPadMode ? (inputIsHeld(BUTTON_TOUCH) ? 120 - inputGetTouch().y : 0) : 0; return 2047 + accelY; }
bool inputKeyHeld(int key) { return inputIsHeld((Button) key) && !(keysForceReleased & key); }