C++, detecting if mouse is idle-ing (short-time, 20ms) - c++

this is my first post!
I'm writing a C++ program to control main character in Touhou Games series; i'm making it for those who have hands disabilities and can't click arrow keys, but still can use mouse.
The player should trigger Arrow Keys with mouse movements (mouse goes left and left key is pressed, and so on..). I already did that part, but the character moves as if the arrow keys were pressed multiple times, so the character movements are a little clumsy and rough, not smooth and clean as if the key was HOLD.
My problem is that i have to know when mouse is idling/not moving (to understand how long the player wants to hold the arrow key -- the more the player slides the mouse in a direction, the more that arrow key is hold), but can't figure out how. Searching on Stackoverflow i've found GetLastInput function, but it triggers for EVERY input, and is not mouse-only related.
It should come out something like:
while( *mousenotidling* )
{
//holdbutton
}
What would you suggest? How can i know when mouse is idling (for short-times, like 20ms)? (or if you suggest other solutions, every opinion is welcomed)
I'm writing it in C++, with Codeblock and GCC compiler, my OS is Windows 7 x86 :)

You can call TrackMouseEvent and set the idling time to what is desire like 2000ms for 2sec idle time. Also you can use GetLastInputInfo to get the amount of milliseconds the last key or mouse movement was performed.
DWORD GetIdleTime()
{
LASTINPUTINFO pInput;
pInput.cbSize = sizeof(LASTINPUTINFO);
if (!GetLastInputInfo(&pInput))
{
// any errors will be reported
}
// return idle time in milliseconds
return pInput.dwTime;
}
Also you can try this one suggestion
int prev_x = 0, prev_y = 0; while (1)
{int x = ..., y = ...; if (x == prev_x && y == prev_y) {mouse was moved}
else {mouse wasn't moved} prev_x = x; prev_y = y;}

Related

Function gets called multiple times

So, inside the game loop function that tracks user input is called multiple times. I guess this happens because game loop goes like 40 iterations each second and if I hold down the key for a 0.5 second, function gets called 20 times. I tried to handle this with sfml events too but it didn't work window.setKeyRepeatEnabled(false). How can I solve this?
//this gets called 20-30times
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
leftPlayerPoints++;
}
Use two boolean flags: One for checking if the key is pressed or not, and one that is used to check if the action have happened yet.
In short something like
if (key_is_pressed)
{
if (!action_have_happened)
{
// Perform action...
action_have_happened = true;
}
// Else: Action have already happened this key-press, don't do it again
}
When the key is released reset both flags (to false).
That's what exactly IsKeyPressed is suppose to do , you have to use bitmasking and make it toggle state instead of continuing pressing.
Below is code from Win32API (C++). I know SFML has different events than Win32API but Masking should work in SFML also.
BOOL IsKeyToggled(CONST INT key)
{
SHORT key_state = GetAsyncKeyState(key);
BOOL is_toggled = key_state & 0x1;
return is_toggled;
}
The main point here is key_state & 0x1; bit masking with 0x1

Issues creating light sequence with pause button ARDUINO

So I am trying to create a program that runs various light sequences using an Arduino board. I am not very familiar with C++ so I feel that my lack of syntax knowledge is preventing me from accomplishing my goal.
My idea is to have various light sequences that are played depending on what button is pressed on an infrared remote. The amount of time that a light is on or off may or may not be the same as that of another light. Unfortunately, the sequences do not seem to be working which indicates that the issue is likely with the toggleLight function.
I also wanted there to be a button that allows the user to pause the sequence (no matter where along the sequence it is). And once the button is pressed again, then the sequence continues where it left off. I read something about an interrupter and sleep mode using C++ but I am unfamiliar with this so it is not included in my code.
The rest of my goals I have included within my code. I created an object "light" because I was trying to create the sequence without using the delay function as the interrupt does not work well with the delay function (as far as I am aware). Then I am able to call the function toggleLight on the specific light object. However, as I previously stated the sequences are not working.
I am more familiar with OOP languages so perhaps creating an object is not the best for Arduino. If anyone has any ideas for how I can accomplish my goal it would be much appreciated.
unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
//sets up the Infrared receiver for the remote controller
const int RECV_PIN = 1;
IRrecv irrecv(RECV_PIN);
decode_results results;
//Sets up the LED's pin number and light status
class light{
private:
int _pinNumber;
byte _Lstatus;
public:
//function that creates the objects with the parameters
light(int pinNum, byte Lstat){
_pinNumber = pinNum;
_Lstatus = Lstat;}
void toggleLight(long interval){
//ensures that the "interval" amount of time has passed between the last LED blink
if ((currentMillis - previousMillis) >= interval) {
// if the LED is off turn it on and vice-versa:
if (_Lstatus == LOW) {
_Lstatus = HIGH;
} else if (_Lstatus == HIGH) {
_Lstatus = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(_pinNumber, _Lstatus);
// save the last time you blinked the LED
previousMillis = currentMillis;
}
}
};
//creating four light objects with the pins and initial status of off.
light J1(13, LOW);
light J2(11, LOW);
light P1(12, LOW);
light P2(10, LOW);
void setup()
{
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
}
//Sequence 1 is a mock sequence. It will probably be longer and the intervals would not all be 1000
void seq1(){
currentMillis = millis();
J1.toggleLight(1000);
P1.toggleLight(1000);
J1.toggleLight(1000);
P1.toggleLight(1000);
J2.toggleLight(1000);
P2.toggleLight(1000);
}
void seq2(){
currentMillis = millis(); //I found that placing currentMillis = millis() here allows the lights to at least turn on
J1.toggleLight(2000);
J1.toggleLight(10);
P1.toggleLight(1000);
P1.toggleLight(0);
J2.toggleLight(1500);
J2.toggleLight(1);
P2.toggleLight(2000);
P2.toggleLight(1);
}
void loop()
{
/* So once i get the sequences working, my idea is to have different sequences play
depending on what button on the remote is pressed. However, first I want to get the sequences and
interrupter
For now I have just tried running sequence #2 but it does not work.. Neither does Sequence #1. */
seq2();
//I MADE THESE LINES OF CODE COMMENTS FOR NOW. UNTIL I GET THE REST OF THE PROGRAM WORKING
/*if (irrecv.decode(&results))
{
switch (results.value) {
case : 0xf00000 // When button #1 sequence one plays
seq1();
break;
case : 0xf00000 // when button #2 is pressed, sequence two plays
seq2();
break;
*/
}
I can see that you haven't yet got around to understanding the flow of code inside the Arduino. Here's a quick tutorial to get you up and running.
Basically, your code is not being processed sequentially. So when the processor is moving through seq() and gets to the first if statement in 'J1.toggleLight(2000);' and finds that the condition is not met (i.e. the 2000 milliseconds have not yet passed,) it immediately moves on to the second line in seq(). The issue with this is that when it does meet the condition at the second line it will reset the 'previousMillis' value which all the lights depend on.
Thus you should dedicate a clock for each light by moving in 'previousMillis' into the class as a member.
class light{
private:
int _pinNumber;
byte _Lstatus;
unsigned long previousMillis = 0;
This way each light will be able to keep track of its own time without conflicting with the other lights. This will lead to your lights flickering at a frequency of 1/interval which I doubt is what you want.(it wont even do that with each light getting toggled twice in the seq() functions. Try removing the second calls and see hat happens) This brings me to the second issue.
The second issue is with the way you set up your sequences. Since you want to the lights to operate sequentially you'll need to find the accumulated time which crosses out the chance of using a class, unless you're willing to implement a scheduling mechanism that takes account the interval and arrangement of each instance. Seems a bit impractical imo.
I think you should ditch the class and use a simple function that that accepts the eight values that each sequence requires. Then you could utilize if statements to manipulate the states of the lights.
I hope the answer made some sense.
Good luck.

How to prevent multiple sound calls in update loop of game engine?

I'm working on a game engine project (for learning purposes) and I've run into an issue with my audio system. I currently have a static PlaySound() function within my AudioSystem class that's defined like so:
void AudioSystem::PlaySound(uint16 soundID)
{
pendingSoundRequests[numSoundsPending].id = soundID;
numSoundsPending++;
}
Keeping in mind things are simplified here for ease of understanding. PendingSoundRequests is an array of soundEffect objects which only contain an id which is tied to a certain sound file. This function is called from other systems like my input system that plays a sound upon a certain key press:
void UpdateInput()
{
//....other code
if (keypress == spaceBar)
PlaySound(1)
}
This stores a soundID of 1 which plays a certain audio file. The AudioSystem will then loop over and play all sounds in it's update loop like so:
void AudioSystem::Update()
{
for (int i = 0; i < numSoundsPending; i++)
{
StartAudio(pendingSoundRequests[i].id);
//Reset all sounds id's to 0 meaning no sound should be played
//unless id is passed another number through PlaySound function
pendingSoundRequests[i].id = 0;
}
numSoundsPending = 0;
}
This works fine if the spacebar key is pressed only once, but if I hold down the key then since the update loop is called every frame, each individual sound keeps restarting itself and only playing the first millisecond of it's sound before being cut off by the same sound having to be played again on the next loop.
How would I go about creating some logic to prevent sounds from playing multiple times when I only want them to play once on the first press of the key?
Keep a list of what is currently playing, and remove it when it is done. When you go to start a sound you should check to see if the sound is already playing. If it is don't start the sound again. That way you avoid the issue.
You could put a sleep after the sound is played as long as the sound takes to play which would make it not play the next sound until after one sound is played. Are you using a separate thread for your audio system?
void AudioSystem::Update()
{
for (int i = 0; i < numSoundsPending; i++)
{
StartAudio(pendingSoundRequests[i].id);
//sleep here as long as the sound takes
//Reset all sounds id's to 0 meaning no sound should be played
//unless id is passed another number through PlaySound function
pendingSoundRequests[i].id = 0;
}
numSoundsPending = 0;
}
That might make a queue of sounds.
So you could do something like this:
//get current number of sounds pending
x = numSoundsPending
//sleep
//get new current after sleep
y = numSoundsPending
//get difference
z = y - x
//skip the difference
i = i + z
As far as I know, there are three types of key event:
Keydown: returns true only once per key press.
Keyup: returns true only once per key press.
Keypress: remains true when key is pressed.
you need Keydown event here.

Moving mouse position then back to beginning position

I'm trying to make keys move the mouse to a different position on the screen and then instantly back, at a very fast rate (50+ times per second) This is my current Code.
#include "stdafx.h"
#include <iostream>
#include <windows.h>
int main()
{
POINT p;
for( ; ; )
{
if (GetAsyncKeyState(0x57) < 0)
{
GetCursorPos(&p);
std::cout << "W key pressed";
SetCursorPos(0, 0);
SetCursorPos(p.x, p.y);
Sleep(100);
}
}
With this code it'll just change my mouse position then update as to where it was (I don't have free movement of my mouse and just keeps it at/around 0,0) If I put Sleep(100) at the end then it works pretty consistently but every ~10 seconds my mouse will get stuck at 0,0 again, the more I put up the sleep the less this happens, but why?
edit console app in Visual Studio
See documentation for GetAsyncKeyState
Return value
Type: SHORT
If the function succeeds, the return value specifies whether the key
was pressed since the last call to GetAsyncKeyState, and whether the
key is currently up or down. If the most significant bit is set, the
key is down, and if the least significant bit is set, the key was
pressed after the previous call to GetAsyncKeyState. However, you
should not rely on this last behavior; for more information, see the
Remarks.
Example
if (GetAsyncKeyState('W') & 0x8000)
{
std::cout << "W key pressed\n";
}
SetCursorPos(0,0) moves the cursor to top-left corner, while SetCursorPos(p.x, p.y) moves the cursor back to where it was when you called GetCursorPos. You won't see any changes to the mouse position.
It is not common to use these WinAPI functions in a console program.

Pausing in OpenGL successively

void keyPress(unsigned char key,int x,int y){
int i;
switch(key){
case 'f':
i = 3;
while(i--){
x_pos += 3;
sleep(100);
glutPostRedisplay();
}
}
}
Above is the code snippet written in C++ using GLUT library in Windows 7.
This function takes a character key and mouse co-ordinates x,y and performs translation along x-direction in 3 successive steps on pressing f character. Between each step the program should sleep for 100 ms.
We want to move a robot, and pause successively when he moves forward steps.
We are facing a problem in making the program sleep between the 3 steps. What is the problem in the above code snippet?
Disclaimer: The answer of jozxyqk seems better to me. This answer solves the problem in a dirty way.
You are misusing glutPostRedisplay, as is stated in this answer. The problem being, that glutPostRedisplay marks the current window as needing to be redisplayed, but it will only be done once you get in the glutMainLoop again. That does happen only once, hence only one sleep seems to work.
In fact all three sleeps work, but you get only one redraw after 300 ms.
To solve this, you have to find another way of redrawing the scene.
while(i--){
x_pos += 3;
sleep(100);
yourDrawFunction();
}
Assuming that you are working on a UNIX system.
sleep for 100 ms
sleep(100);
The problem here is, that you are sleeping for 100 seconds, as you are probably using the sleep function of the <unistd.h> header, which defines sleep() as:
extern unsigned int sleep (unsigned int __seconds);
What you want is probably something like
usleep(100000); //sleeps for 100000 microseconds == 100 ms
I believe the issue with your code is your sleep is messing with glut's main loop. The call stack might look something like this
main() -> glutMainLoop() -> keyPress() -> sleep()
#but can't get to this...
main() -> glutMainLoop() -> display()
Until keyPress() returns, glut's main loop cannot continue to render the next frame. It's waiting for the function to return. All glutPostRedisplay() does is say "hey, something's changed so the image is stale and we need to redraw the next time the main loop iterates". It doesn't actually call display().
You'll have to structure your code such that the main loop can continue as normal, but still include a delay between drawing. For example:
In keyPress(), set a moving = true state. Let the function return.
In the idle() function, call sleep() if moving or maybe if you have moved last time (really you might want to look into calculating elapsed time and do the timing yourself so you don't block the entire program)
Again in idle() increase x_pos and decrease your move count, let the function return, glut will draw, then call idle again and you can sleep/move again.