[bug] win32 shift key events

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
pc0de
Posts: 300
Joined: Wed Dec 05, 2007 4:41 pm

[bug] win32 shift key events

Post by pc0de »

In the trunk irr::KEY_LSHIFT & irr::KEY_RSHIFT are now being sent for WM_KEYDOWN events. But it's still sending irr::KEY_SHIFT for a corresponding WM_KEYUP.

Before offering a patch, I can think of two ways to fix this:

1. Track shift key state between key events in the device class.

2. Add low level keyboard hookproc and post shift key events from there.

And while I'm in there - add in code for differentiating between left/right ctrl & alt keys.

Which would be preferred? Can anyone think of a better method?
pc0de
Posts: 300
Joined: Wed Dec 05, 2007 4:41 pm

Post by pc0de »

After playing with this a bit more, it turns out:

1. Tracking state between events still won't be able to differentiate between left/right shift WM_KEYUP... :oops:

2. It appears SetWindowsHookEx isn't available on WinCE and for non WinCE it would require using a low-level hook (WH_KEYBOARD_LL) to get at the extended keys. Seems messy to me.

I was able to get up/down left/right shift key detection working by using:

In the CIrrDeviceWin32 constructor:

Code: Select all

    // get scan code for virtual right shift keys.
    // RShiftC statically defined (u32) in CIrrDeviceWin32.cpp
    RShiftSC = MapVirtualKey(VK_RSHIFT, MAPVK_VK_TO_VSC);
and in the WndProc:

Code: Select all

if (event.KeyInput.Key==irr::KEY_SHIFT)
{                
    u32 scan_code = (lParam & 0xFF0000) >> 16;
    if (scan_code == RShiftSC)
        event.KeyInput.Key=irr::KEY_RSHIFT;
    else 
        event.KeyInput.Key=irr::KEY_LSHIFT;                   
}
Unfortunately this same logic won't work for the Ctrl & Alt/Menu keys because on the keyboards I tested, both the left/right virtual keys returned the same scan codes. However, this code that tests the extended key bit does appear to work:

Code: Select all

else if(event.KeyInput.Key == irr::KEY_CONTROL)
{
    // extended key?
    if (lParam & 0x1000000)
        event.KeyInput.Key=irr::KEY_RCONTROL;
    else
        event.KeyInput.Key=irr::KEY_LCONTROL;
}
else if(event.KeyInput.Key == irr::KEY_MENU)
{
    if (lParam & 0x1000000)
        event.KeyInput.Key=irr::KEY_RMENU;
    else 
        event.KeyInput.Key=irr::KEY_LMENU;
}

zillion42
Posts: 324
Joined: Wed Aug 29, 2007 12:32 am
Location: Hamburg, Germany

Post by zillion42 »

Normal KEY_SHIFT or KEY_CONTROL doesn't seem to work on either osX nor linux, I changed it to LSHIFT and LCONTROL which worked. Didnt check if they threw shift/control key-ups instead.
svn version
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

@pc0de: Thanks a lot. I spend on that whole morning, but didn't have the idea of checking that extended key bit. I've checked in now to trunk for svn release 1.6.

Though I have still one problem to which I found no solution so far. When both shift-keys are pressed until repeat starts then it seems I don't get the first up-event. It's simply missing.

