spiegel-keyman/windows/src/engine/keyman32/serialkeyeventclient.cpp
2018-10-19 05:34:48 +11:00

164 lines
4.3 KiB
C++

#include "pch.h"
#include "serialkeyeventclient.h"
#include "security.h"
//
// Client application functionality
//
class SerialKeyEventClient : public ISerialKeyEventClient {
private:
HANDLE m_hKeyEvent = 0;
HANDLE m_hKeyMutex = 0;
HANDLE m_hMMF = 0;
SerialKeyEventSharedData *m_pSharedData = NULL;
public:
SerialKeyEventClient() {
//
// Initialisation
//
m_pSharedData = NULL;
m_hKeyEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, GLOBAL_KEY_EVENT_NAME);
if (m_hKeyEvent == 0) {
DebugLastError("OpenEvent");
return;
}
m_hKeyMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, GLOBAL_KEY_MUTEX_NAME);
if (m_hKeyMutex == 0) {
DebugLastError("OpenMutex");
return;
}
m_hMMF = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, GLOBAL_FILE_MAPPING_NAME);
if (m_hMMF == 0) {
DebugLastError("OpenFileMapping");
return;
}
m_pSharedData = (SerialKeyEventSharedData *)MapViewOfFile(m_hMMF, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(SerialKeyEventSharedData));
if (!m_pSharedData) {
DebugLastError("MapViewOfFile");
return;
}
}
SerialKeyEventClient::~SerialKeyEventClient() {
if (m_pSharedData != NULL) {
if (!UnmapViewOfFile(m_pSharedData)) {
DebugLastError("UnmapViewOfFile");
}
}
if (m_hMMF != NULL) {
if (!CloseHandle(m_hMMF)) {
DebugLastError("CloseHandle(m_hMMF)");
}
}
if (m_hKeyMutex != NULL) {
if (!CloseHandle(m_hKeyMutex)) {
DebugLastError("CloseHandle(m_hKeyMutex)");
}
}
if (m_hKeyEvent != NULL) {
if (!CloseHandle(m_hKeyEvent)) {
DebugLastError("CloseHandle(m_hKeyEvent)");
}
}
}
/**
Provide a copy of the input data to the Key Event Sender thread and signal it
to send the input back to the client application.
*/
BOOL SerialKeyEventClient::SignalServer(PINPUT pInputs, DWORD nInputs) {
if (m_pSharedData == NULL) {
// Initialisation failed, don't even try
return FALSE;
}
//
// Check inputs
//
if (nInputs > MAX_KEYEVENT_INPUTS) {
SendDebugMessageFormat(0, sdmGlobal, 0, "Too many INPUT events for queue (%d)", nInputs);
nInputs = MAX_KEYEVENT_INPUTS;
}
if (nInputs == 0) {
// Don't need to signal sender, nothing to send
return TRUE;
}
//
// Capture the mutex and copy input buffer into global shared buffer. We have a fairly
// short buffer here to avoid stalling the active application for too long if for some
// reason Keyman's g_SerialKeyEventServer thread is not responding.
//
switch (WaitForSingleObject(m_hKeyMutex, 500)) {
case WAIT_OBJECT_0:
break;
case WAIT_TIMEOUT:
SendDebugMessage(0, sdmGlobal, 0, "Timed out waiting to send input to host app");
return FALSE;
case WAIT_ABANDONED_0:
SendDebugMessage(0, sdmGlobal, 0, "Host app closed mutex");
return FALSE;
case WAIT_FAILED:
default:
DebugLastError("WaitForSingleObject");
return FALSE;
}
//
// Copy the INPUT objects into our cross-platform-safe structure
//
m_pSharedData->nInputs = nInputs;
for (DWORD i = 0; i < nInputs; i++) {
m_pSharedData->inputs[i].wVk = pInputs[i].ki.wVk;
m_pSharedData->inputs[i].wScan = pInputs[i].ki.wScan;
m_pSharedData->inputs[i].dwFlags = pInputs[i].ki.dwFlags;
m_pSharedData->inputs[i].time = pInputs[i].ki.time;
m_pSharedData->inputs[i].extraInfo = pInputs[i].ki.dwExtraInfo;
}
//
// Force CPU to complete all memory operations before we signal the host
//
MemoryBarrier();
//
// Release the mutex and signal the host application to process the input
//
if (!ReleaseMutex(m_hKeyMutex)) {
DebugLastError("ReleaseMutex");
return FALSE;
}
if (!SetEvent(m_hKeyEvent)) {
DebugLastError("SetEvent");
return FALSE;
}
return TRUE;
}
};
void ISerialKeyEventClient::Startup() {
PKEYMAN64THREADDATA _td = ThreadGlobals();
if (_td) {
_td->pSerialKeyEventClient = new SerialKeyEventClient();
}
}
void ISerialKeyEventClient::Shutdown() {
PKEYMAN64THREADDATA _td = ThreadGlobals();
if (_td && _td->pSerialKeyEventClient) {
delete _td->pSerialKeyEventClient;
_td->pSerialKeyEventClient = NULL;
}
}