Программные интерфейсы джойстика и таймера

Уведомления, передаваемые программе

Для сообщения программе об изменениях состояния джойстика его подсистема помещает сообщения в очередь заданного окна — это единственный возможный способ уведомления. Для получения уведомляющих сообщений устройство джойстика должно быть переведено в режим захвата.

Для сообщения об истечении заданного временного интервала подсистема таймера вызывает заданную программную функцию (callback), — это также единственный способ уведомления от таймера.

В начало

В начало

Уведомление о состоянии джойстика

Для уведомления о состоянии джойстика используются сообщения, отражающие произошедшие изменения. Константы для кодов сообщений имеют префикс MM_JOY:

  • nMOVE — изменение координат X/Y.
  • nZMOVE — изменение координаты Z.
  • nBUTTONDOWN — нажатие кнопки.
  • nBUTTONUP — отпускание кнопки.

Вместо n в именах присутствует цифра 1 или 2, обозначающая номер джойстика. Во всех сообщениях параметр wParam содержит битовую шкалу нажатых кнопок. Параметр lParam представляет значения координат: в сообщениях ZMOVE — Z (младшее слово), в остальных сообщениях — X (младшее слово) и Y (старшее слово). Для выделения координат из двойного слова удобно использовать макросы LOWORD и HIWORD.

Как видно, в подсистеме предусмотрены сообщения лишь для трехосевых джойстиков. Об изменении координат R, U, V и POV приложению никак не сообщается — для этого необходимо организовать периодический опрос собственными силами — например, по периодическому таймерному событию.

В начало

В начало

Уведомление о наступлении таймерного события

При наступлении таймерного события подсистема вызывает заданную программную функцию из специально созданной вспомогательной задачи (thread), имеющей уровень приоритета TIME_CRITICAL. Однажды созданная вспомогательная задача существует до завершения процесса; с ее помощью также выполняются все последующие отработки возникающих таймерных событий.

В начало

В начало

Набор интерфейсных функций подсистем

В отличие от ранее описанных подсистем MME, интерфейсы джойстика и таймера достаточно своеобразны и не допускают какой-либо систематизации набора функций. Поэтому все имена функций приводятся полностью, без сокращений.

В начало

В начало

Перечень интерфейсных функций

joyGetNumDevs

Запрос количества устройств джойстика

joyGetDevCaps

Запрос параметров и возможностей устройства джойстика

joyGetPos

Запрос состояния традиционного джойстика

joyGetPosEx

Запрос состояния любого джойстика

joyGetThreshold

Запрос порога чувствительности

joySetThreshold

Установка порога чувствительности

joySetCapture

Захват джойстика

joyReleaseCapture

Освобождение джойстика от захвата

timeGetDevCaps

Запрос параметров таймера

timeGetSystemTime

Запрос системного времени в виде структуры MMTIME

timeGetTime

Запрос системного времени в миллисекундах

timeBeginPeriod

Начало работы с заданным разрешением

timeEndPeriod

Конец работы с заданным разрешением

timeSetEvent

Запрос таймерного события

timeKillEvent

Отмена таймерного события

CallbackProc

Прототип функции уведомления таймера

В начало

В начало

Значения, возвращаемые интерфейсными функциями

За редким исключением, все функции интерфейса возвращают результат типа MMRESULT, эквивалентный типу UINT. Значение MMSYSERR_NOERROR, равное нулю, означает успешное выполнение функции, любое другое значение указывает на ошибку. Константы для кодов ошибок имеют префиксы MMSYSERR_ (общая ошибка мультимедийной подсистемы), JOYERR_ (ошибка подсистемы джойстика) и TIMERR_ (ошибка подсистемы таймера):

MMSYSERR_BADDEVICEID

Недопустимый номер устройства

MMSYSERR_NOTENABLED

Драйвер не активизирован

MMSYSERR_NODRIVER

Драйвер отсутствует

MMSYSERR_NOMEM

Недостаточно памяти

MMSYSERR_NOTSUPPORTED

Запрошенная функция не поддерживается

MMSYSERR_INVALFLAG

Недопустимый флаг

MMSYSERR_INVALPARAM

Недопустимый параметр

MMSYSERR_ERROR

Неопределенная ошибка

JOYERR_NOERROR

Успешное завершение запроса

JOYERR_PARMS

Недопустимые параметры запроса

JOYERR_NOCANDO

Невозможно выполнить запрос

