You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 23:42:05