http://sulfurzona.ru/
News
Service
Magazine
Software (Battle City Game, Wallpaper manager, Superpad, VG-NOW, Puzzle Game, Netler Internet Browser, ..)
Wing-Thunder Game (fly simulator)
Dune Game (Dune III, Dune IV, Cheats, Forum, ..)
Games free
Turbo Pascal (Assembler, Docs, Sources, Debbugers, ..)
Books (Docs for developers)
Guest book
Компьютерная диагностика двигателя автомобиля (адаптер К-линии)Компьютерная диагностика двигателя автомобиля (адаптер К-линии)
 
 
Скачать игру Крыло-Гром (Wing-Thunder) бесплатно
 
 

Паскаль для новичков (часть 20)

 

Спрашивали? Отвечаю…

Дружба с Микки Маусом (часть 1)

 
Автор: Владислав Демьянишин
 
Паскаль для новичков
Те читатели, которые внимательно следят за моими статьями, стали свидетелями того, как легко можно расширять возможности языка Turbo Pascal, не ограничиваясь стандартными средствами и модулями, можно легко наращивать мощь этой среды разработки, в которой созданы почти все условия для этого.
 
Ну вот, выводить текст и получать информацию посредством ее ввода с клавиатуры мы уже научились. Все это хорошо, НО для создания программы с настоящим серьезным пользовательским интерфейсом необходима одна маленькая, но немаловажная деталь – работа с манипулятором “Мышь”(Mouse), а вернее получение управляющих команд пользователя посредством интерфейса мыши и их обработка. Так вот, задача, которую мы сегодня перед собой поставим – это составление универсального модуля, который бы состоял из процедур и функций, позволяющих управлять манипулятором “мышь” и получать информацию о действиях пользователя (кликах и перемещении манипулятора). Своеобразный джентльменский набор самых необходимых процедур и функций.
 
Ну что же, начнем как обычно с блока Interface, описав в нем перечислимый тип TMouseButton для идентификации нажатой клавиши и множественный тип TMouseState , который послужит индикатором того, какая клавиша мыши нажата в данный момент. А так как одновременно могут быть нажаты несколько клавиш, то рациональность применения множества в данном случае неоспорима.
 
Unit MsMouse;
 
interface
 
type TMouseButton = (mbLeft, mbRight, mbMiddle);
        TMouseState = set of TMouseButton;
 
function Ms_Init : boolean;
procedure Ms_CurShow;
procedure Ms_CurHide;
function Ms_X : word;
function Ms_Y : word;
procedure Ms_SetPosition( x, y : word );
function Ms_State : byte;
procedure Ms_SetMinMaxX( Min, Max : word );
procedure Ms_SetMinMaxY( Min, Max : word );
procedure Ms_SetMickey( Horiz, Vertic : word );
function Ms_Down( Button : TMouseButton):boolean;
function Ms_Click( Button : TMouseButton):boolean;
 
Перейдя к блоку Implementation, опишем типизированную константу Ms_ButtonFlag, начальное значение которой свидетельствует о том, что ни одна клавиша мыши не нажата.
 
implementation
 
const
         Ms_ButtonFlag : array [TMouseButton] of boolean = ( false, false, false );
 
Теперь опишем короткую, но очень важную функцию Ms_Init, с выполнения которой нужно начинать работу программы, чтобы проверить наличие драйвера мыши в памяти. Будет возвращен результат true, если драйвер загружен и false, если драйвер отсутствует или не совместим со стандартным интерфейсом, принятым Microsoft, но такое на моем веку не встречалось. Так что можно смело загружать драйверы MOUSE.COM, MMOUSE.COM, MOUSE.SYS и другие вручную или через AUTOEXEC.BAT. Думаю, Вас не нужно этому учить.
 
Функция состоит из двух машинных команд: mov ax,0 – загружает номер 0 функции инициализации драйвера мыши, а int 33h – вызывает обработчик интерфейса мыши (драйвер), который, как правило, позиционируется на программном прерывании $33. При этом, драйвер не только откликается и возвращает результат в регистре AX (AX = 0 – драйвера нет или AX = $0FFFF – драйвер есть), но в регистре BX он может вернуть значение $0FFFF –
стандартная мышь Microsoft с двумя клавишами, любое другое значение – мышь не стандартная. Но на это нам уже начихать ;o)
 
Кроме этого, драйвер осуществляет сброс аппаратного и программного обеспечения мыши. Т.е. все установки чувствительности и диапазона координат устанавливаются по умолчанию, курсор в центре экрана и невидим, видеостраница 0, работа пользовательского обработчика сообщений мыши заблокирована, чувствительность по горизонтали 8:8 микки/pixel, по вертикали – 16:8 микки/pixel, порог удвоения скорости равен 64 микки/сек.
 
