[fixed]Key repeats

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
FreakNigh
Posts: 122
Joined: Thu Oct 19, 2006 7:31 am
Location: Orlando FL, USA
Contact:

[fixed]Key repeats

Post by FreakNigh »

Well i have this code that is suposed to execute only ONCE when a button is held down, but on linux (i guess?) it likes to switch between pressed and not pressed so i haven't a clue right now how i'm suposed to know if someone is pressing a button constantly quickly or if they have it held down.

here be the code...

Code: Select all

bool MyEventReceiver:: OnEvent(SEvent event)
{
	static char w=0,s=0,a=0,d=0, exhaust=0;
	
	//If the key 'W' or 'S' was left up, we get the position of the scene node, and modify the Y coordinate a little bit. So if you press 'W', the node moves up, and if you press 'S' it moves down.
	
	//printf("what\n");
	//return false;
	
	if (event.EventType == EET_KEY_INPUT_EVENT)
	{
		if(!display_menu)
		{
			if(event.KeyInput.PressedDown)
				switch(event.KeyInput.Key)
			{
				default:
					//printf("key:%d\n",event.KeyInput.Key);
					break;
				case KEY_UP:
					w=1;
					player_ship->set_accelerate(ACCEL_SPEED);
					if(!exhaust) 
					{
						player_ship->send_exhaust(1);
						exhaust = 1;
					}
					return true;
					break;
				case KEY_DOWN:
					s=1;
					player_ship->set_accelerate(-ACCEL_SPEED);
					if(!exhaust) 
					{
						player_ship->send_exhaust(-1);
						exhaust = 1;
					}
					return true;
					break;
				case KEY_LEFT:
					a=1;
					player_ship->set_turn_angle(-TURN_ANGLE_SPEED);
					return true;
					break;
				case KEY_RIGHT:
					d=1;
					player_ship->set_turn_angle(TURN_ANGLE_SPEED);
					return true;
					break;
				case KEY_KEY_A:
					player_ship->fire_missile();
					return true;
					break;
				case 27:
					Irr_root->closeDevice();
					return true;
					break;
					
					
			}
			else
				switch(event.KeyInput.Key)
			{
				case KEY_UP:
					w=0;
					if(s)
					{
						player_ship->set_accelerate(-ACCEL_SPEED);
						if(!exhaust) 
						{
							player_ship->send_exhaust(-1);
							exhaust = 1;
						}
					}
					else
					{
						player_ship->set_accelerate(0);
						if(exhaust) 
						{
							player_ship->send_exhaust(0);
							exhaust = 0;
						}
					}
					return true;
					break;
				case KEY_DOWN:
					s=0;
					if(w)
					{
						player_ship->set_accelerate(ACCEL_SPEED);
						if(!exhaust) 
						{
							player_ship->send_exhaust(1);
							exhaust = 1;
						}
					}
					else
					{
						player_ship->set_accelerate(0);
						if(exhaust) 
						{
							player_ship->send_exhaust(0);
							exhaust = 0;
						}
					}
					return true;
					break;
				case KEY_LEFT:
					a=0;
					if(d)
						player_ship->set_turn_angle(TURN_ANGLE_SPEED);
					else
						player_ship->set_turn_angle(0);
					return true;
					break;
				case KEY_RIGHT:
					d=0;
					if(a)
						player_ship->set_turn_angle(-TURN_ANGLE_SPEED);
					else
						player_ship->set_turn_angle(0);
					return true;
					break;
			}
		}
		else
		{
			if(event.KeyInput.PressedDown)
				if(event.KeyInput.Key == 27)
					display_menu = 0; //Irr_root->closeDevice();
				else
					Nigh_menu->enter_key(event.KeyInput.Key);
				
				return true;
		}
	}
	return false;
}
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I'd think the key input alternates between pressed and not pressed when you hold the key due to the keyboard auto-repeat. If you open up an editor and hold down the W key, you get one W, a small delay, then a continuous stream of Ws. The continuous stream of Ws happens because the driver is simulating key presses by reporting the key is pressed then released repeatedly. This is reasonable behavior.

One thing you might try is to set all of the flags in one area of code, and then do something with those settings somewhere else...

Code: Select all

class MyEventReceiver : public IEventReceiver
{
private:
   bool Keys[256];
};

bool MyEventReceiver::OnEvent(SEvent event)
{
   if (event.EventType == EET_KEY_INPUT_EVENT)
   {
      Keys[event.KeyInput.Key] = event.KeyInput.Pressed;
      return true;
   }

   return false;
}

void MyEventReceiver::update()
{
   f32 accel = 0.f;
   if (Keys[KEY_UP])
      accel += ACCEL_SPEED;
   if (Keys[KEY_DOWN])
      accel -= ACCEL_SPEED;

   player_ship->set_accelerate(accel);

   f32 turn = 0.f;
   if (Keys[KEY_LEFT])
      turn += TURN_ANGLE_SPEED;
   if (Keys[KEY_RIGHT])
      turn -= TURN_ANGLE_SPEED;

   player_ship->set_turn_angle(turn);

   if (Keys[KEY_KEY_A])
      player_ship->fire_missle();

   if (Keys[KEY_ESCAPE])
      Irr_root->closeDevice();
  
}
FreakNigh
Posts: 122
Joined: Thu Oct 19, 2006 7:31 am
Location: Orlando FL, USA
Contact:

