Работа с мышью

Низкоуровневое программирование портов, микроконтроллеров и т.д.

Модератор: Andy

Ответить
Aндрей1
Сообщения: 9
Зарегистрирован: 15 фев 2009, 21:17

Программа должна рисовать на экране прямые линии, оканчивающиеся в позициях, которые указываются мышью, при нажатии левой кнопки. Запускаю программу, можно перемещать курсор, но когда нажимаю левую кнопку, курсор больше не двигается. Набирал текст из учебника: Зубков - "Assembler dlya DOS, Windows i UNIX" и сверил его много раз, вроде все правильно. Помогите исправить код пожалуйста, если в нем проблема.

Код: Выделить всё

; mousedr.asm
;Рисует на экране прямые линии, оканчивающиеся в позициях, которые указываются мышью.
;
                .model  tiny
                .code
                org             100h                            ; COM-файл.
                .186                                            ; Для команжы shr cx, 3.
start:
                mov             ax, 12h
                int             10h                             ; Видеорежим 640*480.
                mov             ax, 0                           ; Инициализировать мышь.
                int             33h
                mov             ax, 1                           ; Показать курсор мыши.
                int             33h
                
                mov             ax, 000Ch                       ; Установить обработчик событий мыши.
                mov             cx, 0002h                       ; Событие - нажатие левой кнопки.
                mov             dx, offset handler              ; ES :D X - адрес обработчика.
                int             33h
                
                mov             ah, 0                           ; Ожидание нажатия любой клавиши.
                int             16h
                mov             ax, 000Ch
                mov             cx, 0000h                       ; Удалить обработчик событий мыши.
                int             33h
                mov             ax, 3                           ; Текстоый режим.
                int             10h
                ret                                             ; Конец программы.
 
; Обработчик событий мыши: при первом нажатии выводит точку на экран,
; при каждом дальнейшем вызове проводит прямую линию от предыдущей
; точки к текущей.
                
handler:
                push            0A000h
                pop             es                              ; ES - начало видеопамяти.
                push            cs
                pop             ds                              ; DS - сегмент кода и данных этой программы.
                push            cx                              ; CX (X-координата) и DX(Y-координата)
                push            dx                              ; потребуются в конце.
                
                mov             ax, 2                           ; Спрятать курсор мыши перед выводом на экран.
                int             33h
                
                cmp             word ptr previous_X, -1            ; Если это первый вызов,
                je              first_point                     ; только вывести точку.
                
                call            line_bresenham                     ; Иначе - провести прямую.                                                   
 
exit_handler:
                pop             dx                              ; Восстановить CX и DX
                pop             cx
                mov             previous_X, cx                     ; и запомнить их как предыдущие
                mov             previous_Y, dx                     ; координаты.
                
                mov             ax, 1                           ; Показать курсор мыши.
                int             33h
                
                retf                                            ; Выход из обработчика - команда RETF.
                
first_point:
                call            putpixel1b                      ; Вывод одной точки (при первом вызове).
                jmp             short exit_handler
Aндрей1
Сообщения: 9
Зарегистрирован: 15 фев 2009, 21:17

Продолжение:

Код: Выделить всё

; Процедура рисования прямой линии с использованием алгоритма Брезенхама.
; Вывод CX, DX - X, Y начальной точки.
; previous_X, previous_Y - X, Y начальной точки.
                
line_bresenham:
                mov             ax, cx
                sub             ax, previous_X                     ; AX = длина проекции прямой на ось X.
                jns             dx_pos                             ; Если AX отрицательный -
                neg             ax                              ; сменить его знак, причем
                mov             word ptr X_increment, 1            ; координата X при выводе
                jmp             short dx_neg                       ; прямой будет расти.
dx_pos: mov             word ptr X_increment, -1                   ; Иначе - уменьшаться.
 
dx_neg: mov             bx, dx
                sub             bx, previous_Y                     ; BX = длина проекции прямой на ось Y.
                jns             dy_pos                             ; Если BX отрицательный - 
                neg             bx                              ; сменить его знак, причем
                mov             word ptr Y_increment, 1            ; координата Y при выводе
                jmp             short dy_neg                    ; прямой будет расти.
dy_pos: mov             word ptr Y_increment, -1                   ; иначе - уменьшаться.
dy_neg:
                shl             ax, 1                           ; Удвоить значения проекций,
                shl             bx, 1                           ; чтобы избежать работы с полуцелыми числами.
                
                call            putpixel1b                      ; Вывести первую точку (прямая рисуется от
                                                                ; CX, DX к previous_X, previous_Y).
                cmp             ax, bx                          ; Если проекция на ось X больше, чем на Y,
                jna             dx_le_dy
                mov             di, ax                          ; DI будет указывать, в какую сторону мы
                shr             di, 1                           ; отклонились от идеальной прямой.
                neg             di                              ; Оптимальное начальное значение DI:
                add             di, bx                          ; DI = 2 * dy - dx