function Ms_Init : boolean; assembler;
asm
mov ax,0; int 33h
end;
 
Пример:
 
Uses msmouse;
begin
if not Ms_Init then begin
   { выдаем сообщение об ошибке }
   writeln('Error: Mouse driver not found.');
   halt;
   end;
end.
 
С этого момента можно обращаться к драйверу мыши, и наверное, первое, что может нас заинтересовать, это “Гюльчатай, покажи личико!”, то бишь курсор, ради которого мы все это затеяли. Для исполнения нашего желания следует вызвать процедуру Ms_CurShow, которую сейчас опишем:
 
procedure Ms_CurShow; assembler;
asm
mov ax,1; int 33h
end;
 
наверно уже нет необходимости объяснять, что опять устанавливаем номер вызываемой функции и вызываем ее программным прерыванием $33. Скажу лишь, что функция с номером 1 отобразит (включит) курсор мыши, если при этом будет установлен стандартный текстовый или графический режим, коими являются текстовый режим 80x25 и графические режимы CGA, EGA, VGA (разрешение последнего 320x200). Иначе, хотя и будет считаться, что курсор включен, он будет отображаться неправильно или не будет виден вовсе, так как, например, при VESA режимах драйвер мыши не знает, как правильно рисовать курсор. Но мы ему поможем, создав еще один модуль-надстройку, но это будет немного позднее.
 
Для осуществления собственной прорисовки курсора или для чего-то еще, программисту может понадобиться скрыть (выключить) курсор процедурой Ms_CurHide, которая вызывает функцию драйвера с номером 2.
 
procedure Ms_CurHide; assembler;
asm
mov ax,2; int 33h
end;
 
При этом, следует помнить, что если курсор мыши был выключен подряд определенное количество раз, то для его включения следует столько же раз выполнить процедуру включения. Я уже вижу, как у некоторых читателей рука тянется к какому-нибудь тяжелому предмету, чтобы запустить в меня. Для тех, кто готов метнуть в меня камнем, скажу, что это придумал не я, а пресловутый Micro… Все камни прошу завернуть в яркую подарочную бумагу и послать посылкой в главный офис Microsoft, а лучше прямо на виллу резиденции гражданина Билла, как это делал кот Матроскин, посылая Шарику кочергу ;o)
 
Особо любопытных могут заинтересовать две функции Ms_X и Ms_Y, которые возвращают координаты курсора мыши в пикселях соответственно по горизонтали и вертикали. Даже если курсор мыши будет невидим, он все равно способен перемещаться, иначе зачем нам была бы нужна ента мышь белая ;o)
 
При этом вызывается функция 3 драйвера мыши, которая дает исчерпывающую информацию о положении курсора в регистрах CX – X, DX – Y и состоянии клавиш в регистре BX. Биты 0,1 и 2 отвечают за левую (Left), правую (Right) и среднюю (Middle) клавиши соответственно, где нулевое значение бита – означает, что клавиша отпущена, а 1 – клавиша нажата. Но в данном случае, на мой взгляд, удобней читать координаты отдельно, а состояние клавиш отдельно. Хотя это и не рационально с точки зрения беспокойства для драйвера, но он не будет за это на нас в обиде.
 
function Ms_X : word; assembler;
asm
mov ax,3; int 33h; mov ax,cx
end;
 
function Ms_Y : word; assembler;
asm
mov ax,3; int 33h; mov ax,dx
end;
 
Если возникнет непреодолимое желание установить курсор где-то в другом месте экрана, то в этом сможет помочь процедура Ms_SetPosition, которая позиционирует курсор мыши с новыми координатами X и Y, даже если он невидим. В итоге, регистр CX будет загружен значением параметра X, а регистр DX значением параметра Y и будет вызвана функция 4 драйвера.
 
procedure Ms_SetPosition(x, y : word); assembler;
asm
mov ax,4; mov cx,x; mov dx,y; int 33h
end;
 
Для тех, кто, читая данный толмут, успел себе задать (риторический) вопрос “А где же у него кнопка?!…”, внятный ответ сможет дать функция Ms_State, которая возвращает результат типа byte, последний можно легко привести к типу TMouseState путем нехитрой комбинации byte(MouseState):=Ms_State, где MouseState – переменная, заранее описанная с типом TMouseState.
 
function Ms_State : byte; assembler;
asm
mov ax,3; int 33h; mov ax,bx
end;
 
Как Вы могли заметить, в данном случае вызывается все та же функция 3 драйвера, рассмотренная выше. Пример:
 
