Mouse events not read in C++ console - c++

When I move my mouse or do any mouse related operations like clicking, it isn't picked up or read by ReadConsoleInput while keyboard events are picked up.
It used to work but now, I don't know what's causing problems which blocks the reading of mouse events.
This is the code i'm using, and I referred from This Website
DWORD numEvents = 0;
DWORD numEventsRead = 0;
while (appIsRunning)
{
reachedEnd = false;
GetNumberOfConsoleInputEvents(Input_Handle, &numEvents);
if (numEvents != 0)
{
INPUT_RECORD *eventBuffer = new INPUT_RECORD[numEvents];
ReadConsoleInput(Input_Handle, eventBuffer, numEvents, &numEventsRead);
for (DWORD i = 0; i < numEventsRead; ++i)
{
if (eventBuffer[i].EventType == KEY_EVENT) // this works
{
. // other
. // functions
if (eventBuffer[i].Event.KeyEvent.uChar.UnicodeChar == 'c' && eventBuffer[i].Event.KeyEvent.bKeyDown)
return true;
}
else if (eventBuffer[i].EventType == MOUSE_EVENT) // this doesnt work
{
cout << " E";
if (eventBuffer[i].Event.MouseEvent.dwButtonState == FROM_LEFT_1ST_BUTTON_PRESSED)
{
char x[50];
fstream file;
file.open("test.txt", ios::out);
cout << " YY";
SetConsoleCursorPosition(Output_Handle, { eventBuffer[i].Event.MouseEvent.dwMousePosition.X , eventBuffer[i].Event.MouseEvent.dwMousePosition.Y });
cin >> x;
file << "SetConsoleCursorPosition(out, { "
<< eventBuffer[i].Event.MouseEvent.dwMousePosition.X << " , "
<< eventBuffer[i].Event.MouseEvent.dwMousePosition.Y << "}); "
<< x;
}
}
}
delete[] eventBuffer;
}
if (reachedEnd)
return true;
}
I guess i should also post the code which sets the console mode and stuff
void initScr(COORD bufferSize, HANDLE& hOut, HANDLE& hIn, SMALL_RECT screen, SMALL_RECT side, Box& screenBox, Box& sideBox)
{
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
hIn = GetStdHandle(STD_INPUT_HANDLE);
CONSOLE_CURSOR_INFO cursorInfo;
SMALL_RECT windowSize = { 0, 0, bufferSize.X - 1, bufferSize.Y - 1 };
SetWindowPos(GetConsoleWindow(), HWND_TOPMOST, 5, 5, 0, 0, SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_NOSIZE);
SetConsoleWindowInfo(hOut, true, &windowSize);
SetConsoleScreenBufferSize(hOut, bufferSize);
SetConsoleMode(hOut, ENABLE_WINDOW_INPUT | ENABLE_INSERT_MODE | ENABLE_EXTENDED_FLAGS | ENABLE_MOUSE_INPUT);
cls(hOut); //Clears the whole screen
SetConsoleTitle(L"The Game");
GetConsoleCursorInfo(hOut, &cursorInfo);
cursorInfo.bVisible = false;
SetConsoleCursorInfo(hOut, &cursorInfo);
screenBox.drawBox(screen, hOut, COLOR(bRed | bGreen | bBright ));
sideBox.drawBox(side, hOut, COLOR(bRed | bGreen | bBright));
setcursorPos({ 91, 5 }, hOut);
cout << "Press \'C\' to re-create maze";
setcursorPos({ 91, 7 }, hOut);
cout << " Arrow keys for movement.";
setcursorPos({ 0,0 }, hOut);
}
I guess this part of my code is quite messy.

Your problem is enabled selection by mouse in console.
just open your console (Win + r) -> cmd, open properties and disable highlighting function
(I have russian language as my default, but checkbox that you need must be here (i highlighted it by red line))

You may need to pass the ENABLE_MOUSE_INPUT flag to SetConsoleMode().
Also notice that some functions will discard console mouse events. Read the notes at the linked SetConsoleMode documentation.

Related

Custom resolution on GCP VM (with T4 GPU on Windows Server 2019)

