kmonad-0.4.1: c_src/keyio_win.c
// Necessary to get mingw to compile for some reason
/* #define WINVER 0x0601 */
/* #define _WIN32_WINNT 0x0601 */
#include <windows.h>
#include <stdbool.h>
#include <stdio.h>
// Type of the key event: 0 Press, 1 Release, 2 Repeat
typedef unsigned char ACTION;
ACTION KEY_PRESS = 0;
ACTION KEY_RELEASE = 1;
// All the information KMonad needs about a key-event
struct KeyEvent {
ACTION type;
DWORD keycode;
} KeyEvent;
// Variables we need to access globally
HANDLE readPipe = NULL;
HANDLE writePipe = NULL;
HHOOK hookHandle;
// Print last error and exit program
void last_error()
{ LPVOID lpMsgBuf;
DWORD dw = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL);
//printf("C: Error: %s", lpMsgBuf);
exit(dw);
}
// Callback we insert into windows that writes events to pipe
LRESULT CALLBACK keyHandler(int nCode, WPARAM wParam, LPARAM lParam)
{
// Cast the lParam to a keyboard-event struct
KBDLLHOOKSTRUCT* e = (KBDLLHOOKSTRUCT*)(lParam);
// Skip processing if nCode is 0 or this is an injected event
if (nCode < 0 || e->flags & LLKHF_INJECTED) {
return CallNextHookEx(hookHandle, nCode, wParam, lParam);
};
// Create the KEY_EVENT matching the current event
ACTION type;
switch (wParam) {
case WM_KEYDOWN:
type = KEY_PRESS;
break;
case WM_SYSKEYDOWN:
type = KEY_PRESS;
break;
case WM_KEYUP:
type = KEY_RELEASE;
break;
case WM_SYSKEYUP:
type = KEY_RELEASE;
break;
};
// Construct the KeyEvent to write to the pipe
struct KeyEvent ev;
ev.type = type;
ev.keycode = e->vkCode;
// Write the event to the pipe
DWORD dwWritten;
WriteFile(writePipe, &ev, sizeof(ev), &dwWritten, NULL);
}
// Read an event from the pipe and write it to the provided pointer
void wait_key(struct KeyEvent* e)
{
DWORD dwRead;
ReadFile(readPipe, e, sizeof(e), &dwRead, NULL);
//printf("receiving: %d\n", e->keycode);
return;
}
// Insert the keyboard hook and start the monitoring process
int grab_kb()
{
// Insert the hook, error on failure
hookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, keyHandler, NULL, 0);
if (hookHandle == NULL) last_error();
// Create the pipe, error on failure
if ( !CreatePipe(&readPipe, &writePipe, NULL, 0) ) last_error();
// This *never* triggers, but if not included the program doesn't run..?
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{ TranslateMessage(&msg);
DispatchMessage(&msg); }
}
// Uninstall the keyboard hook and kill the process
int release_kb()
{
UnhookWindowsHookEx(hookHandle);
PostQuitMessage(0);
return(0);
}
// Send key to the OS
void sendKey(struct KeyEvent* e)
{
INPUT ip;
// Standard stuff we don't use
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.wVk = e->keycode;
switch (e->type) {
case 0:
ip.ki.dwFlags = 0;
break;
case 1:
ip.ki.dwFlags = KEYEVENTF_KEYUP;
break;
}
//printf("emitting kc: %d\n", ip.ki.wVk);
// Emit the event to the OS
SendInput(1, &ip, sizeof(INPUT));
}
// OLD STUFF FOR FUTURE REFERENCE
// Tell windows to start sending all keyboard events to hTarget
/* bool HID_RegisterDevice(HWND hTarget, USHORT usage)
{
RAWINPUTDEVICE hid[1];
hid[0].usUsagePage = 0x01;
hid[0].usUsage = usage;
hid[0].dwFlags = RIDEV_INPUTSINK; // RIDEV_DEVNOTIFY RIDEV_NOLEGACY
hid[0].hwndTarget = hTarget;
return RegisterRawInputDevices(&hid, 1, sizeof(RAWINPUTDEVICE));
}
*/
/* void grab_keyboard(HWND hTarget)
{
RAWINPUTDEVICE ri[1];
ri[0].usUsagePage = 0x01;
ri[0].usUsage = 0x06;
ri[0].dwFlags = RIDEV_NOLEGACY | RIDEV_INPUTSINK;
ri[0].hwndTarget = hTarget;
if (RegisterRawInputDevices(ri, 1, sizeof(ri[0])) == FALSE) {
last_error();
}
}
*/
/*
// Tell windows to stop sending all keyboard events to hTarget
void HID_UnregisterDevice(USHORT usage)
{
RAWINPUTDEVICE hid;
hid.usUsagePage = 1;
hid.usUsage = usage;
hid.dwFlags = RIDEV_REMOVE;
hid.hwndTarget = NULL;
RegisterRawInputDevices(&hid, 1, sizeof(RAWINPUTDEVICE));
} */
/* Make windows class and window
//const wchar_t CLASS_NAME[] = L"Sample Window Class";
static const char* CLASS_NAME = "MESSAGE_ONLY";
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0x0;
wc.lpszClassName = CLASS_NAME;
wc.lpfnWndProc = callback;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszMenuName = 0;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = NULL;
fprintf(stdout, "trying to make window class\n");
if ( !RegisterClassEx(&wc) ) { last_error(); }
fprintf(stdout, "succeeded");
fprintf(stdout, "hello\n");
HWND hwnd = CreateWindowEx(
0,
CLASS_NAME, // Window class
"kmonad", // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position
0,0,0,0,
HWND_MESSAGE, // Parent: message only window
NULL, // Menu
hInstance, // Instance
NULL // Additional data
);
ShowWindow(hwnd, cmd_show);
// Windows event callback
LRESULT CALLBACK callback(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
case WM_CLOSE: {
DestroyWindow(hwnd);
return 0;
}
case WM_INPUT: {
fprintf(stdout, "hello");
UINT dwSize;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
//LPBYTE lpb = new BYTE[dwSize];
//inf (lpb == NULL) {
// return 0; }
return 0;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR cmd_line, int cmd_show)
{
*/