Here is my code:
void MainGame::ProcessInput()
{SDL_Event Evnt;
while (SDL_PollEvent(&Evnt));
{switch(Evnt.type)
{case SDL_QUIT: {_GameState = GameState::EXIT;}
break;
case SDL_MOUSEMOTION: {}
break;
case SDL_KEYDOWN: {_InputManager.PressedKey(Evnt.key.keysym.scancode);}
break;
case SDL_KEYUP: {_InputManager.ReleasedKey(Evnt.key.keysym.scancode);}
break;
case 771: {std::cout << "Info1 = " << Evnt.key.keysym.scancode << std::endl;
_InputManager.PressedKey(Evnt.key.keysym.scancode); }
break;
}
}
}
So in this code, if I push up, down, left and right arrows, KEYDOWN is working properly. If I hit any letters on my keyboard, it will only return code 771. Here I made a test including 771 in my switch. When I hit letters, it does go to 771 and print a silly number like 30445778. And this number change every time I re-run the program. Man what's going on here?!? please help me
The problem you are facing is an additional ; after your while condition. Citing SDL wiki, your code should be written as follows:
while (1) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
/* handle your event here */
}
/* do some other stuff here -- draw your app, etc. */
}
Note that there's no semicolon after while.
However, although the code you've written does not do what you want it to do, it's still correct from C++ point of view.
This line:
while (SDL_PollEvent(&Evnt));
will enter a loop that will iterate up until the point SDL_PollEvent returns 0, while doing nothing.
After that, your switch statement will only run once, processing the last polled event (disregarding its type). In the same time, your switch statement is not ready to handle most of the event types.
Related
I'm rewriting some SDL things for practice from my Linux/Codeblocks setup to my Win7/VisStudio setup and I've hit an odd road block. SDL recognizes some keystrokes but not others. It reads the arrow keys, shift, alt, ctrl and a handful of others but it doesn't recognize a majority of keys, a-z 0-9, Space among others.
Neither:
SDL_GetScancodeName(event->key.keysym.scancode)
nor
SDL_GetKeyName(event->key.keysym.sym)
print any response from the problematic keys with a printf but responds fine for the working keys.
I double checked that my keyboard was set to English and I also tried a USB keyboard as opposed to my usual PS2 board just in case for some reason those were interfering but no result.
I've tried to find similar questions but I can't seem to find any that have specific keystroke problems like this.
Visual Studio 2017. SDL2, using libsdl.org's Dev libs. x86 if it matters.
EDIT:
I treated the symptoms but not the fever. If anyone could help I would like to have a better understanding for what went wrong and some better solutions.
I was trying to detect when no keys were being pressed, my original code was to follow:
if (e.type == SDL_KEYDOWN)
with an:
else
for when no keys were pressed. This worked fine except for the problem keys.
I'm curious as to why this only affected some keys and possibly an alternative to detecting when no keys are pressed.
Here's an excerpt of the code I was using:
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_KEYDOWN)
{
switch (e.key.keysym.sym)
{
case SDLK_UP:
keyPressed = "Up";
printf("Keypress test: Up\n");
break;
case SDLK_SPACE:
keyPressed = "Space";
printf("Keypress test: Space\n");
break;
default:
break;
}
}
else
{
keyPressed = "None";
}
}
With the else I can correctly return the string keyPressed for SDLK_UP but not SDLK_SPACE. In this case both printf in the switch occur so I definitely step into it but the else seems to overwrite the string. Removing the else makes both work perfectly but then I can't detect when no keys are pressed.
I assume there is just something about SDLK_SPACE A-Z and 0-9 that I don't understand that causes the program to step into the else.
I quickly made a git to post the code:
https://github.com/TorsvikVonClemson/AloeFoil00
It should display 5 shapes and a test rectangle. One for no key presses, on for each arrow key and the rect while pressing space.
Apologies if its sloppy, I haven't quite figured how to post straight from VS17.
Although this is a question from four years ago, I still want to provide my answer to help others in need.
// In your main loop
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
{
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
std::cout << "I want quit game\n"; // Working
break;
case SDLK_p:
std::cout << "I want pause game\n"; // Not working
break;
default:
break;
}
}
break;
case SDL_TEXTINPUT:
std::cout << event.text.text;
break;
default:
break;
}
}
If you check event type SDL_TEXTINPUT, you will find 0-9, a-z, etc. just go into case SDL_TEXTINPUT.
The soluction is SDL_StopTextInput, It's obvious:
// In your main loop
SDL_StopTextInput(); // Stop text input first.
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
{
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
std::cout << "I want quit game\n"; // Working
break;
case SDLK_p:
std::cout << "I want pause game\n"; // Working now🎉🎉🎉
break;
default:
break;
}
}
break;
case SDL_TEXTINPUT:
std::cout << event.text.text; // bye bye text input event 🎃
break;
default:
break;
}
}
If you want to reopen text input, just use SDL_StartTextInput.
Thanks #HolyBlackCat comment :)
I was thinking, is there any way you can use throw/try/catch without closing the program?
For example:
function
{
restore point:
//code goes here
try "something";
goto restore point;
}
Is there any method to call function and, if the condition is not verified in try statement, to go back to identifier?
Here`s my case:
int Automat::Retragere()
{
int suma;
cout<<"\n Introduceti suma pe care doriti s-o retrageti: ";
cin>>suma;
if(suma > 5000){
throw "\n Suma este mai mare decat plafonul maximal zilnic.";
}
else{
if(suma > sold){
throw "\n Suma este mai mare decat SOLDUL curent.";
}
else{
cout<<"Operatiune efectuata cu succes.";
sold = sold - suma;
return 1;
}
}
}
marcaj2:
//code here
switch(optiune){
case 1:
Retragere();
goto marcaj2;
case 2:
Depunere();
goto marcaj2;
case 3:
Transfer();
goto marcaj2;
default:
break;
}
I`m asking if, after calling "Retragere" function, is there a posibility to go back to my identifier in case try encounters an error.
In the case you present, Automat::Retragere should probably not throw any exceptions but just return error codes describing what was wrong, since "input too large" (larger than allowed or larger than sum on account) are not really exceptional states. Use an enum with speaking names for that instead of plain int. With a simple return value you are free to use ordinary control flow like a while loop for the input until the number is allowed etc.
Design interlude: That would be different if this was a routine expecting sanitized input so that these conditions indicate a program error. In fact, one should probably already at this stage separate data acquisition from business logic.
This means here that one function is responsible for obtaining the input and checking it; another function would expect valid input (no strings, but a number indicating a valid amount) and perform the actual business action like withdrawel or deposit. It's only a one-liner here but in the real world may involve establishing a connection of some sort, authentication etc.
The business function could throw when presented with an invalid number, because the data provider broke its contract.
Concerning the technical aspect of your question: The 2011 standard says in 15/3:
A goto, break, return, or continue statement can be used to transfer
control out of a try block or handler.
I cannot imagine any ordinary reason to do that, but it is not illegal. (Some of the provisions surrounding goto, arguably even goto proper, target machine generated code or similar scenarios.)
It may well be possible to handle certain exceptions locally; a saner approach (saner than goto directly from inside the catch block to somewhere in the function) would be to have the try/catch block in a loop. The catch block would examine the exception and either set an error code which is then checked in the loop condition, or possibly re-throw exceptions which are unknown or too severe to recover from locally.
Is this what you are looking for?
bool done = false;
while (!done)
{
//marcaj2:
switch(optiune){
case 1:
Retragere();
break; // break out of the switch, i.e. will continue at while (!done)
// so it similar to goto marcaj2
case 2:
Depunere();
break;
case 3:
Transfer();
break;
default:
done = true; // end the while loop
break;
}
}
Others have already commented that the exception throw is bad.
But if you really want it, I think you can do it something like:
bool done = false;
while (!done)
{
try
{
//marcaj2:
switch(optiune){
case 1:
Retragere();
break; // break out of the switch, i.e. will continue at while (!done)
// so it similar to goto marcaj2
case 2:
Depunere();
break;
case 3:
Transfer();
break;
default:
done = true; // end the while loop
break;
}
}
catch (...)
{
// error handling...
}
}
I'm wondering what the correct return value for a windows message loop is. So far I've used the following:
case WM_LBUTTONDOWN: // left mouse button pressed.
if (condition == true )
{
do_something();
}
break;
but I've seen also things like:
if (IDC_BUTTON == LOWORD(wParam) && BN_CLICKED == HIWORD(wParam))
{
do_something();
return true;
}
break;
which one is correct? Should I return true? or should I break? Does it matter?
EDIT does it depend whether I'm interacting with a button press or a mouse movement?
The return value is documented on MSDN, as part of the documentation for each message. For example, the documentation for WM_LBUTTONDOWN states that
If an application processes this message, it should return zero.
For other messages, the return value might be more meaningful. You should always read the documentation, never guess.
Whether you break or return depends upon the context - i.e. what you wish to do after processing this message. If you have nothing more to do - you may return immediately.
But when you do return from your message loop - make sure you return 0;
According to MSDN: If an application processes this message, it should return zero
If you use break, your execution remains in the current function. It allows you to set the result variable and perform some actions uniformaly before returning. But if you return, your execution will get to the calling function and will not continue to execute whatever you have further in the current function. So there is no correct variant - it's up to you to decide what to use: break or return. It depends on your own design.
For example:
bool result;
switch(msg)
{
case WM_LBUTTONDOWN:
//do smth...
result=true;
break;//execution goes to (3)
case WM_MOUSEMOVE:
//actions...
result=true;
break;//execution goes to (3)
case WM_RBUTTONDOWN:
//some code...
//no break here! execution continues to the next event
case WM_MWHEELUP:
//if WM_RBUTTONDOWN occured, execution continues to here and goes on
result=false;//maybe you need false here, I dont know
break;//processing WM_RBUTTONDOWN will stop only here, as well as processing WM_MWHEELUP
case WM_USER1:
//lines of code....
return true;//do not perform final actions starting from (3), but end up with this function immideately
default:
result=false;
}
// (3)
//perform some final actions...
return result;
It does not depend on what event you are interacting with.
I came across a case-switch piece of code today and was a bit surprised to see how it worked. The code was:
switch (blah)
{
case a:
break;
case b:
break;
case c:
case d:
case e:
{
/* code here */
}
break;
default :
return;
}
To my surprise in the scenario where the variable was c, the path went inside the "code here" segment. I agree there is no break at the end of the c part of the case switch, but I would have imagined it to go through default instead. When you land at a case blah: line, doesn't it check if your current value matches the particular case and only then let you in the specific segment? Otherwise what's the point of having a case?
This is called case fall-through, and is a desirable behavior. It allows you to share code between cases.
An example of how to use case fall-through behavior:
switch(blah)
{
case a:
function1();
case b:
function2();
case c:
function3();
break;
default:
break;
}
If you enter the switch when blah == a, then you will execute function1(), function2(), and function3().
If you don't want to have this behavior, you can opt out of it by including break statements.
switch(blah)
{
case a:
function1();
break;
case b:
function2();
break;
case c:
function3();
break;
default:
break;
}
The way a switch statement works is that it will (more or less) execute a goto to jump to your case label, and keep running from that point. When the execution hits a break, it leaves the switch block.
That is the correct behavior, and it is referred to as "falling through". This lets you have multiple cases handled by the same code. In advanced situations, you may want to perform some code in one case, then fall through to another case.
Contrived example:
switch(command)
{
case CMD_SAVEAS:
{
this->PromptForFilename();
} // DO NOT BREAK, we still want to save
case CMD_SAVE:
{
this->Save();
} break;
case CMD_CLOSE:
{
this->Close();
} break;
default:
break;
}
This is called a fall-through.
It is exactly doing what you are seeing: several cases is going to execute same piece of code.
It is also convenient in doing extra processing for certain case, and some shared logic:
// psuedo code:
void stopServer() {
switch (serverStatus)
case STARTING:
{
extraCleanUpForStartingServer();
// fall-thru
}
case STARTED:
{
deallocateResources();
serverStatus = STOPPED;
break;
}
case STOPPING:
case STOPPED:
default:
// ignored
break;
}
This is a typical use of fall-through in switch-case. In case of STARTING and STARTED, we need to do deallocateResources and change the status to STOPPED, but STARTING need some extra cleanup. By the above way, you can clearly present the 'common logic' plus extra logic in STARTING.
STOPPED, STOPPING and default are similar, all of them fall thru to default logic (which is ignoring).
It is not always a good way to code like this but if it is well used it can present the logic better.
Luckily for us, C++ doesn't depend on your imagination :-)
Think of the switch labels as "goto" labels, and the switch(blah) simply "goes to" the corresponding label, and then the code just flows from there.
Actually the switch statement works the way you observed. It is designed so that you can combine several cases together until a break is encountered and it acts something like a sieve.
Here is a real-world example from one of my projects:
struct keystore_entry *new_keystore(p_rsd_t rsd, enum keystore_entry_type type, const void *value, size_t size) {
struct keystore_entry *e;
e = rsd_malloc(rsd, sizeof(struct keystore_entry));
if ( !e )
return NULL;
e->type = type;
switch (e->type) {
case KE_DOUBLE:
memcpy(&e->dblval, value, sizeof(double));
break;
case KE_INTEGER:
memcpy(&e->intval, value, sizeof(int));
break;
/* NOTICE HERE */
case KE_STRING:
if ( size == 0 ) {
/* calculate the size if it's zero */
size = strlen((const char *)value);
}
case KE_VOIDPTR:
e->ptr = rsd_malloc(rsd, size);
e->size = size;
memcpy(e->ptr, value, size);
break;
/* TO HERE */
default:
return NULL;
}
return e;
}
The code for KE_STRING and KE_VOIDPTR cases is identical except for the calculation of size in case of string.
I have a general function that is supposed to handle any event in the SDL event queue. So far, the function looks like this:
int eventhandler(void* args){
cout << "Eventhandler started.\n";
while (!quit){
while (SDL_PollEvent(&event)){
cout << "Got event to handle: " << event.type << "\n";
switch (event.type){
SDL_KEYDOWN:
keyDownHandler(event.key.keysym.sym);
break;
default:
break;
}
}
}
}
However, when I test the function, I get a whole bunch of events but none of them seem to have a type. It doesn't even print 0 or anything — just nothing. The output when pressing any key looks like this:
Got event to handle:
And nothing else. Any tutorial and the SDL docs say that I should handle events like this, but it isn't working. Anybody else have this problem or a solution?
By the way, the eventhandler runs in an SDL_Thread, but I don't think that's the problem.
That nothing happens is a result of the missing case in front of SDL_KEYDOWN.
With case missing the compiler sees a jump label which you would use for e.g. goto SDL_KEYDOWN;, which results in the default label being the only label in the switch statement.
I don't see why event.type doesn't get output though unless you set some stream-flags somewhere.
event.type is an Uint8 which SDL just typedefs from integral types, so it should be handled like one. Like any integral type it also can't be "empty", but the output for it can be.