Path: blob/trunk/cpp/webdriver-interactions/event_firing_thread.cpp
2867 views
/*1Licensed to the Software Freedom Conservancy (SFC) under one2or more contributor license agreements. See the NOTICE file3distributed with this work for additional information4regarding copyright ownership. The SFC licenses this file5to you under the Apache License, Version 2.0 (the "License");6you may not use this file except in compliance with the License.7You may obtain a copy of the License at89http://www.apache.org/licenses/LICENSE-2.01011Unless required by applicable law or agreed to in writing, software12distributed under the License is distributed on an "AS IS" BASIS,13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14See the License for the specific language governing permissions and15limitations under the License.16*/1718#include "stdafx.h"19#include "event_firing_thread.h"2021// Defaults to false, unless the driver explicitly turns this on.22static bool gEnablePersistentEventFiring = false;23// Thread for firing event24HANDLE hConstantEventsThread = NULL;25class EventFiringData26{27public:28EventFiringData(HWND directInputTo, long onX, long onY, WPARAM buttonValue) :29m_shouldFire(true), m_keepRunning(true),30m_to(directInputTo), m_x(onX), m_y(onY), m_buttonState(buttonValue) { }31// Used to control temporary firing of events.32void pauseFiring() { m_shouldFire = false; }33void resumeFiring() { m_shouldFire = true; }34bool shouldFire() { return m_shouldFire; }35// Used to control the existance of the background thread:36// when shouldRun returns false the thread will exit.37void stopRunning() { m_keepRunning = false; }38bool shouldRun() { return m_keepRunning; }3940// Information on where to send the event to.41HWND getTarget() { return m_to; }42long getXLocation() { return m_x; }43long getYLocation() { return m_y; }44WPARAM getInputDevicesState() { return m_buttonState; }4546// Update the keyboard state.47void setInputDevicesState(WPARAM buttonValue) { m_buttonState = buttonValue; }4849// Fire events to a new window / coordinates.50void setNewTarget(HWND directInputTo, long onX, long onY, WPARAM buttonValue)51{52m_to = directInputTo;53m_x = onX;54m_y = onY;55m_buttonState = buttonValue;56}5758private:59bool m_shouldFire;60bool m_keepRunning;61HWND m_to;62long m_x, m_y;63WPARAM m_buttonState;64};6566// Function passed to the thread.67DWORD WINAPI MouseEventFiringFunction(LPVOID lpParam)68{69EventFiringData* firingData;7071firingData = (EventFiringData*) lpParam;72// busy-wait loop, waiting for 10 milliseconds between73// dispatching events. Since the thread is usually74// paused for short periods of time (tens of milliseconds),75// a more modern signalling method was not used.76while (firingData->shouldRun()) {77if (firingData->shouldFire()) {78HWND target = firingData->getTarget();79if (IsWindow(target)) {80SendMessage(firingData->getTarget(),81WM_MOUSEMOVE, firingData->getInputDevicesState(),82MAKELPARAM(firingData->getXLocation(),83firingData->getYLocation()));84}85}86Sleep(10 /* ms */);87}8889return 0;90}9192EventFiringData* EVENT_FIRING_DATA;9394void pausePersistentEventsFiring()95{96if (!gEnablePersistentEventFiring) {97// Persistent event firing is disabled.98return;99}100if ((hConstantEventsThread != NULL) && (EVENT_FIRING_DATA != NULL)) {101EVENT_FIRING_DATA->pauseFiring();102Sleep(10 /* ms */);103}104}105106// Helper method to update the state of a given flag according to a toggle.107static void setStateByFlag(bool shouldSetFlag, UINT flagValue)108{109if (!gEnablePersistentEventFiring) {110// Persistent event firing is disabled.111return;112}113if ((hConstantEventsThread == NULL) || (EVENT_FIRING_DATA == NULL)) {114return;115}116117WPARAM currentInputState = EVENT_FIRING_DATA->getInputDevicesState();118if (shouldSetFlag) {119currentInputState |= flagValue;120} else {121currentInputState = currentInputState & (~flagValue);122}123EVENT_FIRING_DATA->setInputDevicesState(currentInputState);124}125126void updateShiftKeyState(bool isShiftPressed)127{128setStateByFlag(isShiftPressed, MK_SHIFT);129}130131void updateLeftMouseButtonState(bool isButtonPressed)132{133setStateByFlag(isButtonPressed, MK_LBUTTON);134}135136// Creates a new thread if there isn't one up and running.137void resumePersistentEventsFiring(138HWND inputTo, long toX, long toY, WPARAM buttonValue)139{140if (!gEnablePersistentEventFiring) {141// Persistent event firing is disabled.142return;143}144145if (hConstantEventsThread == NULL) {146EVENT_FIRING_DATA = new EventFiringData(inputTo, toX, toY, buttonValue);147hConstantEventsThread = CreateThread(148NULL, // Security permissions.1490, // default stack size.150MouseEventFiringFunction,151EVENT_FIRING_DATA,1520, // default creation flags153NULL);154} else {155EVENT_FIRING_DATA->setNewTarget(inputTo, toX, toY, buttonValue);156EVENT_FIRING_DATA->resumeFiring();157}158}159160void resumePersistentEventsFiring()161{162if (!gEnablePersistentEventFiring) {163// Persistent event firing is disabled.164return;165}166if ((hConstantEventsThread == NULL) || (EVENT_FIRING_DATA == NULL)) {167return;168}169EVENT_FIRING_DATA->resumeFiring();170}171172extern "C" {173// Terminates the background thread.174void stopPersistentEventFiring()175{176if ((hConstantEventsThread != NULL) && (EVENT_FIRING_DATA != NULL)) {177EVENT_FIRING_DATA->stopRunning();178WaitForSingleObject(hConstantEventsThread, 2500 /* ms */);179CloseHandle(hConstantEventsThread);180hConstantEventsThread = NULL;181delete EVENT_FIRING_DATA;182EVENT_FIRING_DATA = NULL;183}184}185186void setEnablePersistentHover(bool enablePersistentHover)187{188gEnablePersistentEventFiring = enablePersistentHover;189}190}191192193