Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система Microsoft Windows 3.1 для программиста

© Александр Фролов, Григорий Фролов
Том 11, М.: Диалог-МИФИ, 1993, 269 стр.

[Назад] [Содеожание] [Дальше]

6.6. Управление курсором мыши с помощью клавиатуры

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

Мы подготовили приложение MOUSEKEY, которое демонстрирует способ использования клавиатурных сообщений для перемещения курсора мыши.

Главный файл приложения приведен в листинге 6.7.


Листинг 6.7. Файл mousekey\mousekey.cpp


// ----------------------------------------
// Управление курсором мыши при
// помощи клавиатуры
// ----------------------------------------

#define STRICT
#include <windows.h>
#include <mem.h>

BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);

char const szClassName[]   = "MOUSEKEYAppClass";
char const szWindowTitle[] = "MOUSEKEY Application";

// =====================================
// Функция WinMain
// =====================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPSTR     lpszCmdLine,
        int       nCmdShow)
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  if(!InitApp(hInstance))
      return FALSE;

  hwnd = CreateWindow(
    szClassName, szWindowTitle, 
    WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, CW_USEDEFAULT,
    CW_USEDEFAULT, CW_USEDEFAULT,
    0, 0, hInstance, NULL); 

  if(!hwnd)
    return FALSE;

  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  while(GetMessage(&msg, 0, 0, 0))
  {
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// =====================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна

  memset(&wc, 0, sizeof(wc));

  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = (WNDPROC) WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon   = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszMenuName  = (LPSTR)NULL;
  wc.lpszClassName = (LPSTR)szClassName;

  aWndClass = RegisterClass(&wc);
  return (aWndClass != 0);
}

Функция WinMain создает одно главное окно и не имеет никаких особенностей.

Функция главного окна приложения приведена в листинге 6.8.


Листинг 6.8. Файл mousekey\wndproc.cpp


#define STRICT
#include <windows.h>

// Прототипы функций
int max(int value1, int value2);
int min(int value1, int value2);

// --------------------------------------------
// Функция max
// --------------------------------------------
int max(int value1, int value2)
{
  return((value1 > value2) ? value1 : value2);
}

// --------------------------------------------
// Функция min
// --------------------------------------------
int min(int value1, int value2)
{
  return((value1 < value2) ? value1 : value2);
}

// =====================================
// Функция WndProc
// =====================================
LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static POINT pt;
  RECT rc;

  switch (msg)
  {
    // Нажали клавишу
    case WM_KEYDOWN:
    {
      // Получаем текущие экранные
      // координаты курсора мыши 
      GetCursorPos(&pt);

      // Преобразуем экранные координаты
      // в оконные координаты
      ScreenToClient(hwnd, &pt);

      // Для клавиш позиционирования текстового
      // курсора изменяем соответствующим образом
      // координаты курсора мыши
      switch(wParam)
      {
        case VK_DOWN:  // вниз
        {
          pt.y += 20;
          break;
        }
        case VK_UP:    // вверх
        {
          pt.y -= 20;
          break;
        }
        case VK_LEFT:  // влево
        {
          pt.x -= 20;
          break;
        }
        case VK_RIGHT: // вправо
        {
          pt.x += 20;
          break;
        }
        // Для всех остальных клавиш
        // ничего не делаем
        default:
        {
          return 0;
        }
      }

      // Получаем координаты внутренней
      // области окна
      GetClientRect(hwnd, &rc);

      // Вычисляем новые координаты курсора мыши
      // таким образом, чтобы курсор не выходил
      // за пределы окна
      pt.x = max(min(pt.x, rc.right),  rc.left);
      pt.y = max(min(pt.y, rc.bottom), rc.top);

      // Преобразуем оконные координаты в экранные
      ClientToScreen(hwnd, &pt);

      // Устанавливаем курсор мыши
      // в новую позицию
      SetCursorPos(pt.x, pt.y);

      return 0;
    }

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

Обработчик сообщения WM_KEYDOWN вызывает функцию GetCursorPos, которая записывает текущие экранные координаты курсора мыши в структуру pt.

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

void WINAPI ScreenToClient(HWND hwnd, POINT FAR* lppt);

В качестве первого параметра функции (hwnd) указывается идентификатор окна, для которого выполняется преобразование. Второй параметр (lppt) является указателем на структуру типа POINT. В эту структуру записываются преобразованные координаты. В нашем случае это оконные координаты курсора мыши:

ScreenToClient(hwnd, &pt);

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

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

Для получения координат главного окна приложения вызывается функция GetClientRect:

GetClientRect(hwnd, &rc);

Она записывает сведения о расположении окна в структуру rc.

Далее новые координаты курсора сравниваются с границами окна приложения и при необходимости корректируются.

Для выполнения преобразования оконных координат курсора в экранные используется функция ClientToScreen:

void WINAPI ClientToScreen(HWND hwnd, POINT FAR* lppt);

Назначение параметров этой функции аналогично назначению параметров функции ScreenToClient.

После выполнения преобразования координат функция окна устанавливает курсор мыши в новое положение, для чего вызывает функцию SetCursorPos:

SetCursorPos(pt.x, pt.y);

Файл определения модуля для приложения MOUSEKEY приведен в листинге 6.9.


Листинг 6.9. Файл mousekey\mousekey.def


; =============================
; Файл определения модуля
; =============================
NAME        MOUSEKEY
DESCRIPTION 'Приложение MOUSEKEY, (C) 1994, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   5120
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple
[Назад] [Содеожание] [Дальше]