I am currently searching for a way to set a fully custom resolution on a Windows Server 2019 VM with GPU (T4, with grid licence, and virtual workstation grid drivers) with C++.
I have tried different way to achieve this, I can make this work on my laptop, but seems to have some limitations on GCP VMs (or Windows Server limitation).
I have tried to do this with ChangeDisplaySettings/ChangeDisplaySettingsEx (winuser.h), I can change to a known resolution, but can't make it works with a custom one (not even with CDS_ENABLE_UNSAFE_MODE).
DWORD deviceIndex = 0;
DISPLAY_DEVICE displayDevice = { 0 };
displayDevice.cb = sizeof(DISPLAY_DEVICE);
while (EnumDisplayDevices(NULL, deviceIndex, &displayDevice, 0)) {
deviceIndex++;
DEVMODE dm = { 0 };
dm.dmSize = sizeof(DEVMODE);
DEVMODE finalDm = { 0 };
finalDm.dmSize = sizeof(DEVMODE);
//Check if able to retrieve current settings
if (!EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &dm)) {
continue;
}
//Check if there is a difference in resolution list if UNSAFE_MODE is enabled or not (it seems to not change anything)
int result = ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, 0, CDS_DISABLE_UNSAFE_MODES, NULL);
std::cout << "CDS_DISABLE_UNSAFE_MODE" << std::endl;
if (result == DISP_CHANGE_SUCCESSFUL) {
for (int i = 0; EnumDisplaySettings(displayDevice.DeviceName, i, &dm) != 0; i++) {
if (dm.dmBitsPerPel == 32) {
std::cout << i << ". Found available resolution : " << dm.dmPelsWidth << " x " << dm.dmPelsHeight << " x " << dm.dmBitsPerPel << " # " << dm.dmDisplayFrequency << std::endl;
}
}
}
result = ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, 0, CDS_ENABLE_UNSAFE_MODES, NULL);
std::cout << "CDS_ENABLE_UNSAFE_MODE" << std::endl;
if (result == DISP_CHANGE_SUCCESSFUL) {
for (int i = 0; EnumDisplaySettings(displayDevice.DeviceName, i, &dm) != 0; i++) {
if (dm.dmBitsPerPel == 32) {
std::cout << i << ". Found available resolution : " << dm.dmPelsWidth << " x " << dm.dmPelsHeight << " x " << dm.dmBitsPerPel << " # " << dm.dmDisplayFrequency << std::endl;
}
}
}
std::cout << "Please enter width : ";
int width, height;
std::cin >> width;
std::cout << "Please enter height : ";
std::cin >> height;
dm.dmPelsWidth = width;
dm.dmPelsHeight = height;
if (width > height) {
dm.dmDisplayOrientation = DMDO_DEFAULT;
}
else {
dm.dmDisplayOrientation = DMDO_90;
}
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYORIENTATION;
//result = ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, NULL, CDS_TEST, NULL);
result = ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, NULL, 0, NULL);
if (result != DISP_CHANGE_SUCCESSFUL) {
std::cout << "Impossible to ChangeDisplaySettings" << endl;
}
else {
std::cout << "OK" << endl;
}
break;
}
I then take a look at NVAPI, and same here, I can make it works on my PC but still nothing on the GCP VMs... I have found a way to make NVAPI create and use custom resolution on my local PC, but can't make it works on GCP VM once again... (Code example found here)
NvAPI_Status result = NVAPI_ERROR;
NvU32 primaryDisplayId = 0;
//Testing resolution
int horizontal = 1920, vertical = 1090;
result = NvAPI_Initialize();
if (result != NVAPI_OK) {
printf("Could not initialize NvAPI");
return false;
}
MONITORINFOEX monInfo;
HMONITOR hMon;
const POINT ptZero = { 0, 0 };
// determine the location of the primary monitor
hMon = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
ZeroMemory(&monInfo, sizeof(monInfo));
monInfo.cbSize = sizeof(monInfo);
GetMonitorInfo(hMon, &monInfo);
result = NvAPI_DISP_GetGDIPrimaryDisplayId(&primaryDisplayId);
if (result != NVAPI_OK) {
printf("Could not get display ID from device");
NvAPI_Unload();
return false;
}
NvU32 deviceCount = 0;
NV_CUSTOM_DISPLAY cd[NVAPI_MAX_DISPLAYS] = { 0 };
float refreshRate = 60;
// timing computation (to get timing that suits the changes made)
NV_TIMING_FLAG flag = { 0 };
NV_TIMING_INPUT timing = { 0 };
timing.version = NV_TIMING_INPUT_VER;
timing.height = vertical;
timing.width = horizontal;
timing.rr = refreshRate;
timing.flag = flag;
timing.type = NV_TIMING_OVERRIDE_CVT_RB;
result = NvAPI_DISP_GetTiming(primaryDisplayId, &timing, &cd[0].timing);
if (result != NVAPI_OK) {
printf("Failed to get timing for display"); // failed to get custom display timing
NvAPI_Unload();
return false;
}
cd[0].width = horizontal;
cd[0].height = vertical;
cd[0].xRatio = 1;
cd[0].yRatio = 1;
cd[0].srcPartition = { 0, 0, 1.0, 1.0 };
cd[0].depth = 32;
cd[0].version = NV_CUSTOM_DISPLAY_VER;
cd[0].colorFormat = NV_FORMAT_A8R8G8B8;
//Returns NVAPI_ERROR on GCP but NVAPI_OK on my laptop
result = NvAPI_DISP_TryCustomDisplay(&primaryDisplayId, 1, cd);
if (result != NVAPI_OK) {
printf("Could not set custom resolution");
NvAPI_DISP_RevertCustomDisplayTrial(&primaryDisplayId, 1);
NvAPI_Unload();
return false;
}
else {
NvAPI_DISP_SaveCustomDisplay(&primaryDisplayId, 1, true, true);
}
This part works perfectly well on my laptop, I can use a new dynamic resolution (It works with 1920x400, 1920x500, 1920x600), but not on my GCP VM, this parts :
NvAPI_DISP_TryCustomDisplay(&primaryDisplayId, 1, cd);
always returns NVAPI_ERROR
I have found another trick, I can edit this registry entry : HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Video{RANDOM_ID}\0001\NV_Modes
(Here is an old pdf, after some testing, it seems it is still working this way)
If I add some resolution using NVAPI, I can then set through ChangeDisplaySettingsEx function this resolution (it needs GPU driver restart, or Windows restart be able to change to a fresh new added resolution).
But I need to be able to rotate screen, playing with "dmDisplayOrientation", and it does not seem to work on GCP VM once again, if I authorize for example 1920x1090 I can set resolution to this, but cannot set 1090x1920 with a "dmDisplayOrientation = DMDO_90" (even if I authorize 1090x1920 too...)
So if anyone found a way, or have any idea on how to do this, it would be great, I am running out of idea right now...

