<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Text_Mode_Cursor</id>
	<title>Text Mode Cursor - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.foofun.cn//index.php?action=history&amp;feed=atom&amp;title=Text_Mode_Cursor"/>
	<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Text_Mode_Cursor&amp;action=history"/>
	<updated>2026-04-06T14:40:30Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>http://wiki.foofun.cn//index.php?title=Text_Mode_Cursor&amp;diff=732&amp;oldid=prev</id>
		<title>Zhang3：创建页面，内容为“光标会自动移动到最后一个书写字符之后的一个位置。在文本模式中，光标的工作方式与高级语言中不同。 它只是一个可由操作系统调整大小、显示、隐藏和移动的闪烁区域。  == 通过BIOS==  要使用BIOS操作光标，请使用int 0x10，屏幕功能的中断。  ===启用游标===  启用光标功能还允许您设置开始和结束扫描线，即光标开始和结束的行。 最…”</title>
		<link rel="alternate" type="text/html" href="http://wiki.foofun.cn//index.php?title=Text_Mode_Cursor&amp;diff=732&amp;oldid=prev"/>
		<updated>2022-03-07T08:11:43Z</updated>

		<summary type="html">&lt;p&gt;创建页面，内容为“光标会自动移动到最后一个书写字符之后的一个位置。在&lt;a href=&quot;/index.php?title=Text_mode&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Text mode（页面不存在）&quot;&gt;文本模式&lt;/a&gt;中，光标的工作方式与高级语言中不同。 它只是一个可由操作系统调整大小、显示、隐藏和移动的闪烁区域。  == 通过&lt;a href=&quot;/index.php?title=BIOS&quot; title=&quot;BIOS&quot;&gt;BIOS&lt;/a&gt;==  要使用BIOS操作光标，请使用int 0x10，屏幕功能的中断。  ===启用游标===  启用光标功能还允许您设置开始和结束扫描线，即光标开始和结束的行。 最…”&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;光标会自动移动到最后一个书写字符之后的一个位置。在[[text mode|文本模式]]中，光标的工作方式与高级语言中不同。 它只是一个可由操作系统调整大小、显示、隐藏和移动的闪烁区域。&lt;br /&gt;
