Иногда наступает момент, когда хочется отложить работу, забыть о базах данных и немного поразвлечься. Один из способов это сделать — подшутить над любимым начальником или, по крайней мере, над кем-нибудь за соседним компьютером. В Интернете можно найти множество таких «шуточных» программок, но ведь настоящие программисты пишут такие программы сами. В функциях Windows API заложено достаточно много возможностей для реализации чувства юмора программистов. Предлагаю вам ознакомиться с некоторыми из них.

Получение и изменение координат курсора.

Для получения координат курсора используется функция:

Function GetCursorPos(var lpPoint:TPoint):LongBool;

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

Для изменения координат курсора используется функция:

Function SetCursorPos(x:integer;y:integer):LongBool;

Как и предыдущая, эта функция позволяет управлять курсором в независимости от того, какая программа активна. Используя эти две функции, можно сделать простую программу, которая будет записывать положение курсора, а затем воспроизводить его, как это показано в Примере 2.

А вот в этой программке показано, как сделать курсор движущимся в противоположную сторону.

program Project1; uses MMsystem,windows; {$R *.RES} var TimerID:Cardinal; //идентификатор таймера i:integer=0; //счетчик повторений X1,Y1,X2,Y2:integer; //координаты курсора lpPoint:TPoint; //переменная для получения координат курсора Procedure Timer(uTimerID, uMessage: UINT;dwUser, dw1, dw2: DWORD) stdcall; begin if i>=20000 then //не закрывать таймер 1мс*20000=20 секунд begin timekillEvent(TimerID); //закрытие таймера exit; end; GetCursorPos(lpPoint); //получение координат курсора //делаем так, чтобы курсор двигался в другом направлении X1:=X2; Y1:=Y2; X2:=x1-(lpPoint.x-x1); Y2:=y1-(lpPoint.y-y1); //делаем курсор безразличным к границам экрана if x2<10 then x2:=GetSystemMetrics(SM_CXSCREEN)-10; if y2<10 then y2:=GetSystemMetrics(SM_CYSCREEN)-10; if x2>GetSystemMetrics(SM_CXSCREEN)-10 then x2:=10; if y2>GetSystemMetrics(SM_CYSCREEN)-10 then y2:=10; SetCursorPos(x2,y2); //устанавливаем позицию курсора inc(i); //увеличиваем счетчик end; begin GetCursorPos(lpPoint); //Узнаем начальное положение курсора X2:=lpPoint.x; Y2:=lpPoint.y; //создаем мультимедийный таймер с интервалом в 1 мс TimerID:=timeSetEvent(1,0,@Timer,0,TIME_PERIODIC); while i<20000 do //не закрывать программу, пока i меньше 20000 end.

Обратите внимание, что откомпилированная программа занимает 18 Кб. Это связано с тем, что в программе не используется модуль Forms, и вместо стандартных для Delphi screen.width и screen.height используется вызов функций API GetSystemMetrics(SM_CXSCREEN) и GetSystemMetrics(SM_CYSCREEN).

Получение информации о состоянии клавиши.

О состоянии клавиши на клавиатуре или мышке мы можем узнать из функции

Function GetKeyState(nVirtKey:integer):Smallint

Вот несколько строчек, наглядно демонстрирующих использование этой функции:

var sm:smallint; begin sm:=GetKeyState(VK_NUMLOCK); if Hi(sm)>0 then ShowMessage('key is down') else ShowMessage('key is up'); if Lo(sm)>0 then ShowMessage('toggled') else ShowMessage('untoggled'); end;

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

Имитация нажатия пользователем клавиш.

А теперь самое интересное. Оказывается, в Windows есть функции, позволяющие имитировать нажатие пользователем клавиш:

Procedure keybd_event(bVk:byte;bScan:byte;dwFlags:cardinal;dwExtraInfo:Cardinal);

Начиная с Windows 98 и Windows NT 4.0 SP3, Microsoft рекомендует использовать функцию:

Function SendInput(cInputs:Cardinal; var pInputs:tagINPUT; cbSize:integer):Cardinal;

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

procedure Delay(seconds,Millisec:Word); //Процедура паузы var TimeOut:TDateTime; begin TimeOut:=Now+EncodeTime(0,seconds div 60,seconds mod 60,millisec); //Чтобы программа не зависла, продолжаем обрабатывать сообщения while Now0) then begin //Если в верхнем регистре, значит, нужно «нажать» Shift keybd_event(VK_SHIFT,0,0,0); //Пауза для имитации работы человека Delay(0,random(100)+100); //Нажимаем на кнопку keybd_event(Lo(VkKeyScan(s[i])),0,0,0); //Пауза для имитации работы человека Delay(0,random(300)); //Отпускаем кнопку keybd_event(Lo(VkKeyScan(s[i])),0,KEYEVENTF_KEYUP,0); //Пауза для имитации работы человека Delay(0,random(100)+100); //отпускаем Shift keybd_event(VK_SHIFT,0,KEYEVENTF_KEYUP,0); end else begin //в нижнем регистре keybd_event(Lo(VkKeyScan(s[i])),0,0,0); Delay(0,random(400)); keybd_event(Lo(VkKeyScan(s[i])),0,KEYEVENTF_KEYUP,0); end; end; end;

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

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