SDL2 cannot capture console keyboard events?

TL;DR
I am trying to capture keyboard events (more specifically, the Ctrl+c command) in my own C++ program. I am attempting this through generic keyboard presses in SDL2.
END TL;DR
I have found links on SO and the internet that cover the subject of handling keyboard events with SDL2. I have a few of them listed here.
https://stackoverflow.com/questions/28105533/sdl2-joystick-dont-capture-pressed-event
https://lazyfoo.net/tutorials/SDL/04_key_presses/index.php
http://www.cplusplus.com/forum/windows/182214/
http://gigi.nullneuron.net/gigilabs/handling-keyboard-and-mouse-events-in-sdl2/
The major issue I think is causing the problem is that I am also using an Xbox-style joystick at the same time. I have had no issues whatsoever with capturing joystick events. I have been doing that for a long time now. I am having issues trying to get anything with the keyboard to throw an event. I have tried if(event.type == SDL_KEYDOWN) and then checking which key it was, but that appears to return nothing. I feel like there is some macro that I need to define to allow this since I keep finding the same solutions on the internet.
I have included the entire script that I am running at the moment.
#include <boost/thread.hpp>
// Time library
#include <chrono>
// vector data structure
#include <vector>
// Thread-safe base variables
#include <atomic>
// std::cout
#include <iostream>
// Joystick library
#include <SDL2/SDL.h>
// Counters for printing
std::atomic_int printcounter{ 0 };
// This is every 3 * 1000 milliseconds
const int printer = 300;
// If an event is found, allow for printing.
std::atomic_bool eventupdate{ false };
// This function converts the raw joystick axis from the SDL library to proper double precision floating-point values.
double intToDouble(int input)
{
return (double) input / 32767.0 ;
}
// Prevent joystick values from going outside the physical limit
double clamp(double input)
{
return (input < -1.0) ? -1.0 : ( (input > 1.0) ? 1.0 : input);
}
// SDL library joystick deadband
const int JOYSTICK_DEAD_ZONE = 5000;
// These are the raw read in values from the joystick in XInput (XBox) mode.
//Normalized direction
int leftX = 0;
int leftY = 0;
int rightX = 0;
int rightY = 0;
int leftTrigger = -32768;
int rightTrigger = -32768;
// Button array
uint buttons[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Tbe pov hat is only 4 bits - 1, 2, 4, 8
int povhat = 0;
// These are the rectified joystick values
double leftstickx = 0;
double leftsticky = 0;
double rightstickx = 0;
double rightsticky = 0;
double lefttrigger = 0;
double righttrigger = 0;
// These are the rectified boolean buttons
bool leftstickbut = false;
bool rightstickbut = false;
bool xbutton = false;
bool ybutton = false;
bool abutton = false;
bool bbutton = false;
bool rightbut = false;
bool leftbut = false;
bool startbut = false;
bool backbut = false;
bool centbut = false;
// This is the boolean that controls running the robot.
std::atomic_bool quitrobot{false};
// Joystick values
static double joyvalues[6] = { 0, 0, 0, 0, 0, 0};
static bool joybuttons[11] = { false };
// Sleep function
void wait(int milliseconds)
{
boost::this_thread::sleep_for(boost::chrono::milliseconds{milliseconds});
}
// Now the main code
int main(int argc, char** argv)
{
// Now the robot goes through the looping code until a quit flag is set to true
while ( ! quitrobot)
{
// Now we look for an Xbox-style joystick
std::cout << "Looking for gamepad..." << std::endl;
while(true)
{
// Now the program waits until an Xbox-style joystick is plugged in.
// resetting SDL makes things more stable
SDL_Quit();
// restart SDL with the expectation that a jostick is required.
SDL_Init(SDL_INIT_JOYSTICK);
// SDL_HINT_GRAB_KEYBOARD
// check for a joystick
int res = SDL_NumJoysticks();
if (res > 0) { break; } // Here a joystick has been detected.
if (res < 0)
{
std::cout << "Joystick detection error: " << std::to_string(res) << std::endl;
}
// we don't want the program running super fast when detecting hardware.
wait(20);
}
// Now we check to make sure that the joystick is valid.
// Open the joystick for reading and store its handle in the joy variable
SDL_Joystick *joy = SDL_JoystickOpen(0);
if (joy == NULL) {
/* back to top of while loop */
continue;
}
// Get information about the joystick
const char *name = SDL_JoystickName(joy);
const int num_axes = SDL_JoystickNumAxes(joy);
const int num_buttons = SDL_JoystickNumButtons(joy);
const int num_hats = SDL_JoystickNumHats(joy);
printf("Now reading from joystick '%s' with:\n"
"%d axes\n"
"%d buttons\n"
"%d hats\n\n",
name,
num_axes,
num_buttons,
num_hats);
/* I'm using a logitech F350 wireless in X mode.
If num axis is 4, then gamepad is in D mode, so neutral drive and wait for X mode.
[SAFETY] This means 'D' becomes our robot-disable button.
This can be removed if that's not the goal. */
if (num_axes < 5) {
/* back to top of while loop */
continue;
}
// This is the read joystick and drive robot loop.
while(true)
{
// poll for disconnects or bad things
SDL_Event e;
if (SDL_PollEvent(&e)) {
// SDL generated quit command
if (e.type == SDL_QUIT) { break; }
// Checking for Ctrl+c on the keyboard
// SDL_Keymod modstates = SDL_GetModState();
// if (modstates & KMOD_CTRL)
// {
// One of the Ctrl keys are being held down
// std::cout << "Pressed Ctrl key." << std::endl;
// }
if(e.key.keysym.scancode == SDLK_RCTRL || e.key.keysym.scancode == SDLK_LCTRL || SDL_SCANCODE_RCTRL == e.key.keysym.scancode || e.key.keysym.scancode == SDL_SCANCODE_LCTRL)
{
std::cout << "Pressed QQQQ." << std::endl;
}
if (e.type == SDL_KEYDOWN)
{
switch(e.key.keysym.sym){
case SDLK_UP:
std::cout << "Pressed up." << std::endl;
break;
case SDLK_RCTRL:
std::cout << "Pressed up." << std::endl;
break;
case SDLK_LCTRL:
std::cout << "Pressed up." << std::endl;
break;
}
// Select surfaces based on key press
switch( e.key.keysym.sym )
{
case SDLK_UP:
std::cout << "Pressed Up." << std::endl;
break;
case SDLK_DOWN:
std::cout << "Pressed Up." << std::endl;
break;
case SDLK_LEFT:
std::cout << "Pressed Up." << std::endl;
break;
case SDLK_RIGHT:
std::cout << "Pressed Up." << std::endl;
break;
}
std::cout << "Pressed blah di blah blah please print me." << std::endl;
}
// Checking which joystick event occured
if (e.jdevice.type == SDL_JOYDEVICEREMOVED) { break; }
// Since joystick is not erroring out, we can
else if( e.type == SDL_JOYAXISMOTION )
{
//Motion on controller 0
if( e.jaxis.which == 0 )
{
// event happened
eventupdate = true;
// Left X axis
if( e.jaxis.axis == 0 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
leftX = 0;
}
else
{
leftX = e.jaxis.value;
}
}
// Right Y axis
else if( e.jaxis.axis == 1 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
leftY = 0;
}
else
{
leftY = e.jaxis.value;
}
}
// Left trigger
else if ( e.jaxis.axis == 2 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
leftTrigger = 0;
}
else
{
leftTrigger = e.jaxis.value;
}
}
// Right X axis
else if( e.jaxis.axis == 3 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
rightX = 0;
}
else
{
rightX = e.jaxis.value;
}
}
// Right Y axis
else if( e.jaxis.axis == 4 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
rightY = 0;
}
else
{
rightY = e.jaxis.value;
}
}
// Right trigger
else if( e.jaxis.axis == 5 )
{
// dead zone check
if( e.jaxis.value > -JOYSTICK_DEAD_ZONE && e.jaxis.value < JOYSTICK_DEAD_ZONE)
{
rightTrigger = 0;
}
else
{
rightTrigger = e.jaxis.value;
}
}
}
}
else if ( e.type == SDL_JOYBUTTONUP || e.type == SDL_JOYBUTTONDOWN )
{
// now we are looking for button events.
if (e.jbutton.which == 0)
{
// event happened
eventupdate = true;
// buttons[e.jbutton.button] = e.jbutton.state;
if (e.jbutton.button == 0)
{
buttons[0] = e.jbutton.state;
}
if (e.jbutton.button == 1)
{
buttons[1] = e.jbutton.state;
}
if (e.jbutton.button == 2)
{
buttons[2] = e.jbutton.state;
}
if (e.jbutton.button == 3)
{
buttons[3] = e.jbutton.state;
}
if (e.jbutton.button == 4)
{
buttons[4] = e.jbutton.state;
}
if (e.jbutton.button == 5)
{
buttons[5] = e.jbutton.state;
}
if (e.jbutton.button == 6)
{
buttons[6] = e.jbutton.state;
}
if (e.jbutton.button == 7)
{
buttons[7] = e.jbutton.state;
}
if (e.jbutton.button == 8)
{
buttons[8] = e.jbutton.state;
}
if (e.jbutton.button == 9)
{
buttons[9] = e.jbutton.state;
}
if (e.jbutton.button == 10)
{
buttons[10] = e.jbutton.state;
}
if (e.jbutton.button == 11)
{
buttons[11] = e.jbutton.state;
}
}
}
else if ( e.type == SDL_JOYHATMOTION)
{
if (e.jhat.which == 0)
{
// event happened
eventupdate = true;
povhat = e.jhat.value;
}
}
}
// Now that we have read in the values directly from the joystick we need top convert the values properly.
leftstickx = clamp(intToDouble(leftX));
leftsticky = clamp(intToDouble(leftY));
rightstickx = clamp(intToDouble(rightX));
rightsticky = clamp(intToDouble(rightY));
lefttrigger = clamp(intToDouble(leftTrigger));
righttrigger = clamp(intToDouble(rightTrigger));
// rectify the buttons to become boolean values instead of integers.
abutton = buttons[0] > 0;
bbutton = buttons[1] > 0;
xbutton = buttons[2] > 0;
ybutton = buttons[3] > 0;
//
rightbut = buttons[4] > 0;
leftbut = buttons[5] > 0;
//
centbut = buttons[8] > 0;
startbut = buttons[7] > 0;
backbut = buttons[6] > 0;
//
leftstickbut = buttons[9] > 0;
rightstickbut = buttons[10] > 0;
// Transfer axis to the array.
joyvalues[0] = leftstickx;
joyvalues[1] = leftsticky;
joyvalues[2] = rightstickx;
joyvalues[3] = rightsticky;
joyvalues[4] = lefttrigger;
joyvalues[5] = righttrigger;
// We are using the "B" button to quit the program
if (bbutton)
{
quitrobot = true;
std::cout << "Shutting down program." << std::endl;
break;
}
if (eventupdate)
{
// This section of code is meant for running code that happens when SDL has detected an event.
// This code section can be used for something else as well.
if (e.key.keysym.sym == SDL_SCANCODE_RCTRL || e.key.keysym.sym == SDL_SCANCODE_LCTRL || e.key.keysym.sym == SDLK_LCTRL || e.key.keysym.sym == SDLK_RCTRL)
{
std::cout << "SDL Event: Ctrl pressed.\n" << std::endl;
}
// Simply print the event
eventupdate = false;
} else {}
if ( ! (printcounter = ((printcounter + 1) % printer)))
{
// const Uint8 *state = SDL_GetKeyboardState(NULL);
// if (state[SDL_SCANCODE_RETURN]) {
// printf("<RETURN> is pressed.\n");
// }
}
// Sleep the program for a short bit
wait(5);
}
// Reset SDL since the robot is no longer being actuated.
SDL_JoystickClose(joy);
// We get here only if the joystick has been disconnected.
std::cout << "Gamepad disconnected.\n" << std::endl;
}
// The program then completes.
return 0;
}
The most important part of that huge block of code is lines 129 to 179. I was doing more fooling around trying to get key capture to work but I could not get a response. Everywhere else is logic for the joystick reading (which has worked for me flawlessly). I have been referring to this link for all of the macros available to the programmer. I have not been able to capture the left control button or the right control button. I have also been trying the arrow keys for kicks as well and those are not working either. I know there are remnants of other code snippets thrown in there as I was testing. Given all of my testing, I am just not sure how to capture any keyboard keys, let alone Ctrl+c. None of my desired print statements print.
I am able to run the code on Ubuntu 1804 LTS with the stock GUI manager and window manager. I have a feeling the problem might also have something to do with the operating system not letting SDL2 capture the keyboard, but I don't know what to do to allow only the keyboard or certain keys to be consumed by SDL2.
I am trying to not use platform-specific code since I already have successfully used platform-specific signal interrupts. My goal is to simply make a certain combination of depressed keys result in a program terminating. I figured that, since SDL2 can access all keys on a keyboard, that I should be able to simply
Unless you want to read keyboard input from stdin you need to open a window and focus it to get key events in SDL. Here's an example (note the call to SDL_Init uses SDL_INIT_VIDEO and there's some code in there for rendering a background and handling resize events).
#include <iostream>
#include <SDL2/SDL.h>
int main(int argc, char** argv)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0) { // also initialises the events subsystem
std::cout << "Failed to init SDL.\n";
return -1;
}
SDL_Window *window = SDL_CreateWindow(
"Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
680, 480, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if(!window) {
std::cout << "Failed to create window.\n";
return -1;
}
// Create renderer and select the color for drawing.
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 200, 200, 200, 255);
while(true)
{
// Clear the entire screen and present.
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_QUIT) {
SDL_Quit();
return 0;
}
if(event.type == SDL_WINDOWEVENT) {
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
int width = event.window.data1;
int height = event.window.data2;
std::cout << "resize event: " << width << "," << height << std::endl;
}
}
if (event.type == SDL_KEYDOWN) {
int key = event.key.keysym.sym;
if (key == SDLK_ESCAPE) {
SDL_Quit();
return 0;
}
std::cout << "key event: " << key << std::endl;
}
}
}
return 0;
}
Key events are sent to the currently focused window and SDL uses the underlying OS to handle this. E.g. In Linux this means SDL calls X11 functions.
edit:
As detailed in this question it appears you can also get a snapshot of the state of the keys. In either case I think a window needs to be opened to receive events even though I've edited this multiple times to come to that conclusion (apologies if that caused any confusion). Your OS may provide functions for polling the state of the keyboard without using events or windows, such as GetAsyncKeyState in Windows.

