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.