Post by FreakNigh »

yes its not so bad that it continuely presses it, whats bad is that irrlicht registers it has being released too, which is not happening. it gives a w presseddown == 1 followed by a w presseddown == 0 (repeatedly), even though the button was constantly held down. And because of this i have no way of knowing if its actauly being held down or if they actauly just pressed the button normaly.

The ultimate goal is to have a function called when it is pressed down, followed by another function being called after it is let up (these functions in my case being player_ship->send_exhaust(0); and player_ship->send_exhaust(1);)
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

It is not a bug that irrlicht sends a key up message. The OS is reporting a key up, and irrlicht reports that.

You really need to have a look at what I've done above. If you need to know the previous state and the new state, then you should keep two copies of key state and swap them.
FreakNigh
Posts: 122
Joined: Thu Oct 19, 2006 7:31 am
Location: Orlando FL, USA
Contact:

Post by FreakNigh »

-How do i have it so a function is called only once per button preson on linux-

this guy was also having the same problem... but his solution would require you to distribute your own irrlicht atm.
http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=16179
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

I'm not running linux, so I can't test this, but it should work.

I guess the real issue is that there is a difference in behavior between windows and linux, and that should probably be fixed. Problems like that cause big headaches after a project is finished and you are trying to port to a platform that should just work right out of the box.

Code: Select all

class MyEventReceiver : public IEventReceiver
{
public:
	MyEventReceiver()
	{
		memset(NewKeys, 0, sizeof(NewKeys));
		memset(OldKeys, 0, sizeof(OldKeys));
	}

	virtual bool OnEvent(const SEvent& event);

	void update();
private:
   bool NewKeys[256]; 
	bool OldKeys[256];
}; 


bool MyEventReceiver::OnEvent(const SEvent& event) 
{ 
   if (event.EventType == EET_KEY_INPUT_EVENT) 
   { 
      NewKeys[event.KeyInput.Key] = event.KeyInput.PressedDown;
      return true; 
   } 

   return false; 
} 

void MyEventReceiver::update() 
{
	// these flags will be set only when the key state goes from not pressed to pressed
	bool upKeyPressed = NewKeys[KEY_UP   ] && !OldKeys[KEY_UP   ];
	bool dnKeyPressed = NewKeys[KEY_DOWN ] && !OldKeys[KEY_DOWN ];
	bool lfKeyPressed = NewKeys[KEY_LEFT ] && !OldKeys[KEY_LEFT ];
	bool rtKeyPressed = NewKeys[KEY_RIGHT] && !OldKeys[KEY_RIGHT];

	memcpy(OldKeys, NewKeys, sizeof(OldKeys));
}
FreakNigh
Posts: 122
Joined: Thu Oct 19, 2006 7:31 am
Location: Orlando FL, USA
Contact:

Post by FreakNigh »

Thanks alot for the help, but i guess i'll have to move over to SDL for input control whenever i get to the point where this problem holds alittle more weight then the list of other things i need to get done. Then switch back over when the problem is fixed. If anyone knows the solution to this problem with the current release of irrlicht please tell me =) Otherwise i will wait until the next release...
kornerr
Posts: 245
Joined: Thu Jul 06, 2006 9:57 am
Location: Russia, Siberia, Kemerovo
Contact:

Post by kornerr »

I face the same problem. Irrlicht lacks setKeyAutorepeat (bool state) function.
vitek's suggesion is nothing useful, because when i hold, say, W key, i get key presses / releases constantly.
I was thinking of not counting in those presses / releases that occur within small interval, that's what happens when key autorepeats. But if user indeed pressed / released key within short delay, the key press / release won't get to target...
Any ideas to overcome it?
Thanks.
Open Source all the way, baby ;)
OSRPG
xskinyx
Posts: 25
Joined: Fri Dec 29, 2006 3:28 am

Post by xskinyx »

Code: Select all

	//keyboard input
	if( event.EventType == EET_KEY_INPUT_EVENT )
	{
		//check if the key is being pressed or released
		if( event.KeyInput.PressedDown )
		{
			//set pressed down state
			m_keys[ event.KeyInput.Key ] = true;
		}
		else
		{
			//set released state
			m_keys[ event.KeyInput.Key ] = false;
		}

		//event handled
		return true;
	}
an excerpt of my input manager code. i hope this is helpful. perhaps the issue here is that you are acting on key events to run game code... you should really be just modifying a state and then querying that state elsewhere for updating your game (so intermediate changes wont run anything prematurely). but i dont have linux so i can only hypothesize.
Last edited by xskinyx on Sat Feb 03, 2007 4:37 am, edited 2 times in total.
kornerr
Posts: 245
Joined: Thu Jul 06, 2006 9:57 am
Location: Russia, Siberia, Kemerovo
Contact:

Post by kornerr »

it's the same as vitek posted.
we need someone who found a way to cope with the problem on Linux
Open Source all the way, baby ;)
OSRPG
Post Reply