C++ Console - properly sized still leaves empty space for scroll bars

I am (as many before me, I have done a lot of searcing) trying to have my console display the buffer with no scroll bars. I have the window resized based on the system font size and the requested buffer size, but even after altering (and updating) the Console's style flags, I am still left with empty spaces where the horizontal and vertical scroll bars were.
Can anyone please assist me with this issue?
#include <windows.h>
#include <iostream>
const bool adjustWindowSize( const unsigned int p_console_buffer_width,
const unsigned int p_console_buffer_height )
{
/// Get the handle to the active window
HWND l_window_handle( GetConsoleWindow() );
if( l_window_handle == NULL )
{
std::cout << "GetConsoleWindow() failed\n";
return false;
}
/// Get the dimensions of the active window
RECT l_window_rect;
if( !GetWindowRect( l_window_handle, &l_window_rect ) )
{
std::cout << "GetWindowRect() failed\n";
return false;
}
/// Remove unwanted WindowStyle flags
LONG l_style( GetWindowLong( l_window_handle, GWL_STYLE ) );
l_style &= ~( WS_VSCROLL | WS_HSCROLL | WS_MAXIMIZEBOX | WS_MINIMIZEBOX |
WS_SIZEBOX );
SetWindowLong( l_window_handle, GWL_STYLE, l_style );
/// Set new window size to update the style flags
if( !SetWindowPos( l_window_handle, HWND_TOP, l_window_rect.left,
l_window_rect.top, l_window_rect.right -
l_window_rect.left, l_window_rect.bottom -
l_window_rect.top, SWP_HIDEWINDOW ) )
{
std::cout << "SetWindowPos() failed\n";
return false;
}
/// Get the dimensions of the client area within the window's borders
RECT l_client_rect;
if( !GetClientRect( l_window_handle, &l_client_rect ) )
{
std::cout << "GetClientRect() failed\n";
return false;
}
/// Get handle to console
HANDLE l_console_handle( GetStdHandle( STD_OUTPUT_HANDLE ) );
if( l_console_handle == nullptr )
{
std::cout << "GetStdHandle() failed\n";
return false;
}
/// Get font information
CONSOLE_FONT_INFO l_font_info;
if( !GetCurrentConsoleFont( l_console_handle, false, &l_font_info ) )
{
std::cout << "GetCurrentConsoleFont() failed\n";
return false;
}
/// Prepare desired client area size
unsigned int l_target_width( l_font_info.dwFontSize.X *
p_console_buffer_width );
unsigned int l_target_height( l_font_info.dwFontSize.Y *
p_console_buffer_height );
POINT l_top_left;
l_top_left.x = l_client_rect.left;
l_top_left.y = l_client_rect.top;
ClientToScreen( l_window_handle, &l_top_left );
POINT l_bottom_right;
l_bottom_right.x = l_client_rect.right;
l_bottom_right.y = l_client_rect.bottom;
ClientToScreen( l_window_handle, &l_bottom_right );
unsigned int l_diff_x = l_window_rect.right - l_bottom_right.x +
l_top_left.x - l_window_rect.left;
unsigned int l_diff_y = l_window_rect.bottom - l_bottom_right.y +
l_top_left.y - l_window_rect.top;
/// Adjust window to fit exactly it's borders + the new client size
l_window_rect.right = l_target_width + l_diff_x;
l_window_rect.bottom = l_target_height + l_diff_y;
/// Set new window size
if( !SetWindowPos( l_window_handle, HWND_TOP, l_window_rect.left,
l_window_rect.top, l_window_rect.right,
l_window_rect.bottom, SWP_SHOWWINDOW ) )
{
std::cout << "SetWindowPos() failed\n";
return false;
}
/// Set new console buffer size
if( !SetConsoleScreenBufferSize( l_console_handle,
COORD( { (SHORT)p_console_buffer_width,
(SHORT)p_console_buffer_height } ) ) )
{
std::cout << "SetConsoleScreenBufferSize() failed\n";
return false;
}
return true;
}
int main()
{
SetConsoleTitle( (LPCSTR)"Console Test" );
unsigned int l_buffer_x( 100 );
unsigned int l_buffer_y( 40 );
if( !adjustWindowSize( l_buffer_x, l_buffer_y ) )
{
std::cout << "adjustWindowSize() failed\n";
return 1;
}
for( unsigned int i( 0 ); i < l_buffer_x * l_buffer_y; ++i )
{
std::cout << i % 10;
}
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ),
COORD( { 0, 0 } ) );
return 0;
}
Picture of console with empty spaces where scroll bars were
As I understood your question, you want to create console window that has no scroll bars and the visible area is exactly the size of the output screen buffer? This is how you can do this:
#include <windows.h>
#include <iostream>
void SetConsoleWindow(HANDLE conout, SHORT cols, SHORT rows)
{
CONSOLE_SCREEN_BUFFER_INFOEX sbInfoEx;
sbInfoEx.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
GetConsoleScreenBufferInfoEx(conout, &sbInfoEx);
sbInfoEx.dwSize.X = cols;
sbInfoEx.dwSize.Y = rows;
sbInfoEx.srWindow = { 0, 0, cols, rows };
sbInfoEx.dwMaximumWindowSize = { cols, rows };
SetConsoleScreenBufferInfoEx(conout, &sbInfoEx);
DWORD mode;
GetConsoleMode(conout, &mode);
mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
SetConsoleMode(conout, mode);
SetConsoleTitle(L"Console Test");
}
int main()
{
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
SHORT cols = 100, rows = 20;
SetConsoleWindow(out, cols, rows);
for (int y = 0; y < rows; ++y)
{
for (int x = 0; x < cols; ++x)
std::cout << y %10;
if (y < rows - 1)
std::cout << std::endl;
}
SetConsoleCursorPosition(out, { 0,0 });
return 0;
}
This needs some explanation. CONSOLE_SCREEN_BUFFER_INFOEX structure seem to contain all the params needed to make this happen. If you check properties of your console window and compare them with struct members
you find that dwSize corresponds to Screen Buffer Size, srWindow.Right - srWindow.Left and srWindow.Bottom - srWindow.Top correspond to Window Size.
If dwMaximumWindowSize is not set, it defaults to the boundaries of the desktop and adds scroll bars if window is larger. Setting it as well fixes that.
Lastly, ENABLE_WRAP_AT_EOL_OUTPUT needs to be removed from console options to stop cursor jumping to the next line at the end of line, thus scrolling buffer with the last printed character. I have adjusted the print loop to account for that.

