Consideram-se ações de Utilizador os eventos ocorridos no click/duplo click do rato e
teclas premidas. Para a captura das ações de utilizador, será utilizada uma biblioteca
denominada "HookManager". A biblioteca é open source e permite utilizar os recursos da
biblioteca user32.dll do Windows para "escutar" os eventos ocorridos com o rato e teclado
(Mamaladze, 2011).
24
Desta biblioteca iremos utilizar a função "MouseDoubleClick", como ilustra a Figura 11,
para criar o evento de “escuta” para as ações de rato, click e duplo click. Esta função é
responsável por criar também a função de controlo do evento click do duplo click, para isso é
utilizado a função "GetDoubleClickTime" da biblioteca user32.dll para saber qual o tempo de
duplo click que se encontra definido no computador, esta parte é adaptável a qualquer
computador, para aplicar ao timer "s_DoubleClickTimer".
public static event MouseEventHandler MouseDoubleClick
{
add
{
EnsureSubscribedToGlobalMouseEvents();
if (s_MouseDoubleClick == null)
{
//We create a timer to monitor interval between two clicks
s_DoubleClickTimer = new Timer
{
//This interval will be set to the value we retrive from windows. This is a
windows setting from contro planel.
Interval = GetDoubleClickTime(),
//We do not start timer yet. It will be start when the click occures.
Enabled = false
};
//We define the callback function for the timer
s_DoubleClickTimer.Tick += DoubleClickTimeElapsed;
//We start to monitor mouse up event.
s_MouseDown += OnMouseUp;
}
s_MouseDoubleClick += value;
}
remove
{
if (s_MouseDoubleClick != null)
{
s_MouseDoubleClick -= value;
if (s_MouseDoubleClick == null)
{
//Stop monitoring mouse up
s_MouseDown -= OnMouseUp;
//Dispose the timer
s_DoubleClickTimer.Tick -= DoubleClickTimeElapsed;
s_DoubleClickTimer = null;
}
}
TryUnsubscribeFromGlobalMouseEvents();
}
}
25
A função "EnsureSubscribedToGlobalMouseEvents", como ilustra a Figura 12, é
responsável por criar o evento de "escuta/espera do acontecimento" para a captura dos
eventos do rato, a função "SetWindowsHookEx" é sempre executada sempre que existe um
click do rato, e este evento é adicionado à aplicação criada. O parâmetro de entrada
"WH_MOUSE_LL" serve para indicar qual o tipo de "escuta" que se pretende observar. A
variável "s_MouseDelegate" contém a informação da função de retorno, que é onde será
tratado os eventos recebidos.
Para que a aplicação não detete os eventos executados na aplicação que vai ser criada, foi
criada uma variável global que guarda o identificador do processo da aplicação, para que depois
os eventos sejam descartados sempre que haja alguma interação por parte do utilizador na
aplicação. Caso contrário iria abrir sempre a região para recorte da imagem.
private static void EnsureSubscribedToGlobalMouseEvents()
{
// install Mouse hook only if it is not installed and must be installed
if (s_MouseHookHandle == 0)
{
//See comment of this field. To avoid GC to clean it up.
s_MouseDelegate = MouseHookProc;
GlobalFunctions.idProgram = Process.GetCurrentProcess().Id;
//install hook
using (ProcessModule module = Process.GetCurrentProcess().MainModule)
{
s_MouseHookHandle = SetWindowsHookEx(WH_MOUSE_LL, s_MouseDelegate,
GetModuleHandle(module.ModuleName), 0);
}
//If SetWindowsHookEx fails.
if (s_MouseHookHandle == 0)
{
//Returns the error code returned by the last unmanaged function called using
platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//do cleanup
//Initializes and throws a new instance of the Win32Exception class with the
specified error.
throw new Win32Exception(errorCode);
}
}
}
26
A função “TryUnsubscribeFromGlobalMouseEvents”, ilustrada na Figura 13, é responsável
pela destruição das "escutas" criadas para a captura das ações de rato. Esta função só é
invocada quando é desligada a gravação do teste.
private static void TryUnsubscribeFromGlobalMouseEvents()
{
//if no subsribers are registered unsubsribe from hook
if (s_MouseClick == null ||
s_MouseDown == null ||
s_MouseMove == null ||
s_MouseUp == null ||
s_MouseClickExt == null ||
s_MouseMoveExt == null ||
s_MouseWheel == null)
{
ForceUnsunscribeFromGlobalMouseEvents();
}
}
private static void ForceUnsunscribeFromGlobalMouseEvents()
{
if (s_MouseHookHandle != 0)
{
//uninstall hook
int result = UnhookWindowsHookEx(s_MouseHookHandle);
//reset invalid handle
s_MouseHookHandle = 0;
//Free up for GC
s_MouseDelegate = null;
//if failed and exception must be thrown
if (result == 0)
{
//Returns the error code returned by the last unmanaged function called using
platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//Initializes and throws a new instance of the Win32Exception class with the
specified error.
throw new Win32Exception(errorCode);
}
}
}
27
Da mesma biblioteca irá utilizar-se a função "KeyDown", ilustrada na Figura 14, para criar
o evento de "escuta" para as ações do teclado. Nesta função irá ser criado a "escuta"
responsável pela captura dos eventos das teclas. Para isso será utilizado a mesma função
"SetWindowsHookEx" para criar os eventos do teclado. Para este caso o parâmetro de entrada
"WH_KEYBOARD_LL" serve para indicar qual o tipo de "escuta" que tem de observar. A variável
public static event KeyEventHandler KeyDown
{
add
{
EnsureSubscribedToGlobalKeyboardEvents();
s_KeyDown += value;
}
remove
{
s_KeyDown -= value;
TryUnsubscribeFromGlobalKeyboardEvents();
}
}
private static void EnsureSubscribedToGlobalKeyboardEvents()
{
// install Keyboard hook only if it is not installed and must be installed
if (s_KeyboardHookHandle == 0)
{
//See comment of this field. To avoid GC to clean it up.
s_KeyboardDelegate = KeyboardHookProc;
//install hook
using (ProcessModule module = Process.GetCurrentProcess().MainModule)
{
s_KeyboardHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, s_KeyboardDelegate,
GetModuleHandle(module.ModuleName), 0);
}
//If SetWindowsHookEx fails.
if (s_KeyboardHookHandle == 0)
{
//Returns the error code returned by the last unmanaged function called
using platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//do cleanup
//Initializes and throws a new instance of the Win32Exception class with the
specified error.
throw new Win32Exception(errorCode);
}
}
}
28
"s_KeyboardDelegate" contém a informação da função de retorno. Os eventos recebidos são
tratados nesta função.
A função "TryUnsubscribeFromGlobalKeyboardEvents", ilustrada na Figura 15, é
responsável pela destruição dos eventos adicionados para a escuta dos eventos do teclado. A
função “UnhookWindowsHookEx” recebe como argumento a função de "escuta" e remove a
captura dos eventos do teclado.
private static void TryUnsubscribeFromGlobalKeyboardEvents()
{
//if no subsribers are registered unsubsribe from hook
if (s_KeyDown == null && _KeyUp == null && s_KeyPress == null)
{
ForceUnsunscribeFromGlobalKeyboardEvents();
}
}
private static void ForceUnsunscribeFromGlobalKeyboardEvents()
{
if (s_KeyboardHookHandle != 0)
{
//uninstall hook
int result = UnhookWindowsHookEx(s_KeyboardHookHandle);
//reset invalid handle
s_KeyboardHookHandle = 0;
//Free up for GC
s_KeyboardDelegate = null;
//if failed and exception must be thrown
if (result == 0)
{
//Returns the error code returned by the last unmanaged function called using
platform invoke that has the DllImportAttribute.SetLastError flag set.
int errorCode = Marshal.GetLastWin32Error();
//Initializes and throws a new instance of the Win32Exception class with the
specified error.
throw new Win32Exception(errorCode);
}
}
}
No documento
Sistema de Apoio à Geração e Automatização de Tarefas
(páginas 30-36)