• Nenhum resultado encontrado

Captura de ações de Utilizador

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);

}

}

}

Documentos relacionados