程序集中的图形光标

时间:2016-07-20 20:26:21

标签: assembly mouse dosbox

我试图在Assembly for DOSBox中制作一个类似绘画的小程序。我不确定DOSBox模拟的CPU类型,但是我发现它可能是386。

我做了我的研究并想出如何使用鼠标中断,33h。我还设法使用屏幕掩码和光标掩码来定义我自己的光标。但是,当用户切换到例如颜色取样器工具时,我希望能够在程序中稍后更改光标。当我尝试这样做时,光标变成了黑色方块。这是因为我不确切知道执行此类更改所需的步骤。

我是否应该隐藏光标,然后重置光标,然后更改光标模板,然后重新显示?我是否更换了面罩并且只重置了?我根本不需要重置鼠标吗?这是我所有与鼠标相关的代码。

P.S。我知道我可以通过将一堆触发器转换为宏来优化其中的一部分,并且一旦我将错误整理出来,我将来可能会这样做。

stdBrush PROC
    push bx cx ax dx
    mov bx, stdBrushHotSpots
    mov cx, stdBrushHotSpots + 2
    mov ax, 9
    mov dx, offset stdBrushMask
    int 33h
    pop dx ax cx bx
    ret
stdBrush ENDP

pickerTool PROC
    push bx cx ax dx
    mov bx, pickerToolHotSpots
    mov cx, pickerToolHotSpots + 2
    mov ax, 9
    mov dx, offset pickerToolMask
    int 33h
    pop dx ax cx bx
    ret
pickerTool ENDP

mouseReset PROC
     push ax
    mov ax, 0
    int 33h
    pop ax
    ret
mouseReset ENDP

showCursor PROC
    push ax
    mov ax, 1
    int 33h
    pop ax
    ret
showCursor ENDP

hideCursor PROC
    push ax
    mov ax, 2
    int 33h
    pop ax
    ret
hideCursor ENDP

getCursorStat PROC
    push ax
    mov ax, 3
    int 33h
    pop ax
    ret
getCursorStat ENDP

initCursor PROC
    mov ax, dseg
    mov es, ax
    call mouseReset
    call stdBrush
    call showCursor
    mov ax, DISPLAY_SEG
    mov es, ax
    ret
initCursor ENDP

这些小程序充当使用int 33h的不同功能的快捷方式。例外的是initCursor,它结合了这些快捷方式,用于在程序开始时初始化光标,以及stdBrush& pickerTool,它将图形光标设置为特定光标(您可以猜到,stdBrush是标准画笔光标,而pickerTool设置光标用于颜色采样器工具)。

以下是我的两个游标的面具。

stdBrushMask    dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 0000000100000000b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b
            dw 1111111011111111b

            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 1111111011111111b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
            dw 0000000100000000b
stdBrushHotSpots dw 7
                 dw 7

pickerToolMask  dw 1111100001000001b
            dw 1111100000000000b
            dw 1111100000000000b
            dw 1111100000000000b
            dw 1111100000000000b
            dw 1111000000000000b
            dw 1110000000000000b
            dw 1100000000000000b
            dw 1000000000000000b
            dw 1000000000000000b
            dw 1000000000000000b
            dw 1000000000011111b
            dw 0000000000111111b
            dw 0000000001111111b
            dw 0000000011111111b
            dw 0000111111111111b

            dw 0000000000000000b
            dw 0000001100011100b
            dw 0000001111111110b
            dw 0000000111111110b
            dw 0000000111111110b
            dw 0000001111111100b
            dw 0000011111111100b
            dw 0000111111111100b
            dw 0001111111111110b
            dw 0011111111100110b
            dw 0001111111000000b
            dw 0001111110000000b
            dw 0011111100000000b
            dw 0111001000000000b
            dw 0110000000000000b
            dw 0000000000000000b

pickerToolHotSpots dw 1
                   dw 14

由于将代码复制到stackoverflow会导致一些缩进差异,我无法逐行删除并修复它们。

这是导致我麻烦的程序的一部分:

paletteModeToggle PROC
    push ax
    call hideCursor
    mov pos_backup, cx
    mov pos_backup+2, dx
    mov al, colorpicker_flag
    not al
    mov colorpicker_flag, al
    test al, al
    jz palette_mode_off
    palette_mode_on:
        call pickerTool
        call backupScreen
        call graphicsMode
        call paletteDraw
        call mouseReset
        call showCursor
        pop ax
        jmp input_loop
    palette_mode_off:
        call stdBrush
        call graphicsMode
        call restoreScreen
        call mouseReset
        call showCursor
    pop ax
    jmp input_loop
paletteModeToggle ENDP

它显示了一个调色板,它应该将光标更改为颜色取样器工具光标。相反,即使切换调色板模式,光标也会变成黑色方块并保持这种状态。我怀疑在更改光标时我没有采取正确的步骤。当光标还没有显示时,它在程序开始时工作得很好。

在此过程中,我隐藏了光标,然后我更改了光标掩码,然后我将鼠标重置为默认驱动程序值(甚至不确定这是否必要),然后再次将其显示。我做错了吗?

如果你还没有注意到,我会使用TASM。

如果您需要查看我的代码的更多部分,请告诉我。

2 个答案:

答案 0 :(得分:1)

您无需隐藏/显示光标以更改其形状。