JOYERR_UNPLUGGED

Джойстик не подключен

TIMERR_NOERROR

Успешное завершение запроса

TIMERR_NOCANDO

Невозможно выполнить запрос

TIMERR_STRUCT

Недопустимый размер структуры

В начало

В начало

Описание интерфейсных функций джойстика

joyGetNumDevs — запрос количества устройств

UINT joyGetNumDevs (void);

Возвращает количество установленных в системе устройств джойстика.

В начало

В начало

joyGetDevCaps — запрос параметров и возможностей джойстика

MMRESULT joyGetDevCaps (
    UINT DevNum,
    JOYCAPS *Caps,
    UINT CapsSize
 );

Служит для определения параметров и возможностей джойстика.

  • DevNum — номер устройства, начиная с нуля.
  • Caps — указатель структуры типа JOYCAPS.
  • CapsSize — размер структуры в байтах.

При успешном завершении функция заполняет поля переданной указателем структуры параметрами устройства.

В начало

В начало

joyGetPos — запрос текущего состояния традиционного джойстика

MMRESULT joyGetPos (
    UINT DevNum,
    JOYINFO *Info
 );
  • DevNum — номер устройства, начиная с нуля.
  • Info — указатель структуры состояния традиционного джойстика типа JOYINFO, которая будет заполнена текущими значениями позиций манипуляторов и состояний кнопок.
В начало

В начало

joyGetPosEx — запрос текущего состояния любого джойстика

MMRESULT joyGetPosEx (
    UINT DevNum,
    JOYINFOEX *Info
 );
  • DevNum — номер устройства, начиная с нуля.
  • Info — указатель структуры состояния джойстика типа JOYINFOEX, которая будет заполнена текущими значениями позиций манипуляторов и состояний кнопок.

Перед обращением к функции необходимо заполнить поля dwSize и dwFlags передаваемой структуры. Первое отражает версию программного интерфейса, а второе — режимы выполнения запроса и набор возвращаемых подсистемой параметров джойстика.

В начало

В начало

joyGetThreshold — запрос порога чувствительности к перемещению

MMRESULT joyGetThreshold (
    UINT DevNum,
    UINT *Threshold
 );
  • DevNum — номер устройства, начиная с нуля.
  • Threshold — указатель переменной типа UINT, в которую возвращается текущий порог чувствительности. Порог измеряется в логических элементарных единицах перемещения и означает максимальное перемещение по любой из координат, при котором еще не генерируются уведомляющие сообщения в режиме захвата. По умолчанию установлено нулевое значение — сообщения генерируются при перемещении на каждую элементарную единицу координаты.
В начало

В начало

joySetThreshold — установка порога чувствительности к перемещению

MMRESULT joySetThreshold (
    UINT DevNum,
    UINT Threshold
 );
  • DevNum — номер устройства, начиная с нуля.
  • Threshold — значение порога чувствительности в элементарных логических единицах перемещения.
В начало

В начало

joySetCapture — захват джойстика

MMRESULT joySetCapture (
    HWND Win,
    UINT DevNum,
    UINT Period,
    BOOL OnChange
 );
  • Win — ключ окна (window handle), которое будет получать уведомляющие сообщения от подсистемы.
  • DevNum — номер устройства, начиная с нуля.
  • Period — период опроса состояния джойстика драйвером, в миллисекундах.
  • OnChange — режим посылки уведомляющих сообщений. При значении TRUE сообщения посылаются только при изменении состояния джойстика; при значении FALSE — после каждого опроса драйвера, то есть регулярно через интервал, определяемый параметром Period. В регулярном режиме после каждого опроса джойстика драйвером посылается пара сообщений — MOVE и ZMOVE.
В начало

В начало

joyReleaseCapture — освобождение джойстика

MMRESULT joyReleaseCapture (
    UINT DevNum
 );
  • DevNum — номер устройства, начиная с нуля.

Освобождает джойстик от ранее установленного режима захвата, выполненного функцией joySetCapture, прекращая посылку уведомляющих сообщений и делая джойстик доступным для нового захвата.

В начало

В начало

Описание интерфейсных функций таймера

timeGetDevCaps — запрос параметров и возможностей таймера

MMRESULT timeGetDevCaps (
    TIMECAPS *Caps,
    UINT CapsSize
 );