cycle:
                cmp             cx, word ptr previous_X            ; Основной цикл выполняется,
                je              exit_bres                       ; пока X не станет равное previous_X.
                cmp             di, 0                           ; Если DI > 0,
                jl              fractlt0
 
                add             dx, word ptr Y_increment        ; перейти к следующему Y
                sub             di, ax                          ; и уменьшить DI на 2 * dx.
fractlt0:
                add             cx, word ptr X_increment        ; Следующий X (на каждом шаге).
                add             di, bx                          ; Увеличить на DI на 2 * dy.
                call            putpixel1b                      ; Вывести точку.                                                                                                                ;!!!!!
                jmp             short cycle                     ; Продолжить цикл.
                
dx_le_dy:                                                       ; Если проекция на ось Y больше, чем на X.
                mov             di, bx
                shr             di, 1
                neg             di                              ; Оптимальное начальное значение DI:
                add             di, ax                          ; DI = 2 * dx - dy.
cycle2:
                cmp             dx, word ptr previous_Y            ; Основной цикл выполняется,
                je              exit_bres                       ; пока Y не станет равным previous_Y.
                cmp             di, 0                           ; Если DI > 0,
                jl              fractlt02
                add             cx, word ptr X_increment        ; перейти к следующему X
                sub             di, bx                          ; и уменьшить DI на 2 * dy,
fractlt02:
                add             dx, word ptr Y_increment        ; Следующий Y (на каждом шаге).
                add             di, ax                          ; Увеличить DI на 2 * dy,
                call            putpixel1b                      ; вывести точку,
                jmp             short cycle2                    ; продолжить цикл.
exit_bres:
                ret                                             ; Конец процедуры.
 
; Процедура вывода точки на экран в режиме, использующем один бит для
; хранения одного пикселя.
; DX = строка, CX = столбец.
; Все регистры сохраняются.              
Aндрей1
Сообщения: 9
Зарегистрирован: 15 фев 2009, 21:17

Продолжение:

Код: Выделить всё

putpixel1b:
                pusha                                           ; Сохранить регистры.
                xor             bx, bx
                mov             ax, dx                          ; AX = номер строки.
                imul            ax, ax, 80                      ; AX = номер строки x число байтов в строке.
                push            cx
                shr             cx, 3                           ; CX = номер байта в строке.
                add             ax, cx                          ; AX = номер байта в видеопамяти.
                mov             di, ax                          ; Поместить его в SI и DI для команд
                mov             si, di                          ; строковой обработки.
                
                pop             cx                              ; CX снова содержит номер столбца.
                mov             bx, 0080h
                and             cx, 07h                            ; Последние три бита CX = 
                                                                ; остаток от деления на 8 = номер бита в байте
                                                                ; считая справа налево.
                shr             bx, cl                          ; Теперь в BL установлен в 1 нужный бит.
 
                lods            es: byte ptr some_label            ; AL = байт из видеопамяти.
                ;or             ax, bx                          ; Установить выводимый бит в 1,
; Чтобы стереть пиксел с экрана, эту команду OR  можно заменить на
 not bx
 and ax, bx
; или лучше инициализировать BX не числом 0080h, а числом FF7Fh и использовать
; только and
                stosb                                           ; И вернуть байт на место.
                popa                                            ; Восстановить регистры.
                ret                                             ; Конец.
                
previous_X                      dw      -1                      ; Предыдущая X-координата.
previous_Y                      dw      -1                      ; Предыдущая Y-координата.
Y_increment                     dw      -1                      ; Направление изменения Y.
X_increment                     dw      -1                      ; Направление изменения X.
some_label:                                                     ; Метка, используемая для переопределения
                                                                ; сегмента-источника для lods с DS на ES.
                end     start
Aндрей1
Сообщения: 9
Зарегистрирован: 15 фев 2009, 21:17

Все, разобрался. оказывается неправильно компилировал. не добавил /t. Однако появилась другая проблема. Не рисует линии... :(
Aндрей1
Сообщения: 9
Зарегистрирован: 15 фев 2009, 21:17

Все, разобрался, все рисуется. Нужно было исправить в putpixel1b на putpixellb
Aндрей1
Сообщения: 9
Зарегистрирован: 15 фев 2009, 21:17

Последний вопрос, помогите пожалуйста!!! с выводом сигнала при нажатии кнопки мыши.
Aндрей1
Сообщения: 9
Зарегистрирован: 15 фев 2009, 21:17

все. я разобрался. вот, что нужно было:
mov ah, 2
mov dl, 07h; функция вывода сигнала
int 21h
Ответить