so I've got this code:
bool toggl = false;
while (!GetAsyncKeyState(VK_END)) {
if (GetAsyncKeyState(VK_INSERT)) {
if (toggl) {
toggl = false;
std::cout << "Off" << std::endl;
}
else {
toggl = true;
std::cout << "On" << std::endl;
}
}
}
The problem is whenever I click insert it just creates a infinite loop changing from false to true. When I use break my whole window just closes.
Any help appreciated.
Thanks,
Ossie
From the documentation for GetAsyncKeyState: "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."
hi lo
1000 0000 0000 0001
^ ^
| |
| pressed since last call
key down (0 for up)
For the infinite loop you only need to have the key state be non-zero. Better tests...
0 != (GetAsyncKeyState(VK_INSERT) & 1) // pressed since last call
0 != (GetAsyncKeyState(VK_INSERT) & 0x8000) // key down
The same documentation warns about use of this last bit for mouse clicks and when other processes are using GetAsyncKeyState at the same time. Worth reading.
Current URL to documentation: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate
The problem is that when insert is tapped, your program will have looped on GetAsyncKeyState 20 or 30 times. And then your toggl flag is getting flipped each time. Hence, a new print statement.
I suspect this is what you really want:
bool toggl = false;
while (!GetAsyncKeyState(VK_END)) {
bool isInsertDown = (GetAsyncKeyState(VK_INSERT) != 0);
if (toggl && !isInsertDown)
{
toggl = false;
std::cout << "Off" << std::endl;
}
else if (!toggl && isInsertDown)
{
toggl = true;
std::cout << "On" << std::endl;
}
}
The above will flip the togl state to true when the insert key is down, and set it back to false when you lift your finger off the key.
But if you want to have toggl state changed on individual key presses. That is, first insert tap sets toggl to true and the next key press sets it back to false, then you'll need another variable. Hence:
bool toggl = false;
bool lastWasDown = false;
while (!GetAsyncKeyState(VK_END)) {
bool isInsertDown = GetAsyncKeyState(VK_INSERT) != 0;
if (isInsertDown == lastWasDown) {
continue;
}
if (isInsertDown && !toggl) {
toggl = true;
std::cout << "On" << std::endl;
}
else if (isInsertDown && toggl) {
toggl = false;
std::cout << "Off" << std::endl;
}
lastWasDown = isInsertDown;
}
Related
I am new to c++ and am currently learning sfml.
I have set up a system that adds one 'Snowpile' object to the vector. But when I keep hitting errors like "can't increment vector past iterator past end" or that it's outside the scope.
std::vector<Snowpile*> snowpiles;
I want it to check every snowpile for the removed2 bool, and delete the ones that do have it.
for (auto s_it = snowpiles.begin(); s_it != snowpiles.end(); s_it++) {
int sindex = std::distance(snowpiles.begin(), s_it);
if (snowpiles[sindex]->getSprite_S().getGlobalBounds().intersects(player.getSpriteP().getGlobalBounds()) && snowpiles[sindex]->melting == false) {
snowpiles[sindex]->melting = true;
}
else if (snowpiles[sindex]->getSprite_S().getGlobalBounds().intersects(player.getSpriteP().getGlobalBounds()) && snowpiles[sindex]->melting == true) {
snowpiles[sindex]->melting = true;
}
else if (!snowpiles[sindex]->getSprite_S().getGlobalBounds().intersects(player.getSpriteP().getGlobalBounds()) && snowpiles[sindex]->melting == true) {
snowpiles[sindex]->melting = false;
}
snowpiles[sindex]->meltedrem(sindex, snowpiles, m_win);
if (snowpiles[sindex]->removed2 == true)
{
cout << "Detected removed 2 at " << sindex << endl;
//delete snowpiles[sindex];
snowpiles.erase(snowpiles.begin() + sindex - 1);
}
}
The melting parts determine whether the player is on top of a snowpile. The meltdrem functions checks for bool 'melting' == true and then proceeds to start the timer. After a few seconds (+ animations) it sets the bool removed2 to true.
I know that at the program at least sees the bools changing, so thats not it.
Am I simply using vector wrong, or do I need to change something in my loop?
The loop is located in the while(window.isOpen()) loop in int main.
For starters it is unclear why there is used the expression
snowpiles.erase(snowpiles.begin() + sindex - 1);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
instead of
snowpiles.erase(snowpiles.begin() + sindex);
^^^^^^^^^^^^^^^^^^^^^^^^^^
if in a comment you wrote
//delete snowpiles[sindex];
You need to increase the iterator in the for loop only when a current object was not removed.
Change the loop the following way
for (auto s_it = snowpiles.begin(); s_it != snowpiles.end(); ) {
//...
if (snowpiles[sindex]->removed2 == true)
{
cout << "Detected removed 2 at " << sindex << endl;
//delete snowpiles[sindex];
s_it = snowpiles.erase( s_it );
}
else
{
++s_it;
}
}
I also tried to use Sleep because I saw in someone's code which was similar to mine but now it doesn't detect clicks I want it to detect
first I tested using the space key in my keyboard I thought it was only for space but when I tested using a character and mouse button I had the same issue so now I'm here to get help
here's my code:
void waitforspace()
{
bool strtd = false, stop = true, set = false;
std::chrono::steady_clock::time_point nw, thn;
std::thread t1;
while (true)
{
if ((GetKeyState(VK_RBUTTON) & 0x8000))
{
// I tried this to fix the repeating issue it worked but now most of the time my clicks doesn't get detected
if (!(GetKeyState(VK_RBUTTON) & 0x8000))
{
if (set)
{
nw = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> time_span = nw - thn;
set = false;
if (time_span.count() < 350.0)
{
std::cout << "Double click Detected!\n";
if (!strtd)
{
// Function I want to run if user clicked twice
t1 = std::thread(sendclicks, &stop);
strtd = true;
}
else
{
stop = false;
strtd = false;
}
}
}
else
{
std::cout << "One click Detected!\n";
thn = std::chrono::high_resolution_clock::now();
set = true;
}
}
}
}
}
So im doing a sort Method using the bubble sort and compareTo method
Yet for some reason, when I run the program it compiles, does no errors whatsoever and shows a blinking cursor in the program (as if u are about to type something in; which u can, just when u press enter nothing happens) and this cursor keeps blinking.
What's wrong here ? (code based on teacher's instructions)
public static void sort(ArrayList al)
{
Person p,p1,p2;
String a1,a2;
boolean flag = true;
System.out.println("Database will be sorted acc to ID ");
System.out.println();
do
{
flag = false;
for (int i=0;i<al.size()-1;i++)
{
p = (Person)al.get(i);
a1=((Person)al.get(i)).personID;
a2=((Person)al.get(i+1)).personID;
if (a1.compareTo(a2) > 0){
p1= (Person)al.get(i);
p2 =(Person)al.get(i+1);
}
}
}
while (flag = true);
if (flag = false)
{
for (int i = 0; i < al.size(); i++)
{
p = (Person) al.get(i);
System.out.println("----------" + (i+1) + "-----------");
System.out.println("ID Number: "+ p.personID);
System.out.println("Name: "+ p.name);
System.out.println("Day of Birth: " +p.dayDOB);
System.out.println("Month of Birth: " +p.monthDOB);
System.out.println("Year of Birth: " +p.yearDOB);
System.out.println("Telephone Number: " +p.telNum);
System.out.println("");
}
}
The problem is in this loop:
do
{
....
}
while (flag = true);
You want to compare flag to true, i.e. flag == true, but instead you set flag to true with flag = true. Therefore, the loop will not exit, but instead run forever (or until you terminate the program).
You have the same problem in the following if statement.
I am trying to implement a retry in the while loop. I want to retry 5 times and if the flag becomes true.
bool flag = false;
unsigned int count = 5;
while(!flag && count > 0) {
DataOperation opt = DataUser::Insert(data_point);
if(opt == DataOperation::DataEnum) {
UserPointData exist = DataUser::FindUser(data_point->user_id());
if(exist) {
exist->attributeData.put(key, value, len_value, client_id, last_modified_date);
flag = true;
}
} else {
// insert in data_point
data_point->attributeData.put(key, value, len_value, client_id, last_modified_date);
flag = true;
}
count--;
}
So if flag becomes true, then I will exit out of the loop
Second case, if flag is false for 5 times, then I will exit out of the loop as well.
Does this look right what I am doing?
Just like #Borgleader pointed out, the flag variable is unnecessary. You can stick with a break instruction and check after the loop if the count is still bigger than zero. If so, means your task succeeded.
unsigned int count = 5;
while(count > 0) {
DataOperation opt = DataUser::Insert(data_point);
if(opt == DataOperation::DataEnum) {
UserPointData exist = DataUser::FindUser(data_point->user_id());
if(exist) {
exist->attributeData.put(key, value, len_value, client_id, last_modified_date);
break; // success.
}
} else {
// insert in data_point
data_point->attributeData.put(key, value, len_value, client_id, last_modified_date);
break; // success.
}
count--;
}
if (count > 0) { /* succeeded within 5 tries. */ }
What you are doing seems fine but possibly more complicated than it needs to be.
For example you don't need to set a flag to exit you can simply call break;.
Here is a pattern I sometimes use that maybe simpler:
bool succeed_at_doing_stuff()
{
std::cout << "trying" << '\n';
return false;
}
int main()
{
int retries = 3;
while(retries--) // will exit when retries == 0, retries then becomes -1
{
if(succeed_at_doing_stuff())
break; // no need to set a flag
// take alternative action
}
if(retries < 0) // retries was decremented after last check
{
std::cerr << "error: gave up - too many retries" << std::endl;
return 1;
}
}
If you will use count variable only for that purpose, I suggest you to use a for loop so count will not be visible and memory of it will be reclaimed after exiting the scope of the loop. And use break statement to immediately exit the loop.
for(auto count = 0; count<5; ++count) {
DataOperation opt = DataUser::Insert(data_point);
if(opt == DataOperation::DataEnum) {
UserPointData exist = DataUser::FindUser(data_point->user_id());
if(exist) {
exist->attributeData.put(key, value, len_value, client_id, last_modified_date);
break;
}
} else {
// insert in data_point
data_point->attributeData.put(key, value, len_value, client_id, last_modified_date);
break;
}
}
The only change I would make is
if(opt == DataOperation::DataEnum) {
UserPointData exist = DataUser::FindUser(data_point->user_id());
if(exist) {
exist->attributeData.put(key, value, len_value, client_id, last_modified_date);
flag = true;
} else {
count--;
}
I am not crazy about you setting count to 5 then counting down, as it is more obvious if you increment until you reach 5, but this will work.
You may want to break instead of setting flag, unless you are planning on using flag to differentiate between finding a match or exiting due to the conditional.
Problem with returning booleans in c++..
bool find( const TrieNode &node, const string word )
{
if (word.length() == 0)
{
if (node.isWord)
{
cout << "TRUE" << endl;
return true;
}
else
{
cout << "FALSE" << endl;
return false;
}
}
char firstletter = word.at(0);
int index = firstletter - 'a';
if (node.letters[index] == NULL)
{
return false;
}
else
{
find (*node.letters[index],word.substr(1,(word.length() - 1)));
}
}
in my main I have
cout << find(*mynode,"word") << endl;
would yield to :
FALSE
95
clearly, a cout of FALSE means that the function returns false.. However, when I print out the result of the function, I get 95 which evaluates to true.. Any reason why it could be doing this?
thanks
Your missing a final return statement, so your getting whatever is in the low byte of EAX, which is random garbage. your probably want return true; at the very end of your function.
Your should pump the warning level of your compiler as it should be telling you this (something along the lines of "not all control paths return a value").
The problem is with your final if statement:
if (node.letters[index] == NULL) {
return false;
}
else {
//if execution gets here, the return value of the function is undefined
find (*node.letters[index],word.substr(1,(word.length() - 1)));
}
...perhaps try:
if (node.letters[index] == NULL) {
return false;
}
else {
return find (*node.letters[index],word.substr(1,(word.length() - 1)));
}