ZenMouse & DISCL_EXCLUSIVE

Started by
6 comments, last by sdoherty55 22 years, 3 months ago
Before I spend all night trying to figure out how the ZenMouse is able to display the cursor using DISCL_EXCLUSIVE mode. To the best of my knowledge it is not possible to replace the system cursor with if you are using DISCL_EXCLUSIVE mode. Therefore, I have to assume that he is not using DISCL_EXCLUSIVE mode or that he is drawing the cursor as a bitmap. At first glance this does not seem to be the case? Anyway, since I am going to invest the time to find out what he is doing, I thought I would ask first. Thanks
    
// ------------------------- class CZenMouse

LPDIRECTINPUT8 g_pDI = 0;

class CZenMouse
{
public:
	CZenMouse();
	~CZenMouse();

// Variables

public:
	
protected:
	LPDIRECTINPUTDEVICE8 m_pMouseDev;
	LPDIRECT3DSURFACE8 m_pCursorSurf;
	
	BOOL m_bInitialized;
	BOOL m_bShowCursor;

	DIMOUSESTATE m_MouseData;

	// The cursor position

	POINT m_Position;
// Functions

public:
	HRESULT Initialize();
	HRESULT Poll();

	POINT GetMousePos();
	BOOL IsButtonDown( int Button );

	// Handles the WM_SETCURSOR message

	BOOL HandleSetCursor();
	// Toggles cursor display

	void ShowCursor( BOOL bShow ){ m_bShowCursor = bShow; }
	// Sets the position of the cursor

	void SetCursorPosition( int x, int y );
	// Gets the position of the cursor

	void GetCursorPosition( int& x, int& y );
	// Moves the position of the cursor.

	void MoveCursor( int x, int y );
	// Update the cursor position 

	// based on mouse movement

	void UpdateCursorPos();
protected:

};

CZenMouse::CZenMouse()
{
	m_pMouseDev = 0;

	m_bInitialized = FALSE;

	m_bShowCursor = FALSE;

	m_pCursorSurf = 0;

	m_Position.x = m_Position.y = 0;
}

CZenMouse::~CZenMouse()
{
	if( m_pCursorSurf )
		m_pCursorSurf->Release();
	
	// Unacquire and release the mouse device

	if( m_pMouseDev )
	{
		m_pMouseDev->Unacquire();
		m_pMouseDev->Release();
	}
}

// Set the position of the cursor, in screen coords

void CZenMouse::SetCursorPosition( int x, int y )
{
	
	// Make sure the point stays within the screen

	if( x < 0 )
		x = 0;

	if( y < 0 )
		y = 0;

	if( x > g_DeviceWidth-1 )
		x = g_DeviceWidth-1;

	if( y > g_DeviceHeight-1 )
		y = g_DeviceHeight-1;

	// Update the postion tracker

	m_Position.x = x;
	m_Position.y = y;

	// Tell Direct3D about the new position

	g_pDevice->SetCursorPosition( x, y, 0 );
}

// Returns the current position of the cursor

void CZenMouse::GetCursorPosition( int& x, int& y )
{
	x = m_Position.x;
	y = m_Position.y;
}

// Moves the cursor relative to its current position

void CZenMouse::MoveCursor( int x, int y )
{
	m_Position.x += x;
	m_Position.y += y;

	g_pDevice->SetCursorPosition( x, y, 0 );
}

// Sets the mouse cursor position

// by tracking how far it has moved

// since the last update.

void CZenMouse::UpdateCursorPos()
{
	// Get the relative movement

	// out of the DIMOUSESTATE structure

	m_Position.x += m_MouseData.lX;
	m_Position.y += m_MouseData.lY;

	// Make sure the point is within screen bounds

	if( m_Position.x < 0 )
		m_Position.x = 0;

	if( m_Position.y < 0 )
		m_Position.y = 0;

	if( m_Position.x > g_DeviceWidth-1 )
		m_Position.x = g_DeviceWidth-1;

	if( m_Position.y > g_DeviceHeight-1 )
		m_Position.y = g_DeviceHeight-1;

	// Set the new position into the device

	g_pDevice->SetCursorPosition( m_Position.x, m_Position.y, 0 );	
}