&lt;br /&gt;
== 通过[[BIOS]]==&lt;br /&gt;
&lt;br /&gt;
要使用BIOS操作光标，请使用int 0x10，屏幕功能的中断。&lt;br /&gt;
&lt;br /&gt;
===启用游标===&lt;br /&gt;
&lt;br /&gt;
启用光标功能还允许您设置开始和结束扫描线，即光标开始和结束的行。 最高处扫描线为0，最低处扫描线为最大扫描线（通常为15）。&lt;br /&gt;
&lt;br /&gt;
* AH = 0x01&lt;br /&gt;
* CH = start scanline&lt;br /&gt;
* CL = end scanline&lt;br /&gt;
&lt;br /&gt;
===禁用光标===&lt;br /&gt;
&lt;br /&gt;
* AH = 0x01&lt;br /&gt;
* CH = 0x3F (bits 0-7 unused, bit 5 disables cursor, bits 0-4 control cursor shape)&lt;br /&gt;
&lt;br /&gt;
=== 移动光标 ===&lt;br /&gt;
&lt;br /&gt;
* AH = 0x02&lt;br /&gt;
* BH = display page (usually, if not always 0)&lt;br /&gt;
* DH = row&lt;br /&gt;
* DL = column&lt;br /&gt;
&lt;br /&gt;
===获取光标数据===&lt;br /&gt;
&lt;br /&gt;
* AH = 0x03&lt;br /&gt;
* BH = display page (usually, if not always 0)&lt;br /&gt;
&lt;br /&gt;
返回值：&lt;br /&gt;
&lt;br /&gt;
* CH = start scanline&lt;br /&gt;
* CL = end scanline&lt;br /&gt;
* DH = row&lt;br /&gt;
* DL = column&lt;br /&gt;
&lt;br /&gt;
== 不通过[[BIOS]] ==&lt;br /&gt;
&lt;br /&gt;
在没有BIOS访问的情况下，操作光标需要将数据直接发送到硬件。&lt;br /&gt;
&lt;br /&gt;
===启用光标===&lt;br /&gt;
&lt;br /&gt;
启用游标功能还允许您设置开始和结束扫描线，即游标开始和结束的行。 最高处扫描线为0，最低处扫描线为最大扫描线（通常为15）。&lt;br /&gt;
&lt;br /&gt;
'''C语言源代码'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void enable_cursor(uint8_t cursor_start, uint8_t cursor_end)&lt;br /&gt;
{&lt;br /&gt;
	outb(0x3D4, 0x0A);&lt;br /&gt;
	outb(0x3D5, (inb(0x3D5) &amp;amp; 0xC0) | cursor_start);&lt;br /&gt;
&lt;br /&gt;
	outb(0x3D4, 0x0B);&lt;br /&gt;
	outb(0x3D5, (inb(0x3D5) &amp;amp; 0xE0) | cursor_end);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 禁用光标 ===&lt;br /&gt;
&lt;br /&gt;
'''C语言源代码'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void disable_cursor()&lt;br /&gt;
{&lt;br /&gt;
	outb(0x3D4, 0x0A);&lt;br /&gt;
	outb(0x3D5, 0x20);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''汇编源代码'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
disable_cursor:&lt;br /&gt;
	pushf&lt;br /&gt;
	push eax&lt;br /&gt;
	push edx&lt;br /&gt;
&lt;br /&gt;
	mov dx, 0x3D4&lt;br /&gt;
	mov al, 0xA	; low cursor shape register&lt;br /&gt;
	out dx, al&lt;br /&gt;
&lt;br /&gt;
	inc dx&lt;br /&gt;
	mov al, 0x20	; bits 6-7 unused, bit 5 disables the cursor, bits 0-4 control the cursor shape&lt;br /&gt;
	out dx, al&lt;br /&gt;
&lt;br /&gt;
	pop edx&lt;br /&gt;
	pop eax&lt;br /&gt;
	popf&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 移动光标 ===&lt;br /&gt;
&lt;br /&gt;
请记住，不需要每次显示新字符时都更新光标的位置。 相反，只在打印完整个字符串之后才更新它会更快。&lt;br /&gt;
&lt;br /&gt;
'''Source in C'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
void update_cursor(int x, int y)&lt;br /&gt;
{&lt;br /&gt;
	uint16_t pos = y * VGA_WIDTH + x;&lt;br /&gt;
&lt;br /&gt;
	outb(0x3D4, 0x0F);&lt;br /&gt;
	outb(0x3D5, (uint8_t) (pos &amp;amp; 0xFF));&lt;br /&gt;
	outb(0x3D4, 0x0E);&lt;br /&gt;
	outb(0x3D5, (uint8_t) ((pos &amp;gt;&amp;gt; 8) &amp;amp; 0xFF));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''汇编中的源代码'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;asm&amp;quot;&amp;gt;&lt;br /&gt;
Cursor:&lt;br /&gt;
VGA.Width equ 80&lt;br /&gt;
&lt;br /&gt;
.SetCoords:&lt;br /&gt;
; input bx = x, ax = y&lt;br /&gt;
; modifies ax, bx, dx&lt;br /&gt;
&lt;br /&gt;
	mov dl, VGA.Width&lt;br /&gt;
	mul dl&lt;br /&gt;
	add bx, ax&lt;br /&gt;
&lt;br /&gt;
.SetOffset:&lt;br /&gt;
; input bx = cursor offset&lt;br /&gt;
; modifies al, dx&lt;br /&gt;
&lt;br /&gt;
	mov dx, 0x03D4&lt;br /&gt;
	mov al, 0x0F&lt;br /&gt;
	out dx, al&lt;br /&gt;
&lt;br /&gt;
	inc dl&lt;br /&gt;
	mov al, bl&lt;br /&gt;
	out dx, al&lt;br /&gt;
&lt;br /&gt;
	dec dl&lt;br /&gt;
	mov al, 0x0E&lt;br /&gt;
	out dx, al&lt;br /&gt;
&lt;br /&gt;
	inc dl&lt;br /&gt;
	mov al, bh&lt;br /&gt;
	out dx, al&lt;br /&gt;
	ret&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===获取光标位置===&lt;br /&gt;
&lt;br /&gt;
使用此代码，您将获得：&amp;lt;tt&amp;gt;pos = y * VGA_WIDTH + x&amp;lt;/tt&amp;gt;。 要获得坐标，只需计算: &amp;lt;tt&amp;gt;y = pos / VGA_WIDTH; x = pos % VGA_WIDTH;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''C语言源代码'''&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
uint16_t get_cursor_position(void)&lt;br /&gt;
{&lt;br /&gt;
    uint16_t pos = 0;&lt;br /&gt;
    outb(0x3D4, 0x0F);&lt;br /&gt;
    pos |= inb(0x3D5);&lt;br /&gt;
    outb(0x3D4, 0x0E);&lt;br /&gt;
    pos |= ((uint16_t)inb(0x3D5)) &amp;lt;&amp;lt; 8;&lt;br /&gt;
    return pos;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==基于字体的“图形”光标==&lt;br /&gt;
&lt;br /&gt;
=== 用途 === &lt;br /&gt;
&lt;br /&gt;
在DOS时代，完全不使用硬件VGA光标是很常见的，而是覆盖VGA字体来创建箭头指针，就像在图形模式中一样。 例如，在[https://en.wikipedia.org/wiki/Norton_Utilities Norton Utilities]或[[Norton Diskedit]]的DOS版本中使用了该技术。&lt;br /&gt;
&lt;br /&gt;
[[Image:Itmouse.png|Arrow cursor in text mode]]&lt;br /&gt;
&lt;br /&gt;
您可以通过光标颜色轻松地发现此字体更改光标: 由于只有字体被更改，属性字节未被触及，指针在移动时会改变颜色。&lt;br /&gt;
&lt;br /&gt;
这里是论坛[https://forum.osdev.org/download/file.php?id=2264&amp;amp;mode=view TUI的另一个例子，具有8x8个字符和指形光标]&lt;br /&gt;
&lt;br /&gt;
=== 如何实现 ===&lt;br /&gt;
&lt;br /&gt;
基本原理是从屏幕上存储4个字节（2x2），将它们的[[VGA Fonts|VGA字体]]复制到一些未使用的方框图字符（0xC0-0xDF），或者将箭头屏蔽，然后在屏幕上写入这些2x2方框图字符。 然后，当鼠标移动时，屏幕上恢复原来的4个字节，整个过程在新位置重复。&lt;br /&gt;
&lt;br /&gt;
使用框绘制字符很重要，因为通常VGA将字体显示为9x16，添加了一个空的第9列，这将导致光标中的 “间隙”。 对于方框图字符，第9列是第8列的副本，因此不会将指针一分为二。 如果您使用8x8字符(如80x50或132x50模式)，则没有字符分隔栏，您可以随意使用任何字符。 在上面的论坛示例中，您可以在字符0xF0-0xF3处发现ASCII表上的光标。&lt;br /&gt;
&lt;br /&gt;
尽管箭头大小与一个字符（通常为8x16或8x8）相同，但由于指针可以以像素精度移动，它可以在水平和垂直方向与下一个字符重叠，因此总共需要4个字节：&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
char 1   attr 1   char 2   attr 2&lt;br /&gt;
........|????????|........|????????       first line&lt;br /&gt;
........|????????|........|????????       (note attribute bytes are untouched)&lt;br /&gt;
........|????????|........|????????&lt;br /&gt;
....x...|????????|........|????????&lt;br /&gt;
....xx..|????????|........|????????&lt;br /&gt;
....xxx.|????????|........|????????&lt;br /&gt;
....xxxx|????????|........|????????&lt;br /&gt;
....xxxx|????????|x.......|????????&lt;br /&gt;
--------+--------+--------+--------&lt;br /&gt;
....xxxx|????????|xx......|????????       second line&lt;br /&gt;
....xxxx|????????|xxx.....|????????&lt;br /&gt;
....xxxx|????????|xxxx....|????????&lt;br /&gt;
.......x|????????|x.......|????????&lt;br /&gt;
.......x|????????|x.......|????????&lt;br /&gt;
........|????????|xx......|????????&lt;br /&gt;
........|????????|........|????????&lt;br /&gt;
........|????????|........|????????&lt;br /&gt;
char 3   attr 3   char 4   attr 4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
您可以使用BIOS读取VGA字体，或者如果您已经处于保护模式，则可以使用VGA寄存器读取VGA字体。 阅读 [[VGA Fonts|VGA字体]] 文章了解更多信息。&lt;br /&gt;
&lt;br /&gt;
通过将鼠标光标除以字体大小来计算字符位置：cx=mx/8和cy=my/16。 然后计算my%16以获得要修改的字体字形的第一个字节，并计算mx%8以获得您必须按其移位箭头掩码的移位值。&lt;br /&gt;
&lt;br /&gt;
== 关于GRUB的提醒 ==&lt;br /&gt;
&lt;br /&gt;
如果grub.cfg中的timeout设置为0，光标将被禁用，您需要自己启用它。 其它情况下，[[GRUB]]将为您启用光标。 由于这种不一致，因此始终启用光标是一个好主意。 即使没有将超时设置为0，将来也可能需要，或者有人可能会在他们的系统上更改timeout。&lt;br /&gt;
&lt;br /&gt;
== 另见 ==&lt;br /&gt;
* [[VGA Hardware|VGA硬件]]&lt;br /&gt;
* [[Text UI]]&lt;br /&gt;
&lt;br /&gt;
===外部链接===&lt;br /&gt;
* http://www.osdever.net/FreeVGA/vga/textcur.htm&lt;br /&gt;
* https://web.archive.org/web/20080731014051/http://www.bookcase.com:80/library/dos/ints/int10.html&lt;br /&gt;
* https://web.archive.org/web/20120324083032/http://www.arl.wustl.edu/~lockwood/class/cs306/books/artofasm/Chapter_13/CH13-2.html&lt;br /&gt;
* https://en.wikipedia.org/wiki/VGA-compatible_text_mode&lt;br /&gt;
&lt;br /&gt;
[[Category:Video]]&lt;br /&gt;
[[Category:Text UI]]&lt;br /&gt;
[[Category:VGA]]&lt;/div&gt;</summary>
		<author><name>Zhang3</name></author>
	</entry>
</feed>