如果您看到黑匣子,请仔细检查

  • ES细分。如果要构建COM,则应该等于CS;如果要构建EXE,如果游标在数据段中,则它应等于DS,如果它们在代码段中,则应等于CS
  • 游标的位图。使用完整的反转方dw 32 DUP(0ffffh)(在NASM语法中为TIMES 32 dw 0ffffh)进行测试,该方块在每种颜色上都可见且易于生成。

调试其他人的代码对于这个网站来说是无趣的,我将提供一个如何更改光标形状的MCWE(最小完整工作示例)。

按任意键更改光标。 再按一次退出。

.286
.MODEL TINY

_CODE SEGMENT PARA PUBLIC 'CODE' USE16
    ASSUME CS:_CODE, DS:_CODE 
    ORG 100h

 __START__:

    call initGraphics                   ;Get into graphic mode and show cursor 

    push 08h 
    push 08h 
    push OFFSET barCursor
    call setCursor 

    xor ah, ah
    int 16h

    push 08h 
    push 08h 
    push OFFSET checkerCursor
    call setCursor 

    xor ah, ah
    int 16h

    call finalizeGraphics

    mov ax, 4c00h
    int 21h 

    ;
    ; PROCEDURES
    ;

    ;Set graphic mode, reset mouse and show cursor
 initGraphics:
    push es

    mov ax, 13h
    int 10h

    push 0a000h
    pop es 
    xor di, di 
    mov ax, 0909h
    mov cx, 320*200/2 
    rep stosw 

    xor ax, ax 
    int 33h 

    mov ax, 01h 
    int 33h

    pop es
    ret

 ;Hide cursor and set text mode
 finalizeGraphics:
    mov ax, 02h
    int 33h 

    mov ax, 03h 
    int 10h 

    ret 

 ;Set cursor
 ;Hotspot X
 ;Hotspot Y
 ;Ptr to cursor bitmaps
 setCursor:
    push bp 
    mov bp, sp

    pusha
    push es

    mov ax, 09h
    mov bx, WORD PTR [bp+08h]
    mov cx, WORD PTR [bp+06h]
    mov dx, WORD PTR [bp+04h]
    push ds                         ;Setting ES = DS is not necessary in COM
    pop es                          ;files unless somebody changed ES
    int 33h 

    pop es
    popa

    pop bp  
    ret 06h     


    ;
    ; CURSORS
    ;

    barCursor       dw  16 DUP(0fe7fh)
                    dw  16 DUP(0180h)

    checkerCursor   dd  8 DUP(5555aaaah)
                    dd  8 DUP(0aaaa5555h)

_CODE ENDS 

END __START__

对于其他读者,光标位图的格式为 1

OFFSET     SIZE       DESCRIPTION
 00h        32         16x16 pixel AND mask
 20h        32         16x16 pixel XOR mask

16x16像素表示光标下的每个像素都映射到该矩阵中的一个位。
光标大小为16x16,因此每个WORD(16位)定义一行 一行中最左边的像素映射到WORD的LSb。

例如,WORD 4807h (0100 1000 0000 0111)的第1,第2,第3,第12和第15像素为1。

AND掩码用于清除光标下的像素,1表示不影响像素,0表示将其设置为黑色。

XOR掩码用于反转光标下的像素,1表示反转像素值(在模式13h中只是低位半字节),0表示不受影响。

这来自AND和XOR的属性。

1 Ralf Brown Interrupt entry这里有点草率。

答案 1 :(得分:0)

根据page

  

ax = 0:将鼠标重置为默认驱动程序值:

     
      
  • 鼠标位于屏幕中心
  •   
  • 鼠标光标已重置并隐藏
  •   
  • 未启用任何中断(mask = 0)
  •   
  • 双倍速度阈值设置为每秒64个mickeys
  •   
  • 水平米奇与像素比(8到8)
  •   
  • 垂直米奇与像素比(16至8)
  •   
  • 视频模式的最大宽度和高度设置为最大值
  •   

所以你的stdBrush + graphicsMode + restoreScreen + resetMouse + showCursor很可能是个问题。

同样是什么graphicsMode?如果它正在设置gfx模式,它很可能也会破坏光标图形。

所以,如果你想打电话给我,我会先尝试这个顺序:

  • 图形模式
  • 重置鼠标
  • 恢复屏幕
  • stdBrush
  • 次showCursor

或者尝试最小化诸如设置/重置之类的东西,如果你一直呆在同一图形模式下,“恢复屏幕”不能重新绘制它?使用鼠标,我发现每次重置它的好处更少(尽管在gfx模式改变后可能是安全的)。

Dosbox模拟您set it to

  

cputype = auto | 386 | 386_slow | 486_slow | pentium_slow |   386_prefetch

关于如何更改光标gfx ..你不需要调用任何hide / reset / show / etc.只需使用新的gfx数据再次调用“INT 33,9”。它会立即替换它(它只是在gfx驱动程序中设置两个地址,让它知道应该在哪里获取掩码+墨水数据,而gfx驱动程序正在使用每个显示帧... IIRC如何工作)。

我记得当然,当我在13h DOS模式下做“精灵编辑器”时,我选择了自己的光标绘制程序,所以我可以使用256色精灵(它们在编辑器中绘制的最终版本) 。但我不记得任何技术细节,它回来了〜25年。 :)