Служит для определения параметров таймера — минимального и максимального поддерживаемого разрешения.

  • Caps — указатель структуры типа TIMECAPS.
  • CapsSize — размер структуры в байтах.

При успешном завершении функция заполняет поля переданной указателем структуры параметрами разрешения.

В начало

В начало

timeGetSystemTime — запрос системного времени в виде структуры

MMRESULT timeGetSystemTime (
    MMTIME *Time,
    UINT StructSize
 );
  • Time — указатель структуры типа MMTIME, в которую будет возвращено значение системного времени.
  • StructSize — размер структуры в байтах.

При успешном завершении функция заносит в поле ms значение системного времени в миллисекундах с момента загрузки системы. Поле wType функцией не рассматривается и после выполнения запроса всегда устанавливается в значение TIME_MS.

В начало

В начало

timeGetTime — запрос системного времени в миллисекундах

DWORD timeGetTime(VOID);

Возвращает значение системного времени в миллисекундах с момента загрузки системы.

В начало

В начало

timeBeginPeriod — начало работы с заданным разрешением

MMRESULT timeBeginPeriod (
    UINT Period
 );
  • Period — интервал между прерываниями аппаратного таймера, корректирующими счетчик системного времени. Значение должно лежать внутри диапазона допустимых разрешений таймера (структура TIMECAPS). Если оно выходит за пределы допустимого диапазона, используется ближайшее из предельных значений.

Функция переводит системный таймер Windows в режим с заданным разрешением, настраивая аппаратный таймер на частоту прерываний, соответствующую наивысшему из затребованных всеми приложениями разрешений. Если в системе есть приложения, установившие более высокое разрешение таймера, — частота прерываний аппаратного таймера не изменяется.

Частота обновления системного времени, получаемого функциями timeGetSystemTime, timeGetTime, GetTickCount и им подобными, определяется частотой аппаратного системного таймера.

Каждый вызов timeBeginPeriod должен быть впоследствии «закрыт» соответствующим вызовом timeEndPeriod, обозначающим блок программы, работающий с заданным разрешением.

В начало

В начало

timeEndPeriod — конец работы с заданным разрешением

MMRESULT timeEndPeriod (
    UINT Period
 );
  • Period — длительность периода таймера, определяющая разрешение, с которым завершается работа. Значение должно совпадать с указанным в предшествующем вызове функции timeBeginPeriod.

Функция завершает работу с указанным разрешением таймера, восстанавливая предыдущее разрешение.

В начало

В начало

timeSetEvent — запрос таймерного события

UINT timeSetEvent (
    UINT Delay,
    UINT Resolution,
    TIMECALLBACK *TimeProc,
    DWORD UserData,
    UINT EventType
 );
  • Delay — интервал времени до наступления таймерного события в миллисекундах.
  • Resolution — разрешение таймера при отсчете интервала, в миллисекундах. Нулевое значение требует максимально возможного разрешения. Этот параметр не увеличивает текущего разрешения системного таймера; если текущего разрешения недостаточно — необходимо использовать функцию timeBeginPeriod.
  • TimeProc — указатель функции уведомления.
  • UserData — произвольное 32-разрядное значение, передаваемое функции уведомления при вызове в качестве параметра.
  • EventType — тип таймерного события: TIME_ONESHOT — однократное, TIME_PERIODIC — периодическое.

Функция «заряжает» виртуальный таймер на заданный интервал времени, возвращая идентификатор будущего таймерного события (виртуального таймера). В случае неудачи возвращается нулевое значение. Идентификатор события передается также функции уведомления в ее вызове при наступлении события.

Однократное событие возникает единожды по истечении указанного интервала, периодическое —каждый раз по истечении промежутка времени заданной величины. Для досрочной отмены однократного события или для прекращения периодических событий необходимо использовать функцию timeKillEvent.

Одновременно приложение может запросить произвольное количество таймерных событий, каждое из которых наступает независимо от остальных.

В начало

В начало

timeKillEvent — отмена таймерного события

MMRESULT timeKillEvent (
    UINT EventId
 );
  • TimerId — идентификатор отменяемого таймерного события (виртуального таймера).

Функция отменяет таймерное событие, которое еще не произошло, а также отменяет регулярную генерацию периодического события.

Вход в функцию еще не гарантирует отмены события. Если событие наступает после входа в функцию, но до достижения точки блокировки переключения задач, то вспомогательная задача может успеть получить управление и выполнить вызов функции уведомления.

