Using RAWINPUT, based off the example, except this one is in a d3d window
#pragma region includes #include <windows.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #include <d3d9.h> // core direct3d #include <d3dx9.h> // aux libs #include <dxerr.h> // detailed error messages #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") // aux libs #ifdef _DEBUG #pragma comment(lib,"d3dx9d.lib") #else #pragma comment(lib,"d3dx9.lib") #endif #pragma comment(lib, "dxerr.lib") // Macros. #define SAFE_RELEASE(ptr) if(ptr) { ptr->Release(); ptr = NULL; } #define CAST_AS_DWORD(x) *((DWORD*)&x) #define PI 3.14159 #pragma endregion #pragma region define the Vertex structure struct Vertex { float x,y,z ; DWORD color ; // Ctor starts you at origin in black // with alpha (opacity) set to 100% Vertex() { x=y=z = 0.0f; color = D3DCOLOR_XRGB( 0,0,0 ) ; } Vertex( float ix, float iy, float iz ) { x=ix;y=iy;z=iz; color = D3DCOLOR_XRGB( 255,255,255 ) ; } // Ctor. Vertex( float ix, float iy, float iz, unsigned char ir, unsigned char ig, unsigned char ib ) { x=ix;y=iy;z=iz; color = D3DCOLOR_XRGB( ir, ig, ib ) ; } // Ctor that lets you pick alpha Vertex( float ix, float iy, float iz, unsigned char ir, unsigned char ig, unsigned char ib, unsigned char ALPHA ) { x=ix;y=iy;z=iz; color = D3DCOLOR_ARGB( ALPHA, ir, ig, ib ) ; } } ; #pragma endregion struct Globals { struct _Win { HINSTANCE hInstance; // window app instance HWND hwnd; // handle for the window HWND hConsole ; // handle for the console window int width, height; } win ; IDirect3D9 * d3d ; IDirect3DDevice9 * gpu ; }; /////////////////////////// // GLOBALS Globals g; /////////////////////////// // FUNCTION PROTOTYPES void printWindowsLastError( char *msg ) ; inline bool CHECK( HRESULT hr, char * msg, bool stop=true ) ; // checks for errors on the HR passed. bool initD3D() ; // function to initialize the BEAST that is Direct3D9 void initRawinput( HWND hwnd ) ; void update() ; // changes geometry of the scene void drawAxes() ; // draws the ever-important axes (for finding your way around your own scene!) void draw() ; // drawing function containing Direct3D drawing calls LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ); int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow ); void printWindowsLastError( char *msg ) { LPSTR errorString = NULL ; int result = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), 0, (LPSTR)&errorString, 0, 0 ); printf( "%s %s\n", msg, errorString ) ; LocalFree( errorString ) ; } inline bool CHECK( HRESULT hr, char * msg, bool stop ) { if( FAILED( hr ) ) { printf( "%s. %s: %s\n", msg, DXGetErrorStringA( hr ), DXGetErrorDescriptionA( hr ) ) ; // Pause so we can see the error and deal with it. if( stop ) system("pause") ; return false ; } else return true ; } /// Initializes Direct3D9. Returns true on success. bool initD3D() { // start by nulling out both pointers: g.d3d = 0 ; g.gpu = 0 ; g.d3d = Direct3DCreate9( D3D_SDK_VERSION ) ; if( g.d3d == NULL ) { // DEVICE CREATION FAILED!!!! OH NO!!! puts( "Oh.. PHOOEY!!!!! Device creation FAILED!!! WHAT NOW???\n" ) ; return false ; } puts( "Direct3D9 creation success!" ) ; D3DPRESENT_PARAMETERS pps = { 0 } ; pps.Windowed = true ; pps.BackBufferCount = 1 ; pps.SwapEffect = D3DSWAPEFFECT_DISCARD ; pps.BackBufferFormat = D3DFMT_UNKNOWN ; pps.EnableAutoDepthStencil = true ; pps.AutoDepthStencilFormat = D3DFMT_D16 ; HRESULT hr = g.d3d->CreateDevice( D3DADAPTER_DEFAULT, // primary display adapter D3DDEVTYPE_HAL, // use HARDWARE rendering (fast!) g.win.hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &pps, &g.gpu ) ; if( !CHECK( hr, "OH NOS!! I could not initialize Direct3D! Bailing...\n" ) ) { return false ; } puts( "Direct3D9 GPU device creation successful" ) ; #pragma region setup interleaved arrays D3DVERTEXELEMENT9 pos ; pos.Usage = D3DDECLUSAGE_POSITION ; pos.UsageIndex = 0 ; pos.Stream = 0 ; pos.Type = D3DDECLTYPE_FLOAT3 ; pos.Offset = 0 ; pos.Method = D3DDECLMETHOD_DEFAULT ; D3DVERTEXELEMENT9 col; col.Usage = D3DDECLUSAGE_COLOR ; col.UsageIndex = 0 ; col.Stream = 0 ; col.Type = D3DDECLTYPE_D3DCOLOR ; col.Offset = 3*sizeof( float ) ; col.Method = D3DDECLMETHOD_DEFAULT ; D3DVERTEXELEMENT9 vertexElements[] = { pos, col, D3DDECL_END() } ; IDirect3DVertexDeclaration9 * Vdecl ; hr = g.gpu->CreateVertexDeclaration( vertexElements, &Vdecl ) ; CHECK( hr, "CreateVertexDeclaration FAILED!" ) ; hr = g.gpu->SetVertexDeclaration( Vdecl ) ; CHECK( hr, "SetVertexDeclaration FAILED!" ) ; #pragma endregion hr = g.gpu->SetRenderState( D3DRS_COLORVERTEX, TRUE ) ; CHECK( hr, "SetRenderState( COLORVERTEX ) FAILED!" ) ; hr = g.gpu->SetRenderState( D3DRS_LIGHTING, FALSE ) ; CHECK( hr, "Lighting off" ) ; hr = g.gpu->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ) ; CHECK( hr, "cull mode off" ) ; initRawinput( g.win.hwnd ) ; return true ; } void initRawinput( HWND hwnd ) { puts( "Starting up rawinput devices..." ) ; // After the window has been created, // register raw input devices RAWINPUTDEVICE Rid[2] ; Rid[0].usUsagePage = 0x01 ; // magic numbers Rid[0].usUsage = 0x02 ; // magically means mouse Rid[0].dwFlags = 0 ; // (use this if you DO NOT WANT to capture mouse) //Rid[0].dwFlags = RIDEV_CAPTUREMOUSE | RIDEV_NOLEGACY ; // (use this to CAPTURE MOUSE) Rid[0].hwndTarget = hwnd ; Rid[1].usUsagePage = 0x01 ; // magic numbers Rid[1].usUsage = 0x06 ; // magically means keyboard Rid[1].dwFlags = 0 ; // use RIDEV_NOHOTKEYS for no winkey Rid[1].hwndTarget = hwnd ; if( !RegisterRawInputDevices( Rid, 2, sizeof(Rid[0]) ) ) { //registration failed. Check your Rid structs above. printWindowsLastError( "RegisterRawInputDevices" ) ; puts( "Could not register raw input devices. Check your Rid structs, please." ) ; exit(1); } } void update() { } //////////////////////// // DRAWING FUNCTIONS void drawAxes() { static float axisLen = 2.0f ; static Vertex axis[] = { // x-axis is red Vertex( -axisLen, 0, 0, 255, 0, 0 ), Vertex( +axisLen, 0, 0, 255, 0, 0 ), // y-axis green Vertex( 0, -axisLen, 0, 0, 255, 0 ), Vertex( 0, +axisLen, 0, 0, 255, 0 ), // z-axis blue Vertex( 0, 0, -axisLen, 0, 0, 255 ), Vertex( 0, 0, +axisLen, 0, 0, 255 ) } ; HRESULT hr = g.gpu->DrawPrimitiveUP( D3DPT_LINELIST, 3, axis, sizeof( Vertex ) ) ; CHECK( hr, "DrawPrimitiveUP FAILED!" ) ; static float pointSize = 8.0f ; g.gpu->SetRenderState( D3DRS_POINTSIZE, CAST_AS_DWORD( pointSize ) ) ; // Draw points at end of axis. static Vertex points[] = { Vertex( axisLen, 0, 0, 255, 0, 0 ), Vertex( 0, axisLen, 0, 0, 255, 0 ), Vertex( 0, 0, axisLen, 0, 0, 255 ), } ; hr = g.gpu->DrawPrimitiveUP( D3DPT_POINTLIST, 3, points, sizeof( Vertex ) ) ; CHECK( hr, "DrawPrimitiveUP FAILED!" ) ; } void draw() { HRESULT hr ; hr = g.gpu->Clear( 0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 255, 25, 25, 25 ), 1.0f, 0 ) ; CHECK( hr, "Clear FAILED!" ) ; #pragma region set up the camera D3DXMATRIX projx ; D3DXMatrixOrthoRH( &projx, 5, 5, 1, 100 ) ; //D3DXMatrixPerspectiveFovRH( &projx, PI/4, (float)g.win.width/g.win.height, 1.0f, 1000.0f ) ; g.gpu->SetTransform( D3DTS_PROJECTION, &projx ) ; D3DXMATRIX viewx ; int x = 2 ; int y = 2 ; D3DXVECTOR3 eye( x, y, 4 ) ; D3DXVECTOR3 look( x, y, 0 ) ; D3DXVECTOR3 up( 0, 1, 0 ) ; D3DXMatrixLookAtRH( &viewx, &eye, &look, &up ) ; g.gpu->SetTransform( D3DTS_VIEW, &viewx ) ; #pragma endregion hr = g.gpu->BeginScene() ; CHECK( hr, "BeginScene FAILED!" ) ; drawAxes(); hr = g.gpu->EndScene() ; CHECK( hr, "EndScene FAILED!" ) ; // And finally, PRESENT what we drew to the backbuffer g.gpu->Present( 0, 0, 0, 0 ) ; } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow ) { ////////////////// // First we'll start by saving a copy of // the hInstance parameter inside our // "glob" of globals "g": g.win.hInstance = hInstance; // In case we need it later, we'll have it // with firsthand easy access. #pragma region part 0 - attach a console // Attach a console AllocConsole(); AttachConsole( GetCurrentProcessId() ) ; freopen( "CON", "w", stdout ) ; // redirect stdout to console // Move the console over to the top left g.win.hConsole = GetConsoleWindow(); MoveWindow( g.win.hConsole, 0, 0, 400, 400, true ) ; printf( "* * Computer Program Begin * *\n" ) ; #pragma endregion #pragma region part 1 - create a window // The next few lines you should already // be used to: create a WNDCLASSEX // that describes the properties of // the window we're going to soon create. // A. Create the WNDCLASSEX WNDCLASSEX wcx = { 0 } ; wcx.cbSize = sizeof( WNDCLASSEX ); wcx.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH ); wcx.hCursor = LoadCursor( NULL, IDC_ARROW ); wcx.hIcon = LoadIcon( NULL, IDI_APPLICATION ); wcx.hInstance = hInstance; wcx.lpfnWndProc = WndProc; wcx.lpszClassName = TEXT("Philip"); wcx.lpszMenuName = 0; wcx.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Register that class with the Windows O/S.. RegisterClassEx( &wcx ); int width = 800, height = 600; int leftEdge = 400, topEdge = 25 ; RECT rect; SetRect( &rect, leftEdge, // left topEdge, // top leftEdge + width, // right topEdge + height ); // bottom // Save width and height off. g.win.width = rect.right - rect.left; g.win.height = rect.bottom - rect.top; // Adjust it. DWORD windowStyle = WS_OVERLAPPEDWINDOW ; // typical features of a normal window DWORD windowExStyle = 0 ; // I want the window to be topmost AdjustWindowRectEx( &rect, windowStyle, false, windowExStyle ); g.win.hwnd = CreateWindowEx( windowExStyle, TEXT("Philip"), TEXT("DIRECT3D WINDOW"), windowStyle, rect.left, rect.top, // adjusted x, y positions rect.right - rect.left, rect.bottom - rect.top, // adjusted width and height NULL, NULL, hInstance, NULL); // check to see that the window // was created successfully! if( g.win.hwnd == NULL ) { FatalAppExit( NULL, TEXT("CreateWindow() failed!") ); } // and show. ShowWindow( g.win.hwnd, iCmdShow ); // JUMP to the initD3D() method. if( !initD3D() ) { FatalAppExit( 0, TEXT("SORRY!!! DEVICE CREATION FAILED!!! YOU LOSE, WITHOUT EVEN PLAYING THE GAME!!!" ) ) ; } #pragma endregion #pragma region message loop MSG msg; while( 1 ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { if( msg.message == WM_QUIT ) { break; } TranslateMessage( &msg ); DispatchMessage( &msg ); } else { update(); draw(); } } #pragma endregion ////////////// // clean up SAFE_RELEASE( g.gpu ) ; SAFE_RELEASE( g.d3d ) ; // and a cheesy fade exit AnimateWindow( g.win.hwnd, 200, AW_HIDE | AW_BLEND ); printf( "* * This Computer Program Has Ended * *\n" ) ; return msg.wParam; } //////////////////////// // WNDPROC // Notice that WndProc is very very neglected. // We hardly do anything with it! That's because // we do all of our processing in the draw() // function. LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam ) { switch( message ) { case WM_CREATE: Beep( 50, 10 ); return 0; break; case WM_PAINT: { HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint( hwnd, &ps ); // don't draw here. would be waaay too slow. // draw in the draw() function instead. EndPaint( hwnd, &ps ); } return 0; break; case WM_KEYDOWN: switch( wparam ) { case VK_ESCAPE: PostQuitMessage( 0 ); break; default: break; } return 0; case WM_INPUT: { UINT dwSize; GetRawInputData((HRAWINPUT)lparam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); LPBYTE lpb = new BYTE[dwSize]; if (lpb == NULL) { return 0; } int readSize = GetRawInputData( (HRAWINPUT)lparam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER) ) ; if( readSize != dwSize ) puts( "ERROR: GetRawInputData didn't return correct size!" ) ; RAWINPUT* raw = (RAWINPUT*)lpb; if (raw->header.dwType == RIM_TYPEKEYBOARD) { if( raw->data.keyboard.VKey == VK_SPACE ) { puts( "You are pressing space" ) ; } } else if (raw->header.dwType == RIM_TYPEMOUSE) { int dx = raw->data.mouse.lLastX ; int dy = raw->data.mouse.lLastY ; printf( "%d %d\n", dx, dy ) ; } delete[] lpb; return 0; } case WM_SIZE: { int width = LOWORD( lparam ) ; int height = HIWORD( lparam ) ; printf( "RESIZED TO width=%d height=%d\n", width, height ) ; } break; case WM_DESTROY: PostQuitMessage( 0 ) ; return 0; break; } return DefWindowProc( hwnd, message, wparam, lparam ); }
4 Comments
By any chance can elaborate about the mouse coordinates?
more specifically, how to get a screen space coordinates of the mouse,
at any time (simple function), using raw input.
What you have is the difference, and I can’t get the screen space coordinates from it.
A mouse doesn’t supply absolute coordinates, only relative. A mouse has no memory!
A pen input device or touch screen supplies absolute coordinates.
The type of input you got (relative or absolute) is in raw->data.mouse.usFlags.
Check
if( raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE )
Then the user was using a pen device.
Device dependent.
To keep screen space coordinates, you can:
– Maintain a global mouse_x,mouse_y with current mouse position (just keep adding dx and dy each time there is raw input, and draw your mouse icon at mouse_x, mouse_y)
– Use an alternative API function, like WM_MOUSEMOVE (http://msdn.microsoft.com/en-us/library/ms645616(VS.85).aspx) (slower!)
I tried using the global variables in order to keep track of it, but I seem to be doing wrong.
My bet is on the initial values. I tried starting with values of 0, even though it didn’t make sense. That didn’t work, of course.
After, I tried getting the initial mouse position from GetCursorPos(), then adding to it. It seems i’m still doing it wrong though. If I had to guess, I would say my problem is _when_ to call GetCursorPos(). Currently, i’m calling it after calling Register, which logically should be right. I can’t be sure about it.
I would love if you can create or link me to a working sample which shows the absolute screen position using raw input.
__You determine__ absolute screen coordinates. The API supplies you with dx and dy to mouse pos. Now you say where the mouse __is__, and draw it there.