SystemParametersInfo() returns 0 randomly

I'm developing an application to randomly change the users wallpaper at a specific time interval. Everything works as expected, except for the occasional error of 0 set by SystemParametersInfo(), which results in the wallpaper being reset to a black screen.
The 0 error is supposed to denote the operation was successful, yet that's obviously not the case. This error does not occur every time a new background is set, but randomly. I've searched this website and many others for possible solutions.. to no avail.
void setBackground() {
dirSize = FindMaxFileNum(); //Reads num of .jpg's in the folder.
if(dirSize != -1)
{
srand( (unsigned int)time(NULL));
bgChoice = rand() % dirSize + 1;
//Ensures backgrounds don't repeat.
for(int i=0; i<=2; i++)
{
if(lastBackground[i] == bgChoice)
{ bgChoice = rand() % dirSize + 1; }
}
//Tracks the last background used.
lastBackground[bgCount] = bgChoice;
bgCount++;
//Resets the counter so we can track the last 3 bg's used.
if(bgCount == 2)
{ bgCount = 0; }
}
else
{
dwLastError = GetLastError();
ssLastError << "Error: " << dwLastError << ".";
MessageBox(NULL, ssLastError.str().c_str(), "Error!", MB_ICONEXCLAMATION | MB_OK);
ssLastError.str("");
}
ssFilePath.str(""); //Ensures the stringstream is clean.
ssFilePath << strLocalDirectory << bgChoice << ".jpg";
if( SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (PVOID)ssFilePath.str().c_str(),
SPIF_UPDATEINIFILE | SPIF_SENDCHANGE) != 0)
{
// Refresh the desktop - cleaning of PIDL is in the WM_DESTROY message.
SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&pidl);
SHChangeNotify(SHCNE_ASSOCCHANGED,SHCNF_IDLIST,pidl,0);
}
else
{
dwLastError = GetLastError();
ssLastError << "Error: " << dwLastError << ".";
MessageBox(NULL, ssLastError.str().c_str(), "Error!", MB_ICONEXCLAMATION | MB_OK);
ssLastError.str("");
}
}