// Handles the WM_SETCURSOR message

BOOL CZenMouse::HandleSetCursor()
{
	// Return if the mouse hasnt been intialized yet

	if( !m_bInitialized )
		return FALSE;
	
	// If the cursor is set to be visible...

	if( m_bShowCursor )
	{
		// Turn off standard cursor 

		SetCursor( NULL );
		// Show the zen cursor

		g_pDevice->ShowCursor( TRUE );

		// Return TRUE, which prevents

		// windows from messing with the

		// cursors anymore

		return TRUE;
	}
			
	// Return FALSE to let windows do

	// its thing if our cursor is not visible

	return FALSE;
}

POINT CZenMouse::GetMousePos()
{
	// Holds mouse data

	POINT MousePos;

	// Get the data from the buffer

	MousePos.x = m_MouseData.lX;
	MousePos.y = m_MouseData.lY;
	
	// Return the position

	return MousePos;
}

BOOL CZenMouse::IsButtonDown( int Button )
{
	// Return the button status from the buffer	

	if( m_MouseData.rgbButtons[Button] & 0x80 )
		return TRUE;
	else
		return FALSE;
}

HRESULT CZenMouse::Poll()
{
	HRESULT r = 0;

	// Return if the object has not been initialized

	if( !m_bInitialized )
		return E_FAIL;

	// Get the state of the mouse

	r = m_pMouseDev->GetDeviceState( sizeof( DIMOUSESTATE ), &m_MouseData );
	if( FAILED( r ) )
	{
		// If the mouse has moved focus

		if( r == DIERR_INPUTLOST )
		{
			// Reacquire the mouse

			while( r == DIERR_INPUTLOST )
				r = m_pMouseDev->Acquire();

			// Try to test the state again

			if( SUCCEEDED( r ) )
				m_pMouseDev->GetDeviceState( sizeof( DIMOUSESTATE ), &m_MouseData );
			else
				return FALSE;
		}
		else
			return E_FAIL;
	}

	return S_OK;
}

// Initializes the mouse

HRESULT CZenMouse::Initialize()
{
	HRESULT r = 0;

	// Return if the DirectInput object does not exist

	if( !g_pDI )
		return E_FAIL;

	// Release the mouse device if it has already been created

	if( m_pMouseDev )
		m_pMouseDev->Release();

	// Create the mouse device

	r = g_pDI->CreateDevice( GUID_SysMouse, &m_pMouseDev, NULL );
	if( FAILED( r ) )
	{
		SetError( "Unable to create mouse device" );
		return E_FAIL;
	}

	// Set the data format for the mouse

	r = m_pMouseDev->SetDataFormat( &c_dfDIMouse );
	if( FAILED( r ) )
	{
		SetError( "Unable to set the mouse data format" );
		return E_FAIL;
	}

	// Set the cooperative level for the mouse

	r = m_pMouseDev->SetCooperativeLevel( g_hWndMain, DISCL_EXCLUSIVE | DISCL_FOREGROUND );
	if( FAILED( r ) )
	{
		SetError( "Unable to set the cooperative level for the mouse" );
		return E_FAIL;
	}

	// Acquire the physical mouse into the device

	r = m_pMouseDev->Acquire();
	if( FAILED( r ) )
	{
		SetError( "Unable to acquire mouse" );
		return E_FAIL;
	}

	// Create a new surface for the mouse pointer image

	g_pDevice->CreateImageSurface( 32, 64, D3DFMT_A8R8G8B8, &m_pCursorSurf );
	// Load the image file from disk

	D3DXLoadSurfaceFromFile( m_pCursorSurf, 0, 0, "TestCursor.dds", 0, D3DX_FILTER_NONE, 0, 0 );
	// Set the hotspot for the cursor

	g_pDevice->SetCursorProperties( 0, 0, m_pCursorSurf );
	


	// Set the initialization flag to true

	m_bInitialized = TRUE;

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	

	// Turn off standard cursor 

	SetCursor( NULL );
	// Show the zen cursor

	g_pDevice->ShowCursor( TRUE );
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


	return S_OK;
}
  
