内核终端光标支持与逐行滚动功能实现咨询
内核终端滚动与光标功能实现修改方案
前置修正(原有代码Bug修复)
- 删除重复定义的
VGA_WIDTH、VGA_HEIGHT全局常量 - 修正
terminal_putchar中换行判断的逻辑位置,避免换行仅在列未溢出时生效 - 删除
terminal_putentryat中错误的行数越界判断逻辑
一、实现自动逐行滚动功能
新增滚动辅助函数
当输出行数超过25行时,将显存内容整体上移一行,清空最后一行容纳新内容:
void terminal_scroll() { // 第1~24行内容整体上移覆盖第0~23行 for (size_t y = 1; y < VGA_HEIGHT; y++) { for (size_t x = 0; x < VGA_WIDTH; x++) { const size_t dest_idx = (y - 1) * VGA_WIDTH + x; const size_t src_idx = y * VGA_WIDTH + x; terminal_buffer[dest_idx] = terminal_buffer[src_idx]; } } // 清空最后一行 const size_t last_line_idx = (VGA_HEIGHT - 1) * VGA_WIDTH; for (size_t x = 0; x < VGA_WIDTH; x++) { terminal_buffer[last_line_idx + x] = make_vgaentry(' ', terminal_color); } }
重写terminal_putchar逻辑
void terminal_putchar(char c) { // 优先处理换行符 if (c == '\n') { terminal_row++; terminal_column = 0; } else { terminal_putentryat(c, terminal_color, terminal_column, terminal_row); terminal_column++; // 列满自动换行 if (terminal_column == VGA_WIDTH) { terminal_column = 0; terminal_row++; } } // 行溢出触发滚动 if (terminal_row >= VGA_HEIGHT) { terminal_scroll(); terminal_row = VGA_HEIGHT - 1; } // 同步更新光标位置 terminal_update_cursor(terminal_row, terminal_column); }
修正后的terminal_putentryat
void terminal_putentryat(char c, uint8_t color, size_t x, size_t y) { const size_t index = y * VGA_WIDTH + x; terminal_buffer[index] = make_vgaentry(c, color); }
二、实现VGA硬件光标支持
x86架构下通过操作VGA控制端口实现光标显示与位置更新,先补充端口操作函数:
// x86 端口输出字节内联汇编实现 static inline void outb(uint16_t port, uint8_t val) { __asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port)); } // 更新光标位置 void terminal_update_cursor(size_t row, size_t col) { uint16_t cursor_pos = row * VGA_WIDTH + col; // 写入光标位置高8位 outb(0x3D4, 0x0E); outb(0x3D5, (uint8_t)(cursor_pos >> 8)); // 写入光标位置低8位 outb(0x3D4, 0x0F); outb(0x3D5, (uint8_t)(cursor_pos & 0xFF)); }
在terminal_initialize函数末尾添加初始化光标的调用:
terminal_update_cursor(0, 0);
三、可选:支持手动上下滚动查看历史内容
如果需要保留历史输出、支持手动翻页查看,可额外维护独立于显存的历史缓冲区:
- 定义历史缓冲区参数:
#define MAX_HISTORY_LINES 100(可自定义保存的历史行数) - 新增全局变量:
uint16_t history_buffer[MAX_HISTORY_LINES][VGA_WIDTH];、size_t view_offset = 0; - 每次输出新行时同步写入历史缓冲区,手动翻页时调整
view_offset,将对应区间的历史内容复制到显存即可实现上下滚动查看历史。
内容的提问来源于stack exchange,提问作者Mohammad Khaddam
相关产品推荐
相关产品推荐