Enable display programmatically

I am trying to enable a secondary monitor in C++. What I have seems to try and change the display settings but nothing really happens, can anyone tell me where I am going wrong?
std::wstring devName( L"Intel(R) HD Graphics Family" );
std::wstring dispName( L"\\\\.\\DISPLAY3" );
DISPLAY_DEVICE theDisplay;
theDisplay.cb = sizeof(theDisplay);
DWORD dev = 0;
while(EnumDisplayDevices(0, dev, &theDisplay, 0))
{
if (devName.compare(theDisplay.DeviceString) == 0 && dispName.compare(theDisplay.DeviceName) == 0)
{
// found display adapter we're looking for
if (theDisplay.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
{
// Display is part of desktop, turn al other monitors off
cout << "Display is part of desktop\n";
}
else
{
// Display is off, turn it on
DEVMODE dm;
memset(&dm,0,sizeof(DEVMODE));
dm.dmSize = sizeof (DEVMODE);
dm.dmFields = DM_POSITION;
dm.dmPosition.x = 3361;
dm.dmPosition.y = 0;
dm.dmPelsWidth = 1920;
dm.dmPelsHeight = 1080;
LONG ret = ChangeDisplaySettingsEx (theDisplay.DeviceName, &dm, NULL, CDS_UPDATEREGISTRY, NULL);
if (ret != DISP_CHANGE_SUCCESSFUL)
{
cout << "failed";
}
}
}
dev++;
}
system ("pause");
return 0;