var
MouseState : TMouseState;
begin
repeat
 byte(MouseState) := Ms_State;
  if mbLeft in MouseState then begin
    …
    end;
until mbRight in MouseState;
end.
 
иллюстрирует использование функции Ms_State. При нажатии левой клавиши (mbLeft) выполняется некоторое действие, а при нажатии правой клавиши (mbRight) цикл прекращается.
 
Основываясь на функции Ms_State, можно расширить функциональность модуля, описав функцию Ms_Down, которая позволяет определить, нажата ли затребованная клавиша Button в данный момент. Если да, то вернет true, если нет – false.
 
function Ms_Down(Button : TMouseButton):boolean;
var State : TMouseState;
begin
Ms_Down := false;
byte(State) := Ms_State;
if Button in State then Ms_Down := true;
end;
 
Тогда, уже известный Вам пример будет выглядеть гораздо нагляднее и эффективнее с точки зрения экономии памяти сегмента данных:
 
begin
repeat
 …
  if Ms_Down(mbLeft) then begin
     …
     end;
until Ms_Down(mbRight);
end.
 
Вы со мной согласны? Не слышу? Ладно, молчание – знак согласия ;O)
Следующая функция может помочь в отслеживании полного нажатия-отпускания клавиши (клик – Click). Достаточно лишь указать нужную клавишу и функция вернет true, если клавиша была нажата и теперь отпущена, или false – если нет. Возможно, у кого-то возникнет вопрос: “А почему нельзя просто отследить отпускание клавиши? Ведь раз произошло отпускание, значит, было и нажатие”. Дело в том, что если просто проверять состояние клавиши, то очень часто может оказаться, что клавиша отпущена и получится, что будет многократно опознано отпускание клавиши, даже когда уже это отпускание было обработано ранее. Именно для того, чтобы устранить такое многократное срабатывание, и нужна функция Ms_Click. Правда, ее следует постоянно вызывать в теле некоторого цикла, чтобы не проморгать момент нажатия и отпускания клавиши. И тогда она зарегистрирует нажатие нужной клавиши в переменной Ms_ButtonFlag и затем, при отпускании сообщит нам.
 
function Ms_Click(Button : TMouseButton):boolean;
var State : TMouseState;
begin
Ms_Click := false;
byte(State) := Ms_State;
{если ранее нажатие клавиши было зарегистрировано}
if Ms_ButtonFlag[Button] then begin
   {то проверяем, отпущена ли она теперь}
   if not (Button in State) then begin
      {раз отпущена, то констатируем событие “Click”}
      Ms_Click := true;
      Ms_ButtonFlag[Button] := false;
     end;
  end
  else if Button in State then
            {это лишь нажатие, и его следует зарегистрировать}
            Ms_ButtonFlag[Button] := true;
end;
 
Все тот же пример теперь будет выглядеть немного иначе:
 
begin
repeat
  …
  if Ms_Click(mbLeft) then begin
     …
    end;
until Ms_Click(mbRight);
end.
 
Обычно, чувствительность мыши по умолчанию вполне приемлема, но все же может возникнуть необходимость регулировать чувствительность мыши к перемещению. Для этого пригодится процедура Ms_SetMickey. Надо лишь задать величину, на сколько микки нужно передвинуть корпус мышки, чтобы переместиться на 8 точек по экрану по горизонтали и вертикали.
 
Таким образом, чем меньше величины параметров Horiz, Vertic тем чувствительнее (быстрее) будет двигаться курсор и наоборот, если установить эти величины очень большими, то возможно придется проехать мышкой пол стола, чтобы добраться ее курсором до границы экрана ;o)
В данном случае параметр Horiz загружается в регистр CX, а Vertic а регистр DX и вызывается функция $0f драйвера.
 
procedure Ms_SetMickey( Horiz, Vertic : word ); assembler;
asm
mov ax,0fh; mov cx,Horiz; mov dx,Vertic; int 33h
end;
 

Литература

1. Диалоговая справочная система Norton Guide.
 
Продолжение следует…
 
© Владислав Демьянишин
 
 
На нашем сайте можно не только бесплатно скачать игры, но и документацию и книги по программированию на MIDLetPascal, Turbo Pascal 6, Turbo Pascal 7, Borland Pascal, по программированию устройств Sound Blaster, Adlib, VESA BIOS, справочник Norton Guide и много другой полезной информации для программистов, включая примеры решения реальных задач по созданию резидентных программ.
 

Журнал > Программирование > Паскаль для новичков (Turbo Pascal, Assembler) > Паскаль для новичков (часть 20): Спрашивали? Отвечаю... Дружба с Микки Маусом (часть 1)
 
 
 
 
 
 
На главную страницу На предыдущую страницу На начало страницы