При попытке отмены уже отработанного события возвращается ошибка MMSYSERR_INVALPARAM, больше никаких действий не выполняется. Однако если с момента отработки события до вызова timeKillEvent выполняется функция timeSetEvent, то данный идентификатор события может быть назначен повторно, вследствие чего может быть ошибочно отменен. Поэтому при работе с событиями необходимо уделять пристальное внимание корректному пути выполнения блоков программы, используя системные средства синхронизации процессов.

В начало

В начало

TimerProc — функция приложения, вызываемая при уведомлении

Эта функция определяется приложением, подсистема таймера вызывает ее при выполнении уведомлений, передавая в ее аргументах параметры события. Прототип функции имеет следующий вид (имя CallbackProc приведено для примера, реальное имя выбирается приложением):

void CALLBACK CallbackProc (
    UINT EventId,
    UINT Msg,
    DWORD UserData,
    DWORD Param1,
    DWORD Param2
 );
  • EventId — идентификатор события.
  • Msg — неиспользуемый параметр.
  • UserData — 32-разрядное значение, указанное приложением при запросе события в функции timeSetEvent.
  • Param1, Param2 — неиспользуемые параметры.

В Win16 функция может вызываться в контексте обработчика прерывания, поэтому безопасно может использовать лишь ограниченный набор функций Windows: EnterCriticalSection, LeaveCriticalSection, midiOutLongMsg, midiOutShortMsg, OutputDebugString, PostMessage, PostThreadMessage, SetEvent, timeGetSystemTime, timeGetTime, timeKillEvent, timeSetEvent. Обращение к другим системным функциям, как и к функциям подсистемы, может вызвать непредсказуемые последствия.

В Win32 вызов функции выполняется из отдельной задачи, поэтому никаких ограничений на выполняемые действия не накладывается. Однако нужно помнить, что вспомогательная задача имеет приоритет TIME_CRITICAL и выполнение в ее контексте длительных операций может вызвать торможение остальных задач процесса и(или) системы.

Вспомогательная задача создается один раз и существует до полного завершения процесса. Подсистема вызывает из этой задачи функции уведомления для всех событий, которые будут запрошены за время жизни процесса.

Параметры Msg, Param1 и Param2 сохранены только в целях унификации прототипа — все подсистемы MME для удобства используют для функций уведомления один и тот же прототип.

В начало

В начало

Недостатки подсистем джойстика и таймера

Так же, как и подсистемы Wave/MIDI, подсистемы джойстика и таймера в Windows 95/98 остались 16-разрядными, как и в Windows 3.x. Из-за этого каждое обращение к ним из Win32-приложения сопровождается двойной сменой режима исполнения (thunking), приводящей к дополнительным накладным расходам. Тем не менее использование мультимедийного таймера — единственный способ достичь более высокого временного разрешения по сравнению со стандартным.

В Windows NT/2000 все подсистемы сделаны изначально 32-разрядными, поэтому описанных проблем там не возникает.

В начало

В начало

Нетрадиционные применения интерфейса джойстика

Интерфейс джойстика может использоваться не только для подключения манипуляторов. Он может рассматриваться как универсальный входной порт с четырьмя аналоговыми и четырьмя цифровыми входами.

Схемотехника аналоговых входов ориентирована на измерение сопротивлений 0..100 кОм, включенных между входом и питающим напряжением +5 В, путем измерения протекающего через вход тока. Следовательно, интерфейс может быть использован для измерения любых аналоговых величин, значения которых преобразованы в пропорциональные им токи соответствующих величин — освещенности, температуры, влажности и т.п. Нельзя только забывать о значительной погрешности метода, которая делает его непригодным для точных измерений.

Цифровые входы интерфейса могут подключаться к любым цепям, обеспечивающим замыкание входа на землю — герконам, реле, переключателям, транзисторам и выходам микросхем ТТЛ с открытым коллектором, электронным ключам и т.п. Например, при наличии источника бесперебойного питания (UPS) с простым интерфейсом, выдающим только сигнал перехода на батарейное питание, этот сигнал может быть принят через интерфейс джойстика специально написанной для этого программой, которая может инициировать нормальное завершение работы системы до того, как батарея UPS полностью разрядится и питание системы будет выключено аварийно.

С автором можно связаться по следующему адресу:

music@spider.nrcde.ru

Предюдущая страница

КомпьютерПресс 11'2000

Наш канал на Youtube

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует