{"id":20950444,"url":"https://github.com/colleagueriley/raw-mouse-input","last_synced_at":"2026-04-27T01:31:25.293Z","repository":{"id":252977132,"uuid":"842054181","full_name":"ColleagueRiley/raw-mouse-input","owner":"ColleagueRiley","description":"A tutorial that explains how to  lock the cursor and enable raw mouse input for X11, WinAPI, Cocoa and  Emscripten.","archived":false,"fork":false,"pushed_at":"2024-08-14T15:43:39.000Z","size":128,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-13T05:19:10.701Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ColleagueRiley.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-13T15:19:49.000Z","updated_at":"2024-12-01T09:48:25.000Z","dependencies_parsed_at":"2025-01-19T22:35:31.968Z","dependency_job_id":"ce7c97b7-55d3-46b5-9932-243e174c51e4","html_url":"https://github.com/ColleagueRiley/raw-mouse-input","commit_stats":null,"previous_names":["colleagueriley/raw-mouse-input"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ColleagueRiley/raw-mouse-input","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ColleagueRiley%2Fraw-mouse-input","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ColleagueRiley%2Fraw-mouse-input/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ColleagueRiley%2Fraw-mouse-input/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ColleagueRiley%2Fraw-mouse-input/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ColleagueRiley","download_url":"https://codeload.github.com/ColleagueRiley/raw-mouse-input/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ColleagueRiley%2Fraw-mouse-input/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32319559,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"ssl_error","status_checked_at":"2026-04-26T23:26:25.802Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T00:48:36.798Z","updated_at":"2026-04-27T01:31:25.272Z","avatar_url":"https://github.com/ColleagueRiley.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RGFW Under the Hood: Raw Mouse Input and Mouse Locking\n## Introduction \nRGFW is a lightweight single-header windowing library, its source code can be found [here](https://github.com/ColleagueRiley/RGFW). \nThis tutorial is based on its source code. \n\nWhen you create an application that locks the cursor, such as a game with a first-person camera, it's important to be able to disable the cursor.\nThis means locking the cursor in the middle of the screen and getting raw input. \n\nThe only alternative to this method would be a hack that pulls the mouse back to the center of the window when it moves. However, this is a hack so it can be buggy\nand does not work on all OSes. Therefore, it's important to properly lock the mouse by using raw input. \n\nThis tutorial explains how RGFW handles raw mouse input so you can understand how to implement it yourself. \n\n## Overview \nA quick overview of the steps required\n\n1. lock cursor\n2. center the cursor\n3. enable raw input\n4. handle raw input\n5. disable raw input\n6. unlock cursor\n\nWhen the user asks RGFW to hold the cursor, RGFW enables a bit flag that says the cursor is held.\n\n```c\nwin-\u003e_winArgs |= RGFW_HOLD_MOUSE;\n```\n\n## Step 1 (Lock Cursor) \n\nOn X11 the cursor can be locked by grabbing it via [`XGrabPointer`](https://tronche.com/gui/x/xlib/input/XGrabPointer.html)\n\n```c\nXGrabPointer(display, window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);\n```\n\nThis gives the window full control of the pointer.\n\nOn Windows, [`ClipCursor`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-clipcursor) locks the cursor to a specific rect on the screen.\nThis means we must find the window rectangle on the screen and then clip the mouse to that rectangle. \n\nAlso using: [`GetClientRect`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getclientrect])) and [`ClientToScreen`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-clienttoscreen)\n\n```c\n//First get the window size (the RGFW_window struct also includes this information, but using this ensures it's correct)\nRECT clipRect;\nGetClientRect(window, \u0026clipRect);\n\n// ClipCursor needs screen coordinates, not coordinates relative to the window\nClientToScreen(window, (POINT*) \u0026clipRect.left);\nClientToScreen(window, (POINT*) \u0026clipRect.right);\n\n// Now we can lock the cursor\nClipCursor(\u0026clipRect);\n```\n\n\nOn MacOS and Emscripten the function to enable raw input also locks the cursor. So I'll get to its function in step 4.\n\n## Step 2 (center the cursor)\nAfter the cursor is locked, it should be centered in the middle of the screen. \nThis ensures the cursor is locked in the right place and won't mess with anything else. \n\nRGFW uses an RGFW function called [`RGFW_window_moveMouse`](https://github.com/ColleagueRiley/RGFW/blob/e068aa58c71668fbce115320b66a9e8f9b868085/RGFW.h#L752) to move the mouse in the middle of the window. \n\nOn X11, [`XWarpPointer`](https://tronche.com/gui/x/xlib/input/XWarpPointer.html) can be used to move the cursor to the center of the window \n\n```c\nXWarpPointer(display, None, window, 0, 0, 0, 0, window_width / 2, window_height / 2);\n```\n\n\nOn Windows, [`SetCursorPos`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setcursorpos) is used\n\n```c\nSetCursorPos(window_x + (window_width / 2), window_y + (window_height / 2));\n```\n\nOn MacOS, [`CGWarpMouseCursorPosition`](https://developer.apple.com/documentation/coregraphics/1456387-cgwarpmousecursorposition) is used\n\n```c\nCGWarpMouseCursorPosition(window_x + (window_width / 2), window_y + (window_height / 2));\n```\n\nOn Emscripten, RGFW does not move the mouse.\n\n## Step 3 (enable raw input)\n\nWith X11, [XI](https://www.x.org/archive/X11R7.5/doc/man/man3/XISelectEvents.3.html) is used to enable raw input\n\n```c\n// mask for XI and set mouse for raw mouse input (\"RawMotion\")\nunsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };\nXISetMask(mask, XI_RawMotion);\n\n// set up X1 struct\nXIEventMask em;\nem.deviceid = XIAllMasterDevices;\nem.mask_len = sizeof(mask);\nem.mask = mask;\n\n//Enable raw input using the structure\nXISelectEvents(display, XDefaultRootWindow(display), \u0026em, 1);\n```\n\n\nOn Windows, you need to set up the RAWINPUTDEVICE structure and enable it with [`RegisterRawInputDevices`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices)\n\n```c\nconst RAWINPUTDEVICE id = { 0x01, 0x02, 0, window };\nRegisterRawInputDevices(\u0026id, 1, sizeof(id));\n```\n\nOn MacOS you only need to run [`CGAssociateMouseAndMouseCursorPosition`](https://developer.apple.com/documentation/coregraphics/1454486-cgassociatemouseandmousecursorpo)\nThis also locks the cursor by disassociating the mouse cursor and the mouse movement \n\n```c\nCGAssociateMouseAndMouseCursorPosition(0);\n```\n\nOn Emscripten you only need to request the user to lock the pointer \n\n```c\nemscripten_request_pointerlock(\"#canvas\", 1);\n```\n\n## Step 4 (handle raw input events)\n\nThese all happen during event loops.\n\n\nFor X11, you must handle the normal MotionNotify, manually converting the input to raw input.\nTo check for raw mouse input events, you need to use [`GenericEvent`](https://www.x.org/releases/X11R7.6/doc/xextproto/geproto.html).\n\n```c\nswitch (E.type) {\n    (...)\n\tcase MotionNotify:\n\t\t/* check if mouse hold is enabled */\n\t\tif ((win-\u003e_winArgs \u0026 RGFW_HOLD_MOUSE)) {\n\t\t\t/* convert E.xmotion to raw input by subtracting the previous point */\n\t\t\twin-\u003eevent.point.x = win-\u003e_lastMousePoint.x - E.xmotion.x;\n\t\t\twin-\u003eevent.point.y = win-\u003e_lastMousePoint.y - E.xmotion.y;\n\t\t}\n        \n\t\tbreak;\n\n\tcase GenericEvent: {\n\t\t/* MotionNotify is used for mouse events if the mouse isn't held */                \n\t\tif (!(win-\u003e_winArgs \u0026 RGFW_HOLD_MOUSE)) {\n\t\t\tXFreeEventData(display, \u0026E.xcookie);\n\t\t\tbreak;\n\t\t}\n\t\t\t\n\t\tXGetEventData(display, \u0026E.xcookie);\n\t\tif (E.xcookie.evtype == XI_RawMotion) {\n\t\t\tXIRawEvent *raw = (XIRawEvent *)E.xcookie.data;\n\t\t\tif (raw-\u003evaluators.mask_len == 0) {\n\t\t\t\tXFreeEventData(display, \u0026E.xcookie);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t\n\t\t\tdouble deltaX = 0.0f; \n\t\t\tdouble deltaY = 0.0f;\n\t\t\n\t\t\t/* check if relative motion data exists where we think it does */\n\t\t\tif (XIMaskIsSet(raw-\u003evaluators.mask, 0) != 0)\n\t\t\t\tdeltaX += raw-\u003eraw_values[0];\n\t\t\tif (XIMaskIsSet(raw-\u003evaluators.mask, 1) != 0)\n\t\t\t\tdeltaY += raw-\u003eraw_values[1];\n\t\t\n\t\t\t//The mouse must be moved back to the center when it moves\n\t\t\tXWarpPointer(display, None, window, 0, 0, 0, 0, window_width / 2, window_height / 2);\n\t\t\twin-\u003eevent.point = RGFW_POINT(deltaX, deltaY);\n\t\t}\n\t\t\n\t\tXFreeEventData(display, \u0026E.xcookie);\n\t\tbreak;\n\t}\n```\n\nOn Windows, you only need to handle [`WM_INPUT`](https://learn.microsoft.com/en-us/windows/win32/inputdev/wm-input) events and check for raw motion input\n\n```c\nswitch (msg.message) {\n\t(...)\n\tcase WM_INPUT: {\n\t\t/* check if the mouse is being held */\n\t\tif (!(win-\u003e_winArgs \u0026 RGFW_HOLD_MOUSE))\n\t\t\tbreak;\n\t\t\t\n\t\t/* get raw data as an array */\n\t\tunsigned size = sizeof(RAWINPUT);\n\t\tstatic RAWINPUT raw[sizeof(RAWINPUT)];\n\t\tGetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, raw, \u0026size, sizeof(RAWINPUTHEADER));\n\t\n\t\t//Make sure raw data is valid \n\t\tif (raw-\u003eheader.dwType != RIM_TYPEMOUSE || (raw-\u003edata.mouse.lLastX == 0 \u0026\u0026 raw-\u003edata.mouse.lLastY == 0) )\n\t\t\tbreak;\n\t\t\n\t\twin-\u003eevent.point.x = raw-\u003edata.mouse.lLastX;\n\t\twin-\u003eevent.point.y = raw-\u003edata.mouse.lLastY;\n\t\tbreak;\n\t}\n```\n\nOn macOS, you can check mouse input as [normal](https://developer.apple.com/documentation/appkit/nsevent/eventtype/mousemoved) while using deltaX and deltaY to fetch the mouse point \n\n```c\nswitch (objc_msgSend_uint(e, sel_registerName(\"type\"))) {\n\tcase NSEventTypeLeftMouseDragged:\n\tcase NSEventTypeOtherMouseDragged:\n\tcase NSEventTypeRightMouseDragged:\n\tcase NSEventTypeMouseMoved:\n\t\tif ((win-\u003e_winArgs \u0026 RGFW_HOLD_MOUSE) == 0) // if the mouse is not held\n                    break;\n                \n                NSPoint p;\n\t\tp.x = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName(\"deltaX\"));\n\t\tp.y = ((CGFloat(*)(id, SEL))abi_objc_msgSend_fpret)(e, sel_registerName(\"deltaY\"));\n\n\t\twin-\u003eevent.point = RGFW_POINT((i32) p.x, (i32) p.y));\n```\n\nOn Emscripten the mouse events can be checked as they [normally](Emscripten_on_mousemove) are, except we're going to use e-\u003emovementX/Y\n\n```c\nEM_BOOL Emscripten_on_mousemove(int eventType, const EmscriptenMouseEvent* e, void* userData) {\n\tif ((RGFW_root-\u003e_winArgs \u0026 RGFW_HOLD_MOUSE) == 0) // if the mouse is not held\n        \treturn\n\n    \tRGFW_point p = RGFW_POINT(e-\u003emovementX, e-\u003emovementY);\n}\n```\n\n## Step 5 (disable raw input)\nFinally, RGFW allows disabling the raw input and unlocking the cursor to revert to normal mouse input. \n\nFirst, RGFW disables the bit flag.\n\n```c\nwin-\u003e_winArgs ^= RGFW_HOLD_MOUSE;\n```\n\nIn X11, first, you must create a structure with a blank mask.\nThis will disable raw input.\n\n```c\nunsigned char mask[] = { 0 };\nXIEventMask em;\nem.deviceid = XIAllMasterDevices;\n\nem.mask_len = sizeof(mask);\nem.mask = mask;\nXISelectEvents(display, XDefaultRootWindow(display), \u0026em, 1);\n```\n\nFor Windows, you pass a raw input device structure with `RIDEV_REMOVE` to disable the raw input.\n\n```c\nconst RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };\nRegisterRawInputDevices(\u0026id, 1, sizeof(id));\n```\n\nOn MacOS and Emscripten, unlocking the cursor also disables raw input.\n\n## Step 6 (unlock cursor)\n\nOn X11, [`XUngrabPoint`](https://tronche.com/gui/x/xlib/input/XUngrabPointer.html) can be used to unlock the cursor.\n\n```c\nXUngrabPointer(display, CurrentTime);\n```\n\nOn Windows, pass a NULL rectangle pointer to ClipCursor to unclip the cursor.\n\n```c\nClipCursor(NULL);\n```\n\nOn MacOS, associating the mouse cursor and the mouse movement will disable raw input and unlock the cursor\n\n```c\nCGAssociateMouseAndMouseCursorPosition(1);\n```\n\nOn Emscripten, [exiting the pointer lock](https://emscripten.org/docs/api_reference/html5.h.html#c.emscripten_exit_pointerlock) will unlock the cursor and disable raw input.\n\n```c\nemscripten_exit_pointerlock();\n```\n\n## Full code examples\n\n### X11\n```c\n// This can be compiled with \n// gcc x11.c -lX11 -lXi\n\n#include \u003cX11/Xlib.h\u003e\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n#include \u003cstring.h\u003e\n \n#include \u003cX11/extensions/XInput2.h\u003e\n\nint main(void) {\n\tunsigned int window_width = 200;\n\tunsigned int window_height = 200;\n\t\n\tDisplay* display = XOpenDisplay(NULL);  \n\tWindow window = XCreateSimpleWindow(display, RootWindow(display, DefaultScreen(display)), 400, 400, window_width, window_height, 1, BlackPixel(display, DefaultScreen(display)), WhitePixel(display, DefaultScreen(display)));\n\t\n\tXSelectInput(display, window, ExposureMask | KeyPressMask);\n\tXMapWindow(display, window);\n\t\n\tXGrabPointer(display, window, True, PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);\n\t\n\tXWarpPointer(display, None, window, 0, 0, 0, 0, window_width / 2, window_height / 2);\n\t\n\t// mask for XI and set mouse for raw mouse input (\"RawMotion\")\n\tunsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 };\n\tXISetMask(mask, XI_RawMotion);\n\t\n\t// set up X1 struct\n\tXIEventMask em;\n\tem.deviceid = XIAllMasterDevices;\n\tem.mask_len = sizeof(mask);\n\tem.mask = mask;\n\t\n\t// enable raw input using the structure\n\tXISelectEvents(display, XDefaultRootWindow(display), \u0026em, 1);\n\t\n\tBool rawInput = True;\n\tXPoint point;\n\tXPoint _lastMousePoint;\n\t\n\tXEvent event;\n\t\n\tfor (;;) {\n\t\tXNextEvent(display, \u0026event);\n\t\tswitch (event.type) {\n\t\t\tcase MotionNotify:\n\t\t\t\t/* check if mouse hold is enabled */\n\t\t\t\tif (rawInput) {\n\t\t\t\t\t/* convert E.xmotion to rawinput by substracting the previous point */\n\t\t\t\t\tpoint.x = _lastMousePoint.x - event.xmotion.x;\n\t\t\t\t\tpoint.y = _lastMousePoint.y - event.xmotion.y;\n\t\t\t\t\tprintf(\"rawinput %i %i\\n\", point.x, point.y);\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\n\t\t\tcase GenericEvent: {\n\t\t\t\t/* MotionNotify is used for mouse events if the mouse isn't held */                \n\t\t\t\tif (rawInput == False) {\n\t\t\t\t\tXFreeEventData(display, \u0026event.xcookie);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\n\t\t\t\tXGetEventData(display, \u0026event.xcookie);\n\t\t\t\tif (event.xcookie.evtype == XI_RawMotion) {\n\t\t\t\t\tXIRawEvent *raw = (XIRawEvent *)event.xcookie.data;\n\t\t\t\t\tif (raw-\u003evaluators.mask_len == 0) {\n\t\t\t\t\t\tXFreeEventData(display, \u0026event.xcookie);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\n\t\t\t\t\tdouble deltaX = 0.0f; \n\t\t\t\t\tdouble deltaY = 0.0f;\n\t\n\t\t\t\t\t/* check if relative motion data exists where we think it does */\n\t\t\t\t\tif (XIMaskIsSet(raw-\u003evaluators.mask, 0) != 0)\n\t\t\t\t\t\tdeltaX += raw-\u003eraw_values[0];\n\t\t\t\t\tif (XIMaskIsSet(raw-\u003evaluators.mask, 1) != 0)\n\t\t\t\t\t\tdeltaY += raw-\u003eraw_values[1];\n\t\n\t\t\t\t\tpoint = (XPoint){deltaX, deltaY};\n\t\t\t\t\tXWarpPointer(display, None, window, 0, 0, 0, 0, window_width / 2, window_height / 2);\n\t\n\t\t\t\t\tprintf(\"rawinput %i %i\\n\", point.x, point.y);\n\t\t\t\t}\t\n\t\n\t\t\t\tXFreeEventData(display, \u0026event.xcookie);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase KeyPress:\n\t\t\t\tif (rawInput == False)\n\t\t\t\t\tbreak;\n\t\n\t\t\t\tunsigned char mask[] = { 0 };\n\t\t\t\tXIEventMask em;\n\t\t\t\tem.deviceid = XIAllMasterDevices;\n\t\n\t\t\t\tem.mask_len = sizeof(mask);\n\t\t\t\tem.mask = mask;\n\t\t\t\tXISelectEvents(display, XDefaultRootWindow(display), \u0026em, 1);\n\t\t\t\tXUngrabPointer(display, CurrentTime);\n\t\n\t\t\t\tprintf(\"Raw input disabled\\n\");\n\t\t\t\tbreak;\n\t\t\tdefault: break;\n\t\t}\n\t}\n\t\n\tXCloseDisplay(display);\n }\n```\n\n## Winapi\n```c\n// compile with gcc winapi.c\n\n#include \u003cwindows.h\u003e\n\n#include \u003cstdio.h\u003e\n#include \u003cstdint.h\u003e\n#include \u003cassert.h\u003e\n\nint main() {\n\tWNDCLASS wc = {0};\n\twc.lpfnWndProc   = DefWindowProc; // Default window procedure\n\twc.hInstance     = GetModuleHandle(NULL);\n\twc.lpszClassName = \"SampleWindowClass\";\n\t\n\tRegisterClass(\u0026wc);\n\t\n\tint window_width = 300;\n\tint window_height = 300;\n\tint window_x = 400;\n\tint window_y = 400;\n\t\n\tHWND hwnd = CreateWindowA(wc.lpszClassName, \"Sample Window\", 0,\n\t\t\twindow_x, window_y, window_width, window_height,\n\t\t\tNULL, NULL, wc.hInstance, NULL);\n\t\n\tShowWindow(hwnd, SW_SHOW);\n\tUpdateWindow(hwnd);\n\t\n\t// first get the window size (the RGFW_window struct also includes this informaton, but using this ensures it's correct)\n\tRECT clipRect;\n\tGetClientRect(hwnd, \u0026clipRect);\n\t\n\t// ClipCursor needs screen coords, not coords relative to the window\n\tClientToScreen(hwnd, (POINT*) \u0026clipRect.left);\n\tClientToScreen(hwnd, (POINT*) \u0026clipRect.right);\n\t\n\t// now we can lock the cursor\n\tClipCursor(\u0026clipRect);\n\t\n\tSetCursorPos(window_x + (window_width / 2), window_y + (window_height / 2));\t\n\tconst RAWINPUTDEVICE id = { 0x01, 0x02, 0, hwnd };\n\tRegisterRawInputDevices(\u0026id, 1, sizeof(id));\n\t\n\tMSG msg;\n\t\n\tBOOL holdMouse = TRUE;\n\t\n\tBOOL running = TRUE;\n\t\n\tPOINT point;\n\t\n\twhile (running) {\n\t\tif (PeekMessageA(\u0026msg, hwnd, 0u, 0u, PM_REMOVE)) {\n\t\t\tswitch (msg.message) {\n\t\t\t\tcase WM_CLOSE:\n\t\t\t\tcase WM_QUIT:\n\t\t\t\t\trunning = FALSE;\n\t\t\t\t\tbreak;\n\t\t\t\tcase WM_INPUT: {\n\t\t\t\t\t/* check if the mouse is being held */\n\t\t\t\t\tif (holdMouse == FALSE)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\t/* get raw data as an array */\n\t\t\t\t\tunsigned size = sizeof(RAWINPUT);\n\t\t\t\t\tstatic RAWINPUT raw[sizeof(RAWINPUT)];\n\t\t\t\t\tGetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, raw, \u0026size, sizeof(RAWINPUTHEADER));\n\t\t\t\t\t\n\t\t\t\t\t// make sure raw data is valid \n\t\t\t\t\tif (raw-\u003eheader.dwType != RIM_TYPEMOUSE || (raw-\u003edata.mouse.lLastX == 0 \u0026\u0026 raw-\u003edata.mouse.lLastY == 0) )\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tpoint.x = raw-\u003edata.mouse.lLastX;\n\t\t\t\t\tpoint.y = raw-\u003edata.mouse.lLastY;\n\t\t\t\t\tprintf(\"raw input: %i %i\\n\", point.x, point.y);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase WM_KEYDOWN:\n\t\t\t\t\tif (holdMouse == FALSE)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\t\t\tconst RAWINPUTDEVICE id = { 0x01, 0x02, RIDEV_REMOVE, NULL };\n\t\t\t\t\tRegisterRawInputDevices(\u0026id, 1, sizeof(id));\n\t\t\t\t\tClipCursor(NULL);\n\t\t\t\t\t\n\t\t\t\t\tprintf(\"rawinput disabled\\n\");\n\t\t\t\t\tholdMouse = FALSE;\n\t\t\t\t\tbreak;\n\t\n\t\t\t\tdefault: break;\n\t\t\t}\n\t\t\tTranslateMessage(\u0026msg);\n\t\t\tDispatchMessage(\u0026msg);\n\t\t}\n\n\t\trunning = IsWindow(hwnd);\n\t}\n\t\n\tDestroyWindow(hwnd);\n\treturn 0;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcolleagueriley%2Fraw-mouse-input","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcolleagueriley%2Fraw-mouse-input","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcolleagueriley%2Fraw-mouse-input/lists"}