C语言Win32控制台文本编辑器:如何实现方向键光标移动?
实现C语言控制台文本编辑器的方向键光标移动
你的代码目前缺少方向键输入的处理逻辑,且未将内存中的光标位置(cursor变量)与控制台的实际光标坐标(cursorPos)同步,导致无法通过方向键移动光标。以下是完整的解决方案及修改后的代码:
核心改动说明
1. 处理扩展键(方向键)输入
方向键属于Windows控制台的扩展键,使用_getch()读取时会返回两次:第一次是0或224(标记为扩展键),第二次是具体键码:
- 上方向键:72
- 下方向键:80
- 左方向键:75
- 右方向键:77
需在输入处理逻辑中判断该情况,再根据第二次返回的键码执行对应光标移动操作。
2. 正确维护内存光标位置(cursor)
根据方向键调整cursor的取值范围:
- 左移:
cursor > 0时减1 - 右移:
cursor < strlen(buffer)时加1 - 上移/下移:通过分割buffer中的换行符定位当前行,再计算目标行的对应列位置(处理行长度差异,例如上一行短于当前列时,光标移至该行末尾)。
3. 同步控制台光标坐标(cursorPos)
每次cursor变更后,遍历buffer统计到cursor位置的换行符数量,计算对应的控制台行号与列号,确保控制台光标与内存光标位置一致。
修改后的完整代码
#include <stdio.h> #include <string.h> #include <windows.h> #include <conio.h> #define MAX_BUFFER 1024 // 假设displayBuffer和saveFile为已实现的函数 void displayBuffer(const char *buffer, const char *filename) { printf("File: %s\n\n%s", filename, buffer); } int saveFile(const char *filename, const char *buffer) { FILE *fp = fopen(filename, "w"); if (!fp) return -1; fputs(buffer, fp); fclose(fp); return 0; } // 计算cursor对应的控制台坐标 void updateCursorPos(COORD *pos, const char *buffer, int cursor) { pos->X = 0; pos->Y = 0; for (int i = 0; i < cursor; i++) { if (buffer[i] == '\n') { pos->Y++; pos->X = 0; } else { pos->X++; } } // 偏移displayBuffer中标题行的行数 pos->Y += 2; } // 获取光标所在行的起始索引 int getLineStart(const char *buffer, int cursor) { int start = 0; for (int i = 0; i < cursor; i++) { if (buffer[i] == '\n') { start = i + 1; } } return start; } // 获取光标所在行的结束索引 int getLineEnd(const char *buffer, int cursor) { int end = strlen(buffer); for (int i = cursor; i < strlen(buffer); i++) { if (buffer[i] == '\n') { end = i; break; } } return end; } // EDIT LOOP void insertMode(char *buffer, const char *filename) { // Init cursor int cursor = strlen(buffer); COORD cursorPos = {0, 0}; HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); BOOL isEditing = TRUE; while (isEditing) { // 清屏并显示内容 system("cls"); displayBuffer(buffer, filename); // 显示操作提示 printf("\nesc = SAVE&QUIT | ↑↓←→ = MOVE CURSOR\n"); // 更新并设置控制台光标位置 updateCursorPos(&cursorPos, buffer, cursor); SetConsoleCursorPosition(console, cursorPos); // 捕获用户输入 char ch = _getch(); // 处理扩展键(方向键) if (ch == 0 || ch == 224) { char extendedKey = _getch(); switch (extendedKey) { case 75: // 左方向键 if (cursor > 0) cursor--; break; case 77: // 右方向键 if (cursor < strlen(buffer)) cursor++; break; case 72: // 上方向键 { int currentLineStart = getLineStart(buffer, cursor); if (currentLineStart == 0) break; int prevLineStart = getLineStart(buffer, currentLineStart - 1); int prevLineEnd = getLineEnd(buffer, prevLineStart); int currentCol = cursor - currentLineStart; cursor = prevLineStart + (currentCol < (prevLineEnd - prevLineStart) ? currentCol : (prevLineEnd - prevLineStart)); } break; case 80: // 下方向键 { int currentLineEnd = getLineEnd(buffer, cursor); if (currentLineEnd == strlen(buffer)) break; int nextLineStart = currentLineEnd + 1; int nextLineEnd = getLineEnd(buffer, nextLineStart); int currentCol = cursor - getLineStart(buffer, cursor); cursor = nextLineStart + (currentCol < (nextLineEnd - nextLineStart) ? currentCol : (nextLineEnd - nextLineStart)); } break; default: break; } continue; } // ESC键:保存退出 if (ch == 27) { if (saveFile(filename, buffer) == 0) { system("cls"); printf("\nFile saved successfully.\n"); } else { printf("\nError saving file.\n"); } break; } // Backspace键:修复原代码的字符截断问题 else if (ch == '\b') { if (cursor > 0) { memmove(&buffer[cursor - 1], &buffer[cursor], strlen(buffer) - cursor + 1); cursor--; } } // Enter键:插入换行符 else if (ch == '\r') { if (cursor < MAX_BUFFER - 1) { memmove(&buffer[cursor + 1], &buffer[cursor], strlen(buffer) - cursor + 1); buffer[cursor] = '\n'; cursor++; } } // 普通字符输入 else { if (cursor < MAX_BUFFER - 1) { memmove(&buffer[cursor + 1], &buffer[cursor], strlen(buffer) - cursor + 1); buffer[cursor] = ch; cursor++; } } } } // 测试用主函数 int main() { char buffer[MAX_BUFFER] = "Hello World!\nThis is a test line.\nThird line here."; insertMode(buffer, "test.txt"); return 0; }
额外说明
- 修复了原代码中Backspace和Enter键的逻辑:原代码直接覆盖字符会导致后续内容丢失,改用
memmove移动字符保证buffer完整性。 - 辅助函数
getLineStart和getLineEnd用于定位行边界,为上下方向键的光标移动提供计算基础。
内容的提问来源于stack exchange,提问作者ShizamDaGeek
相关产品推荐
相关产品推荐

