When windows launches my program with /p argument, it initializes SDL window over HWND of that little preview monitor. The problem is, when the preview window closes, my process keeps running. I've tried to catch WM_DESTROY using SDL_SYSWMEVENT, but it didn't work: it catches WM_SETCURSOR, WM_NCHITTEST and some others, but not destroy. How to fix that problem?
Here's my code.
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
#include <windows.h>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cstdio>
char *lowercase(const char *str) {
char *ans=new char[strlen(str)+1]; int i;
for (i=0;str[i]>0;i++) ans[i]=tolower(str[i]);
ans[i]=0; return ans;
}
int main(int argc,char **argv) {
if (argc>1&&(strcmp(lowercase(argv[1]),"/c")==0||strcmp(lowercase(argv[1]),"-c")==0)) {
MessageBox(NULL,"Config should be there, WIP!","Screensaver",MB_OK);
return 0;
}
FILE *f;
SDL_Init(SDL_INIT_VIDEO);
int SCREEN_WIDTH,SCREEN_HEIGHT;
SDL_Window *wnd;
bool preview;
if (preview=(argc>2&&(strcmp(lowercase(argv[1]),"/p")==0||strcmp(lowercase(argv[1]),"-p")==0))) {
wnd=SDL_CreateWindowFrom((HWND)atoi(argv[2]));
SDL_GetWindowSize(wnd,&SCREEN_WIDTH,&SCREEN_HEIGHT);
} else {
SDL_DisplayMode tmp;
SDL_GetCurrentDisplayMode(0,&tmp);
SCREEN_WIDTH=tmp.w;SCREEN_HEIGHT=tmp.h;
wnd=SDL_CreateWindow("",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,SCREEN_WIDTH,SCREEN_HEIGHT,SDL_WINDOW_SHOWN|SDL_WINDOW_FULLSCREEN);
}
SDL_Renderer *rnd=SDL_CreateRenderer(wnd,-1,SDL_RENDERER_ACCELERATED);
SDL_DisableScreenSaver();
bool quit=false;
SDL_Event evt;
SDL_EventState(SDL_SYSWMEVENT,SDL_ENABLE);
while (SDL_PollEvent(&evt)); //clear event queue
while (!quit) {
while (SDL_PollEvent(&evt)) switch (evt.type) {
/* does not work
case SDL_SYSWMEVENT: {
if (evt.syswm.msg->msg.win.msg==WM_DESTROY) quit=true;
break;
}
*/
case SDL_QUIT:
quit=true;
break;
case SDL_KEYDOWN:
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEMOTION:
if (!preview) quit=true;
break;
}
SDL_RenderClear(rnd);
SDL_SetRenderDrawColor(rnd,255,255,255,255);
SDL_RenderDrawLine(rnd,0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
SDL_SetRenderDrawColor(rnd,0,0,0,255);
SDL_RenderPresent(rnd);
SDL_Delay(20);
}
SDL_Quit();
return 0;
}
Looking at this article, it appears the message combo you are looking for is
WM_SYSCOMMAND SC_CLOSE
Okay, after long research I've found an answer. Thanks to that guy.
if (!IsWindow(previewHwnd)) quit=true;
Related
I encountered a strange bug using SDL_PollEvent to detect an SDL_Quit event. Whenever I click the X on the window it works fine and ends the program but whenever I hold down the X button it pauses the execution of the program. Any idea why this is happening, and is there a way around it?
Here is my code:
main.cpp
#include "Game.h"
int main() {
Game* game = nullptr;
while(game->running) {
game->checkForClose();
return 0;
}
Game.h
#ifndef GAME_H_
#define GAME_H_
#include "SDL.h"
class Game {
public:
Game();
~Game();
void checkForClose();
static bool running;
static SDL_Event event;
};
#endif
Game.cpp
#include "Game.h"
#include <iostream>
void Game::checkForClose() {
SDL_PollEvent(&event);
switch (event.type) {
case SDL_QUIT:
running = false;
std::cout << "Program Terminated!" << std::endl;
break;
default:
break;
}
}
P.S. I am on MacOS
I am trying to make it my screen print hello when I click the a key... And switch images when I press the 2 key... however when I do, nothing happens, I'm not sure why... it does not give me an error for some weird reason... if you have any ideas please let me know in the comments below. I have listed the code there!
#include <SDL.h>
#include <iostream>
int main(int argc, char* argv[])
{
SDL_Window* window = nullptr;
SDL_Surface* WindowSurface = nullptr;
SDL_Surface* image1 = nullptr;
SDL_Surface* image2 = nullptr;
SDL_Surface* currentImage = nullptr;
SDL_Init(SDL_INIT_VIDEO);
window = SDL_CreateWindow("sdl Window",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480,
SDL_WINDOW_SHOWN);
WindowSurface = SDL_GetWindowSurface(window);
image1 = SDL_LoadBMP("Red_sheet_full_2.bmp");
image2 = SDL_LoadBMP("Red_sheet_fullA.bmp");
currentImage = image2;
bool isRunning = true;
SDL_Event ev;
while (isRunning)
{
while (SDL_PollEvent(&ev) != 0);
{
if (ev.type == SDL_QUIT)
isRunning = false;
else if (ev.type == SDL_KEYDOWN)
{
switch (ev.key.keysym.sym)
case SDLK_a:
printf("hello");
break;
switch (ev.key.keysym.sym)
case SDLK_2:
currentImage = image1;
break;
}
}
SDL_BlitSurface(currentImage, NULL, WindowSurface, NULL);
SDL_UpdateWindowSurface(window);
}
SDL_FreeSurface(image1);
SDL_FreeSurface(image2);
SDL_DestroyWindow(window);
currentImage = image1 = image2 = nullptr;
window = nullptr;
SDL_Quit();
return 0;
}
The problem is in the switch statement. The break is outside the switch so, if the first event you receive is not an SDLK_a, it will break out of the while loop before printing hello and exit.
Here's a simplified version of what's happening: https://godbolt.org/z/9eEcEYGhj
#include <iostream>
int main(int argc, char* argv[])
{
while (true)
{
char c{'p'};
switch (c)
case 'a':
std::cout << "a\n";
break; // exits without printing anything
switch (c)
case 'b':
std::cout << "b\n";
break;
std::cout << c;
}
}
You have different ways to fix it.
One would be to write the switch statement in a proper way: https://godbolt.org/z/99MohaTMx
#include <iostream>
int main(int argc, char* argv[])
{
while (true)
{
char c{'a'};
switch (c)
{
case 'a':
std::cout << "a\n"; // forever prints "a\n"
break;
case 'b':
std::cout << "b\n";
break;
default:
break;
}
}
}
Another one, just for your current implementation, would be to use an if-else if instead of a switch.
Here is the main file of the game snake I am developing. It uses OpenGL and ncurses. Everything runs exactly like I want it too, but I can only input my key presses to play the game if my command line terminal is the top level process of my computer. Currently, when I run the program, the OpenGL window spawns ontop of my command line prompt and then I need to re select my command line prompt and bring it to the front to play my game.
I want my terminal to recognize my key presses when the terminal is behind the openGL window. How do I do this if it is possible? I am using Ubuntu Linux.
#include <chrono>
#include <thread>
#include <unistd.h>
#include <ncurses.h>
#include "Snake.h"
#include <GL/glut.h>
int khbit(void)
{
int ch = getch();
if (ch != ERR)
{
ungetch(ch);
return 1;
}
else
{
return 0;
}
}
int main(int argc, char **argv)
{
std::unique_ptr<GameBoxes::Box> squareBackground(new GameBoxes::Box(std::stoi(argv[1]), std::stoi(argv[2]),
std::stoi(argv[3]), std::stoi(argv[4])));
int cArgs[4];
(*squareBackground).getSizeArray(cArgs);
glutInit(&argc, argv);
(*squareBackground).createBackGroundTexture();
glClear(GL_COLOR_BUFFER_BIT); //new
// initialize random seed:
srand (time(NULL));
// start ncurses
initscr();
// Line buffering disabled
cbreak();
// Don't echo while we do getch
noecho();
// Allows checking for Keypress
nodelay(stdscr, TRUE);
scrollok(stdscr, TRUE);
bool play = true;
while (play == true)
{
bool alive = true;
std::unique_ptr<GameBoxes::Snake> snake(new GameBoxes::Snake(*squareBackground, cArgs)); //new
int direction;
char directionTwo = 't';
flushinp();
while (alive == true)
{
if (khbit())
{
direction = getch();
directionTwo = direction;
alive = (*snake).moveSnake(*squareBackground, direction, cArgs); // Grow into a loop
flushinp();
}
else
{
alive = (*snake).moveSnake(*squareBackground, directionTwo, cArgs); // Grow into a loop
}
if (direction == 'k')
{
endwin();
return 0;
}
std::chrono::milliseconds dura( 40);
std::this_thread::sleep_for( dura );
}
}
glutMainLoop();
return 0;
}
I have a program in which I shutdown windows this emits a sound. Up to this point all great. But when I hide the window console the program does not emit the sound. Is there some solution for this?
#include <stdio.h>
#include <iostream>
#include <windows.h>
#include <fstream>
#include <direct.h>
#include <dirent.h>
#include <sstream>
BOOL CtrlHandler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
case CTRL_SHUTDOWN_EVENT:
Beep(750, 500);
return FALSE;
default:
return FALSE;
}
}
int main(void)
{
//ShowWindow(GetForegroundWindow(),SW_HIDE);//Hide the window console
if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE))
{
while (1)
{
Sleep(500);
}
}
else
printf("\nERROR: Could not set control handler");
}
I'm trying to catch keypress events using XLib. But for some reasons XNextEvent not working.
I'm not receiving any errors, but it looks like my program stuck on the line of "XNextEvent" call.
Here is my code:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
using namespace std;
int main()
{
XEvent event;
KeySym key;
char text[255];
Display *dis;
dis = XOpenDisplay(NULL);
while (1) {
XNextEvent(dis, &event);
if (event.type==KeyPress && XLookupString(&event.xkey,text,255,&key,0) == 1) {
if (text[0]=='q') {
XCloseDisplay(dis);
return 0;
}
printf("You pressed the %c key!\n", text[0]);
}
}
return 0;
}
This is not how X11 windowing system works.
Read this carefully. The key point is :
The source of the event is the viewable window that the pointer is in.
You do not create a window, therefore your program doesn't receive keyboard events. Even if you created window, it has to have focus :
The window used by the X server to report these events depends on the window's position in the window hierarchy and whether any intervening window prohibits the generation of these events.
Working example
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
using namespace std;
int main()
{
XEvent event;
Display *dis;
Window root;
Bool owner_events = False;
unsigned int modifiers = ControlMask | LockMask;
dis = XOpenDisplay(NULL);
root = XDefaultRootWindow(dis);
unsigned int keycode = XKeysymToKeycode(dis, XK_P);
XSelectInput(dis,root, KeyPressMask);
XGrabKey(dis, keycode, modifiers, root, owner_events, GrabModeAsync, GrabModeAsync);
while (1) {
Bool QuiteCycle = False;
XNextEvent(dis, &event);
if (event.type == KeyPress) {
cout << "Hot key pressed!" << endl;
XUngrabKey(dis, keycode, modifiers, root);
QuiteCycle = True;
}
if (QuiteCycle) {
break;
}
}
XCloseDisplay(dis);
return 0;
}