Some test-code in case anyone wants to try (does a little more stuff for mouse-testing, but I'm too lazy now to remove that stuff):

Code: Select all

#include <irrlicht.h>
#include <iostream>

using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#endif

struct SAppContext
{
	IrrlichtDevice * device;
	irr::gui::IGUIStaticText * info;
	irr::gui::IGUIListBox * keyEvents;
};

void PrintMouseState(const SEvent& event, IrrlichtDevice * device, irr::core::stringw &result)
{
	gui::ICursorControl * cursor = device->getCursorControl();

	core::position2d<f32> relPos = cursor->getRelativePosition();

	result += stringw(L"rel. X: ");
	result += stringw(relPos.X);
	result += stringw(L"\n");
	result += stringw(L"rel. Y: ");
	result += stringw(relPos.Y);
	result += stringw(L"\n");

	result += stringw(L"X: ");
	result += stringw(event.MouseInput.X);
	result += stringw(L"\n");
	result += stringw(L": ");
	result += stringw(event.MouseInput.Y);
	result += stringw(L"\n");


	result += stringw(L"Wheel: ");
	result += stringw(event.MouseInput.Wheel);
	result += stringw(L"\n");
	
	result += stringw(L"Shift: ");
	if ( event.MouseInput.Shift )
		result += stringw(L"true\n");
	else
		result += stringw(L"false\n");

	result += stringw(L"Control: ");
	if ( event.MouseInput.Control )
		result += stringw(L"true\n");
	else
		result += stringw(L"false\n");

	result += stringw(L"ButtonStates: ");
	result += stringw(event.MouseInput.ButtonStates);
	result += stringw(L"\n");

	result += stringw(L"isLeftPressed: ");
	if ( event.MouseInput.isLeftPressed() )
		result += stringw(L"true\n");
	else
		result += stringw(L"false\n");

	result += stringw(L"isRightPressed: ");
	if ( event.MouseInput.isRightPressed() )
		result += stringw(L"true\n");
	else
		result += stringw(L"false\n");

	result += stringw(L"isMiddlePressed: ");
	if ( event.MouseInput.isMiddlePressed() )
		result += stringw(L"true\n");
	else
		result += stringw(L"false\n");

	result += stringw(L"Event: ");
	switch ( event.MouseInput.Event )
	{
		case EMIE_LMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_LMOUSE_PRESSED_DOWN\n"); break;
		case EMIE_RMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_RMOUSE_PRESSED_DOWN\n"); break;
		case EMIE_MMOUSE_PRESSED_DOWN: result += stringw(L"EMIE_MMOUSE_PRESSED_DOWN\n"); break;
		case EMIE_LMOUSE_LEFT_UP: 	result += stringw(L"EMIE_LMOUSE_LEFT_UP\n"); break;
		case EMIE_RMOUSE_LEFT_UP: 	result += stringw(L"EMIE_RMOUSE_LEFT_UP\n"); break;
		case EMIE_MMOUSE_LEFT_UP: 	result += stringw(L"EMIE_MMOUSE_LEFT_UP\n"); break;
		case EMIE_MOUSE_MOVED: 		result += stringw(L"EMIE_MOUSE_MOVED\n"); break;
		case EMIE_MOUSE_WHEEL: 		result += stringw(L"EMIE_MOUSE_WHEEL\n"); break;
	}
	result += stringw(L"\n");
}

class MyEventReceiver : public IEventReceiver
{
public:
	MyEventReceiver(SAppContext & context) : Context(context) { }

	virtual bool OnEvent(const SEvent& event)
	{
		if (event.EventType == EET_MOUSE_INPUT_EVENT)
		{
			irr::core::stringw infoText;
			PrintMouseState(event, Context.device, infoText);
			Context.info->setText(infoText.c_str());
		}
		else if ( event.EventType == EET_KEY_INPUT_EVENT )
		{
			irr::core::stringw wstr( event.KeyInput.PressedDown ? L"DOWN" : L"UP");
			wstr += L" Key: ";
			wstr += irr::core::stringw(event.KeyInput.Key);
			Context.keyEvents->setSelected( Context.keyEvents->addItem( wstr.c_str() ) );
		}

		return false;
	}

private:
	SAppContext & Context;
};

int main()
{
	video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
	IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(800, 600), 16, false);
	if (device == 0)
		return 1; // could not create selected driver.

	device->setResizable(true);

	video::IVideoDriver* driver = device->getVideoDriver();
	IGUIEnvironment* env = device->getGUIEnvironment();
	
	SAppContext context;
	context.device = device;
	
	core::rect< s32 > rectInfo(10,10, 200, 400);
	context.info = env->addStaticText (L"", rectInfo, true, true);
	context.keyEvents = env->addListBox( core::rect<s32>( 210, 10, 410, 400 ) );
	context.keyEvents->setAutoScrollEnabled(true);
	
	MyEventReceiver receiver(context);
	device->setEventReceiver(&receiver);
	

	while(device->run() && driver)
	{
		if (device->isWindowActive())
		{
			static int triggerMousePos = 0;
			if ( !(++triggerMousePos % 100) )
			{
				gui::ICursorControl * cursor = device->getCursorControl();

//				core::position2d<s32> relPos2 = cursor->getPosition();
//				cursor->setPosition(relPos2);

				core::position2d<f32> relPos = cursor->getRelativePosition();
				cursor->setPosition(relPos);
			}

			driver->beginScene(true, true, SColor(0,200,200,200));
	
			env->drawAll();
		
			driver->endScene();
		}
	}

	device->drop();

	return 0;
}

IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
pc0de
Posts: 300
Joined: Wed Dec 05, 2007 4:41 pm

Post by pc0de »

CuteAlien wrote:Though I have still one problem...
After wrestling with that for a couple of hours I wasn't able to find a solution either. SDL & CS also appear to have the same problem. Even Spy++ fails to report the WM_KEYUP when they are both held down and one of the keys is released.

Fwiw I also tried RegisterHotKey(..., VK_LSHIFT) (returned success) but it didn't send any WM_HOTKEY messages.

For accuracy, I guess someone needs to make good on their DirectInput promise...

* edit *
Looks like RawInput/Message Loop is favored over DirectInput? :
pera
Posts: 460
Joined: Wed May 14, 2008 1:05 pm
Location: Novi Sad, Serbia
Contact:

Post by pera »

Im not sure if this bug goes with this, but on 1.6 I have issue with shift key, when I press shift down I get event for KEY_LSHIFT or KEY_RSHIFT, but when I release the key I get release event for KEY_SHIFT key. Is that a bug or what?

WinXP, Athlon 64 2000+, Visual Studio 2008...
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

Yes, sounds like that bug. Irrlicht 1.6.1. will be released soon (I hope still this year) and it's fixed in there.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
pera
Posts: 460
Joined: Wed May 14, 2008 1:05 pm
Location: Novi Sad, Serbia
Contact:

Post by pera »

thanks!
Post Reply