Edited by - sdoherty55 on December 26, 2001 8:05:38 PM Edited by - sdoherty55 on December 26, 2001 8:09:29 PM
Advertisement
Not to sound too harsh dude, but RTFM...

In the docs, you can manipulate the cursor through the IDirect3DDevice8 interface which is what this code is doing here..(via the SetCursorPosition, SetCursorProperties, ShowCursor function calls)

ALSO

This code IS using a custom mouse cursor as COMMENTED (very clearly) in the construction area..

I haven''t (as yet) used the cursor this way, but I imagine that you''d need to set the mouse to DISCL_EXCLUSIVE in order to use your own cursor in your app properly..




Learn about game programming!Games Programming in C++: Start to Finish
For the record I am not just asking this question lighly, if you look at Microsoft Direct Input Mouse Sample it says in the docs:

"Therefore when an application has exclusive access to the mouse. Window is not allowed any access at all. No mouse messages are generated. A further side effect is that the mouse cursor disappears. Menu accessing the menu the application releases the mouse the mouse is displayed again."


I have also spend a good portion of today looking at the docs and the following code:



          /************************************************************************///Method:	InitDI//Purpose:	Initialize Direct Input/************************************************************************/HRESULT CDirectInput8::InitDI(HWND hWnd, HINSTANCE hInstance, DWORD ToUse){		// Create The DI Objectif(FAILED(DirectInput8Create(hInstance, DIRECTINPUT_VERSION,         IID_IDirectInput8, (void**)&m_pDI, NULL))) 	return E_FAIL;	/************************************************************************///Set up keyboard inputif(ToUse & USEKEYBOARD){	if(FAILED(m_pDI->CreateDevice(GUID_SysKeyboard, &m_pDIKeybrd, NULL)))	return E_FAIL;	if(FAILED(m_pDIKeybrd->SetDataFormat(&c_dfDIKeyboard)))	return E_FAIL;	if(FAILED(m_pDIKeybrd->SetCooperativeLevel(hWnd, 		   DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)))	return E_FAIL;	if (m_pDIKeybrd) m_pDIKeybrd->Acquire(); 	}/************************************************************************//************************************************************************///Set up mouse inputif(ToUse & USEMOUSE){if(FAILED(m_pDI->CreateDevice(GUID_SysMouse, &m_pDIMouse, NULL)))return E_FAIL;if(FAILED(m_pDIMouse->SetDataFormat(&c_dfDIMouse)))return E_FAIL;if(FAILED(m_pDIMouse->SetCooperativeLevel(hWnd, 	   DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)))return E_FAIL;m_hMouse = CreateEvent(0,0,0,0);if (m_hMouse == NULL){DIShutdown();return 0;}hr = m_pDIMouse->SetEventNotification(m_hMouse);if (FAILED(hr)){DIShutdown();return 0;}//initialize input bufferDIPROPDWORD dipdw; 	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);dipdw.diph.dwObj        = 0;dipdw.diph.dwHow        = DIPH_DEVICE;dipdw.dwData            = 16;hr = m_pDIMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph);if (FAILED(hr)){DIShutdown();return 0;}if (m_pDIMouse) m_pDIMouse->Acquire();}  



-------------------

From my research it seems that if you comment out the last line "if (m_pDIMouse) m_pDIMouse->Acquire();" you are able to use the mouse in exclusive mode and the custom curor will be displayed. However, if you leave the line in you must, set the the mouse to the following:

  if(FAILED(m_pDIMouse->SetCooperativeLevel(hWnd, 	   DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)))return E_FAIL;      


