エディター作成に初挑戦です。元ネタはここ。
https://github.com/VolosR/KeyboardMF/blob/main/KeyboardMF/KeyboardMF.ino
前回紹介した開発ボード
上に作成しました。元ネタに手を加え、次のようにしました。
1.1024*600解像度を800*480に変更
2.UsbHost機能が使えないため「Tera Term」からのキー入力に
3.Dir(Ls)表示、エディタ画面が1画面固定だったのを、複数画面、スクロール可能に
4.キー機能の追加
これだけでも500行になってしまいました。さらに機能を加えたかったのですが、Qiitaでの投稿はかなり重くなるのでここまでかなと。ino本体が長いのでここまでとします。次がスケッチ本体です。前回の投稿にありますが「Matouch7.h」をスケッチと同じフォルダーに入れコンパイルしてください。詳しくはそちらを。ご利用は、計画的に。
070_KeyboardMF.ino
#include "Matouch7.h"
#include "SD.h"
#include <string>
#define SW 800
#define SH 480
#define TFT_BL 2
#define _LH 22
// microSD card standard connect
#define SPI_MOSI 11
#define SPI_MISO 13
#define SPI_SCK 12
#define SD_CS 10
LGFX lcd; // to use this including "Matouch7.h"
LGFX_Sprite spr0(&lcd);
LGFX_Sprite spr1(&lcd);
LGFX_Sprite spr2(&lcd);
LGFX_Sprite spr3(&lcd);
#define YELW TFT_YELLOW
#define NAVY 0x0008
#define fnLs 20 // display rows at dir files
#define maxLines 18 //20
String fileName = "*.txt, *.c, *.cpp";
String txt[100];
String spc[100];
uint8_t cuX[100];
uint8_t lineCount = 0;
bool mode = 0; // 0 is edit fileName, 1 is edit content
bool openMenu = false;
unsigned short modeColor[2] = { TFT_PURPLE, TFT_SILVER };
bool _drawLine = true; // displaying cursor in line or not
uint8_t line = 0; // present edit-line
uint8_t lastline = 0; // content lines
uint8_t lb = 0; // scroll base line
#define maxFiles 128 // Define maximum number of files to store
String fileNames[maxFiles]; // Array to store file names
uint8_t filesCount = 0;
uint8_t chosenFile = 0;
uint8_t fListPage = 0;
void resetAll() {
fileName = "*.*";
dispCurFname(fileName);
lcd.fillRect(2, 27, SW - 4, SH - 28, TFT_BLACK);
clearTexts();
}
void clearTexts() {
line = 0;
lastline = 2; // 2
lb = 0;
for (uint8_t i = 0; i < 100; i++) {
txt[i] = "";
spc[i] = '|';
cuX[i] = 0;
}
}
void listFilesInArray(const char* dirname) {
File root = SD.open(dirname);
filesCount = 0;
if (!root || !root.isDirectory()) {
Serial.println("Failed to open directory or not a directory");
return;
}
File file = root.openNextFile();
while (file) { // Store the file name in the array
if (filesCount < maxFiles) {
String fn = file.name();
fn.toLowerCase();
if (file.isDirectory()) fn = fn + '/';
fileNames[filesCount] = fn;
filesCount++; // Increment file counter
}
file = root.openNextFile(); // Move to the next file
}
}
void setup(void) {
clearTexts();
Serial.begin(115200);
Serial.println("Serial begin");
analogWrite(2, 210); // LCD on
lcd.begin();
lcd.setRotation(0);
lcd.fillScreen(0x0010);
lcd.fillRect(1, 26, SW - 2, SH - 26, 0x222222U);
lcd.setFont(&fonts::FreeMonoBold9pt7b); //AsciiFont8x16);
spr1.setFont(&fonts::FreeMonoBold9pt7b); //AsciiFont8x16);
spr0.setFont(&fonts::FreeMonoBold9pt7b); //AsciiFont8x16);
lcd.setTextColor(YELW);
lcd.drawString("FILE:", 8, 5);
FKey("F1", " DIR", 305, 1);
FKey("F2", " NEW", 405, 1);
FKey("F3", "Fi/Ed", 505, 1);
FKey("F4", "SAVE", 605, 1);
FKey("F5", "HELP", 705, 1);
spr0.setColorDepth(1);
spr0.createSprite(228, 22); // filename editbox
spr1.setColorDepth(4); // 16 colors pallet
spr1.createSprite(SW - 4, _LH);
spr1.setPaletteColor(2, TFT_LIGHTGRAY); // focused line background
spr1.setPaletteColor(3, TFT_MAGENTA); // cursor color
spr1.setPaletteColor(4, 0x00FF00U); // text color is GREEN
spr2.createSprite(SW - 4, _LH);
spr3.createSprite(SW - 4, 2 * _LH);
fileName = " *.txt ; *.c ; *.cpp";
dispCurFname(fileName);
if (!SD.begin(SD_CS, SPI, 48000000, "/sd")) {
Serial.println("Card Mount Failed");
return;
}
SD_Info();
}
void loop(void) {
if (mode == 0) {
lcd.drawRect(64, 0, 230, 24, modeColor[0]);
lcd.drawRect(1, 26, SW - 2, SH - 26, modeColor[1]);
} else {
lcd.drawRect(64, 0, 230, 24, modeColor[1]);
lcd.drawRect(1, 26, SW - 2, SH - 26, modeColor[0]);
}
while (Serial.available() == 0) { ; }
uint8_t intC = Serial.read();
String intS;
if (intC < ' ' || intC > '~') {
intS = (String)intC;
while (Serial.available()) {
uint8_t k = Serial.read();
intS = intS + (String)k;
}
Serial.printf("%c ; %s\n\r", intC, intS);
if (intS.equals("27") || intS.equals("277980")) { // ESC or F1
resetAll();
openMenu = true; // "Dir /"
listFilesInArray("/"); // store to fileNames[]
dispFiles(fListPage);
}
if (intS.equals("277981")) { //F2 New file
resetAll();
openMenu = false; // NEW
mode = 0; // edit file name
}
if (intS.equals("277982")) { //F3 switch edit fileneme/content
mode = !mode; // toggle filename or content
lcd.drawRect(64, 0, 230, 24, modeColor[mode]);
lcd.drawRect(1, 26, SW - 2, SH - 26, modeColor[!mode]);
}
/*
if (uint8_tS.equals("27914957126")) Serial.pruint8_tln("F8");
if (uint8_tS.equals("27915048126")) Serial.pruint8_tln("F9");
if (uint8_tS.equals("27915049126")) Serial.pruint8_tln("F10");
if (uint8_tS.equals("27915051126")) Serial.pruint8_tln("F11");
if (uint8_tS.equals("27915052126")) Serial.pruint8_tln("F12");
*/
}
if (openMenu) { // File-Choosing mode
if (intS.equals("27914953126")) { //F5 HELP
lcd.drawRect(64, 0, 230, 24, modeColor[1]);
lcd.fillRect(1, 26, SW - 2, SH - 26, 0x111111U);
lcd.setTextColor(TFT_WHITE);
lcd.drawString("UP : DIR previous file", 100, 50);
lcd.drawString("DOWN: DIR next file", 100, 80);
lcd.drawString("F6 : DIR previous page", 100, 110);
lcd.drawString("F7 : DIR next page", 100, 140);
lcd.drawString("ESC : DIR", 100, 170);
}
if (intS.equals("27914955126")) { // F6 previous file list
if (fListPage > 0) {
fListPage--;
chosenFile = fListPage * fnLs;
dispFiles(fListPage);
lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
dispCurFname(fileNames[chosenFile]);
}
}
if (intS.equals("27914956126")) { // F7 next file list
if (filesCount > fnLs * (fListPage + 1)) {
fListPage++;
chosenFile = fListPage * fnLs;
dispFiles(fListPage);
lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
dispCurFname(fileNames[chosenFile]);
}
}
if (intC == 13) { // RETURN to choose the file
resetAll();
lcd.fillRect(2, 27, SW - 4, SH - 28, TFT_BLACK);
openMenu = false;
fileName = fileNames[chosenFile];
dispCurFname(fileName);
openFile("/" + fileName); //String ff = "/" + fileName;
mode = 1; // editing content mode
drawFep();
}
if (intS.equals("279166")) { // DOWN at file choosing
if (chosenFile < filesCount - 1) {
lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, NAVY);
chosenFile++;
if ((chosenFile % fnLs) == 0) {
fListPage++;
dispFiles(fListPage);
}
lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
dispCurFname(fileNames[chosenFile]);
}
}
if (intS.equals("279165")) { // UP at file choosing
if (chosenFile > 0) {
lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, NAVY);
chosenFile--;
if (fListPage > 0 && chosenFile % fnLs == fnLs - 1) {
fListPage--;
dispFiles(fListPage);
}
lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
dispCurFname(fileNames[chosenFile]);
}
}
} else { // (openmenu == false) content-editing mode
if (mode == 0) { // at editing filename
if ('!' <= intC && intC <= '~') { // Ascii chara
fileName = fileName + String((char)intC);
}
if (intC == 8) { // BS
fileName = fileName.substring(0, fileName.length() - 1);
}
if (intC == 127) { // DEL
fileName = "*.txt/*.c/*.cpp";
}
dispCurFname(fileName);
} else { //(mode == 1) at Editing content textlines
if (intS.equals("277983")) saveFile(); // F4 Save file
if (intS.equals("279168")) { // LEFT
if (spc[line].length() > 1) {
cuX[line]--;
spc[line] = spc[line].substring(1, spc[line].length());
} else {
if ((line - lb) > 0) {
_drawLine = 0;
drawEditLine(line);
line--;
if (lb > 0) {
lb--;
for (uint8_t i = 0; i < maxLines; i++) {
_drawLine = 0;
drawEditLine(i + lb);
}
}
}
}
}
if (intS.equals("279167")) { // RIGHT
if (spc[line].length() <= txt[line].length()) {
cuX[line]++;
spc[line] = " " + spc[line];
} else { //if(spc[line].length() > txt[line].length())
if (line < lastline) {
_drawLine = 0;
drawEditLine(line);
line++;
spc[line] = "|";
cuX[line] = 0;
if ((line - lb) >= maxLines) {
lb++;
for (uint8_t i = 0; i < maxLines; i++) {
_drawLine = 0;
drawEditLine(i + lb);
}
}
}
}
}
if (' ' <= intC && intC <= '~') { // Ascii char
txt[line] = txt[line].substring(0, cuX[line])
+ (char)intC + txt[line].substring(cuX[line]);
spc[line] = " " + spc[line];
cuX[line]++;
}
if (intC == 9) { // TAB
txt[line] = txt[line].substring(0, cuX[line])
+ " " + txt[line].substring(cuX[line]);
spc[line] = " " + spc[line];
cuX[line] += 2;
}
if (intC == 8) { // BACKSPACE
if (txt[line].length() == 0) {
spr1.fillSprite(0);
spr1.pushSprite(3, 32 + ((line - lb) * _LH));
for (uint8_t i = line; i < lastline; i++) {
spc[i] = spc[i + 1];
txt[i] = txt[i + 1];
cuX[i] = cuX[i + 1];
_drawLine = 0;
drawEditLine(i);
}
spr1.fillSprite(0);
spr1.pushSprite(3, 32 + ((lastline - lb) * _LH));
lastline--;
if (line > 0) line--;
_drawLine = 1;
drawBlackEndline();
} else { // any word exists
txt[line] = txt[line].substring(0, cuX[line] - 1)
+ txt[line].substring(cuX[line]);
spc[line] = spc[line].substring(0, cuX[line] - 1) + '|';
cuX[line]--;
}
}
if (intS.equals("279165")) { // UP at Editing text
if ((line - lb) > 0) {
_drawLine = 0;
drawEditLine(line);
line--;
if (lb > 0) {
lb--;
for (uint8_t i = 0; i < maxLines; i++) {
_drawLine = 0;
drawEditLine(i + lb);
}
}
}
}
if (intS.equals("279166")) { // DOWN at editing
if (line < lastline) {
_drawLine = 0;
drawEditLine(line);
line++;
if ((line - lb) >= maxLines) {
lb++;
for (uint8_t i = 0; i < maxLines; i++) {
_drawLine = 0;
drawEditLine(i + lb);
}
}
}
}
if (intC == 13) { // RETURN at editing text
for (uint16_t i = lastline; i > line; i--) { // insert a new line
spc[i + 1] = spc[i];
txt[i + 1] = txt[i];
cuX[i + 1] = cuX[i];
_drawLine = 0;
drawEditLine(i + 1);
}
lastline++;
spc[line + 1] = spc[line];
txt[line + 1] = txt[line];
cuX[line + 1] = cuX[line];
_drawLine = 0;
drawEditLine(line + 1);
spc[line] = "|";
txt[line] = "";
cuX[line] = 0;
if ((line - lb) >= maxLines) {
lb++;
for (uint8_t i = 0; i < maxLines; i++) {
_drawLine = 0;
drawEditLine(i + lb);
}
}
}
_drawLine = 1;
drawEditLine(line);
drawBlackEndline();
drawFep();
}
}
}
void dispFiles(uint8_t page) {
lcd.fillRect(1, 26, 380, SH - 26, NAVY);
lcd.setTextColor(YELW);
for (uint8_t i = 0; i < fnLs; i++) {
if (i + page * fnLs < filesCount) {
char s[16];
sprintf(s, "%2d", i + page * fnLs);
lcd.drawString((String)s + ":" + fileNames[i + page * fnLs],
30, 35 + i * _LH);
}
}
lcd.fillRect(15, 38 + (chosenFile % fnLs) * _LH, 10, 10, YELW);
}
void drawEditLine(uint8_t ln) {
if (_drawLine) spr1.fillSprite(1); //フォーカス行の背景は少し明るく
else spr1.fillSprite(0);
spr1.setTextColor(2);
if (ln < 0) exit;
String n = (ln + 1 < 10) ? "0" : "";
spr1.drawString(n + String(ln + 1) + ">", 0, 4); // 行番号
spr1.setTextColor(3);
if (_drawLine) spr1.drawString(spc[ln], 36, 4); // "|"を先に表示
spr1.setTextColor(4);
spr1.drawString(txt[ln], 36, 4);
spr1.pushSprite(2, 32 + ((ln - lb) * _LH));
}
void drawBlackEndline() {
spr2.fillSprite(0);
spr2.pushSprite(2, 32 + (maxLines * _LH));
}
void drawFep() {
spr3.fillSprite(0x3804);
spr3.pushSprite(2, SH - 2 * _LH);
}
void dispCurFname(String fn) {
spr0.fillSprite(0);
spr0.setTextColor(1);
spr0.drawString(fn, 2, 3);
spr0.pushSprite(65, 1);
}
void FKey(String s1, String s2, uint16_t x, uint16_t y) {
lcd.fillRect(x, y, 90, 22, TFT_SILVER);
lcd.setTextColor(TFT_RED);
lcd.drawString(s1, x + 3, y + 4);
lcd.setTextColor(TFT_BLACK);
lcd.drawString(s2, x + 30, y + 4);
}
void SD_Info() {
uint8_t cardType = SD.cardType(); // カード情報
String s = "Card Type: ";
if (cardType == CARD_MMC) s += "MMC";
else if (cardType == CARD_SD) s += "SDSC";
else if (cardType == CARD_SDHC) s += "SDHC";
else s += "UNKNOWN";
Serial.println(s);
uint64_t cardSize = SD.cardSize() / (1024 * 1024 * 1024);
s = "Card Size: " + (String)(cardSize) + "GB";
Serial.println(s);
}
void saveFile() {
String ff = "/" + fileName;
File file = SD.open(ff, FILE_WRITE); // Open file.txt in write mode
if (file) {
for (uint8_t i = 0; i <= lastline; i++) file.println(txt[i]); // Write
file.close();
Serial.println("File save successfully.");
}
}
void openFile(String fn) {
clearTexts();
File fp = SD.open(fn, FILE_READ);
if (fp) {
Serial.println("Reading text file...");
lastline = 0;
while (fp.available()) {
uint8_t c = fp.read();
if (c == 10) lastline++; // Increment the line count
if (c == 9) txt[lastline] += '\t';
if (c >= 32 && c <= 126) txt[lastline] += (char)c;
}
fp.close(); // Close the file
for (uint8_t l = 0; l <= lastline; l++) { // make background spc
uint8_t tlen = txt[l].length();
spc[l] = '|';
for (uint8_t j = 0; j < tlen; j++) spc[l] = " " + spc[l];
cuX[l] = tlen;
}
for (uint8_t i = 0; i < maxLines; i++) { // draw lines
_drawLine = (i == 0) ? 1 : 0;
drawEditLine(i);
if (i == lastline) break;
}
line = 0;
Serial.println("File read successfully.");
} else {
Serial.println("Failed to open file.txt");
}
}
最後まで見ていただきありがとうございました。