As far as I can see they are both using custom cursor and I am even calling the setcursor, show cursor as part of render? As you can see I have followed your advice and RTFM... Clearly it is possible and I am missing something. Thanks for you input.


Edited by - sdoherty55 on December 26, 2001 8:07:59 PM

Edited by - sdoherty55 on December 26, 2001 8:10:18 PM

Edited by - sdoherty55 on December 26, 2001 8:11:35 PM
LOL...sorry, sometimes I end up sounding belligerent..

AFAIK, when you declare your dinput mouse device with the EXCLUSIVE and FOREGROUND flags, you're creating an environment where the regular win32 mouse messages aren't sent to your message handler...(you basically have to do the polling and setting the cursor position on your own)..at least that's what the docs say to me..

I think in your original posted source code (ZenMouse), BECAUSE he declared the mouse as FOREGROUND | EXCLUSIVE he was FORCED to use his own cursor...

Here's a snippet that might help you..

    Because DirectInput works directly with the mouse driver, it bypasses the subsystem of Windows that interprets mousedata for windowed applications. Applications that rely on theWindows cursor for navigation should continue to use the standard Windows mouse messages and Microsoft® Win32® functions.When using the system mouse in exclusive mode, DirectInputsuppresses mouse messages, and therefore Windows is unable toshow the standard cursor.     


Sorry for the earlier sounding post...just having a frustrating day with my application debugging..argh.





Edited by - wazoo69 on December 26, 2001 5:47:59 PM
Learn about game programming!Games Programming in C++: Start to Finish
Thanks, I agree with your comments about him having to use his own cursor. However, I am having trouble figuring out what lines he is calling to make this happen? Is it possible that it only works in full screen mode? I will keep trying, don't understand why DirectInput is so complex.


PS: How do you get your source in a white window.

Edited by - sdoherty55 on December 26, 2001 6:29:23 PM


Edited by - sdoherty55 on December 26, 2001 6:29:07 PM
just enclose your source code with the word "source" in square brackets...(like html..you surround it with {source} {/source}..only replace the squiggly brackets with square ones)

He's creating his custom cursor by the:

    // Create a new surface for the mouse pointer imageg_pDevice->CreateImageSurface( 32, 64, D3DFMT_A8R8G8B8, &m_pCursorSurf );// Load the image file from diskD3DXLoadSurfaceFromFile( m_pCursorSurf, 0, 0, "TestCursor.dds",0, D3DX_FILTER_NONE, 0, 0 );// Set the hotspot for the cursorg_pDevice->SetCursorProperties( 0, 0, m_pCursorSurf );    


All he's doing above is using the IDirect3DDevice8 methods for creating and attaching an IDirect3DSurface8 surface to the device making it the mouse cursor surface..

Since I haven't found anything saying the contrary in the SDK docs, I think you can create your own mouse cursor in EXCLUSIVE or NONEXCLUSIVE modes...

Try not to lose sleep over it though, as DirectInput isn't THAT hard once you get used to it. A LOT of this stuff is very "do-once-then-forget-about-it"...don't worry, you'll pick it up soon...it took me a week or so of fooling around with the samples to figure out what's going on..





Edited by - wazoo69 on December 26, 2001 6:41:11 PM
Learn about game programming!Games Programming in C++: Start to Finish
Ok, I am pretty sure that I have this figured out. It is impossible to have the system display a custom cursor to the screen with the mouse set to exclusive mode unless you are executing a full screen application. I can not get a custom mouse to display, using only Direct Input, when the application is using windowed mode.

However, Direct Input is fully functional in full screen and windows exclusive modes, it just requires a blt of a transparent bitmap to the screen to display the mouse.

Please let me know if someone has found a example.

  // Does Not Work.   


Thanks

Edited by - sdoherty55 on December 26, 2001 8:01:42 PM

This topic is closed to new replies.

Advertisement