SDL 2.0 Keyboard input issues - input

When I try to Poll a keydown event in SDL 2.0 and hold down a key, I get multiple keydown events, one after the other. When I try running the same program using SDL 1.2.15 (with minor changes as SDL 1.2.15 does not support SDL_Window), I do not have this issue. The keydown event only occurs once like it is supposed to. I even tried executing the program on a different computer to make sure that it was not a computer specific issue.
The relevant code is as follows:
#include <iostream>
#include <SDL.h>
using namespace std;
SDL_Event event;
SDL_Window* screen = NULL;
int main(int argc, char* args[])
{
if(SDL_Init(SDL_INIT_EVERYTHING) == -1)
{
cout << "ERROR INIT";
return 0;
}
screen = SDL_CreateWindow("My Game Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_OPENGL);
bool quit = false;
while(!quit)
{
while(SDL_PollEvent(&event))
{
if(event.type == SDL_KEYDOWN)
{
cout << "KEY PRESSED!" << endl;
}
}
}
return 0;
}

Ignore SDL_KEYDOWN events where event.key.repeat != 0.

Related

Point cloud library (PCL) C++ exception when tying to run

i am trying to use PCL with a V1 Microsoft Kinect camera to do 3D mapping. I have installed it and used Cmake to create the project using visual studio 2019 when i try to run the file "openni_grabber.cpp" i get the exception shown below and i cannot figure out what is causing it and how to fix it. I'm not very experience with PCL so any help would be very appreciated
I have tried searching and cannot find anyone else who has had this error or any info on how to fix it
The code im using is shown below
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/openni2_grabber.h>
#include <pcl/common/time.h>
class SimpleOpenNIProcessor
{
public:
void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr &cloud)
{
static unsigned count = 0;
static double last = pcl::getTime ();
if (++count == 30)
{
double now = pcl::getTime ();
std::cout << "distance of center pixel :" << cloud->points [(cloud->width >> 1) * (cloud->height + 1)].z << " mm. Average framerate: " << double(count)/double(now - last) << " Hz" << std::endl;
count = 0;
last = now;
}
}
void run ()
{
// create a new grabber for OpenNI devices
pcl::Grabber* interface = new pcl::io::OpenNI2Grabber();
// make callback function from member function
boost::function<void (const pcl::PointCloud<pcl::PointXYZRGBA>::ConstPtr&)> f =
boost::bind (&SimpleOpenNIProcessor::cloud_cb_, this, _1);
// connect callback function for desired signal. In this case its a point cloud with color values
boost::signals2::connection c = interface->registerCallback (f);
// start receiving point clouds
interface->start ();
// wait until user quits program with Ctrl-C, but no busy-waiting -> sleep (1);
while (true)
boost::this_thread::sleep (boost::posix_time::seconds (1));
// stop the grabber
interface->stop ();
}
};
int main ()
{
SimpleOpenNIProcessor v;
v.run ();
return (0);
}
The details of the exception are
"Unhandled exception at 0x00007FFBEB9206BC in openni_grabber.exe: Microsoft C++ exception: pcl::IOException at memory location 0x00000043E9EFF378."

How to co_await for a change in a variable using boost coroutine ts?

Context
I build a webserver using boost coroutine ts, boost asio and boost beast.
There is a coroutine for reading and one for writing.
There is a message_to_send queue where messages get pushed to send to the user.
The writing coroutine checks if there is something in the message_to_send queue and sends it.
After sending the writing coroutine suspends itself for 100 milliseconds and checks again for something to write.
Problem
The writing coroutine is polling the message queue every 100 milliseconds. I like to find a solution without polling after some timer has fired.
Posible solution
Maybe ther is a solution to co_await the change of a variable. Maybe creating a async_wait_for_callback with "async_initiate"?
Code example
You can clone the project. Or use the complete example code posted here:
#include <algorithm>
#include <boost/asio.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/system_timer.hpp>
#include <boost/beast.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/bind/bind.hpp>
#include <boost/optional.hpp>
#include <chrono>
#include <cstddef>
#include <deque>
#include <exception>
#include <iostream>
#include <list>
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
// TODO use cmake to find out if the compiler is gcc or clang
#include <coroutine> // enable if build with gcc
// #include <experimental/coroutine> //enable if build with clang
using namespace boost::beast;
using namespace boost::asio;
typedef boost::asio::use_awaitable_t<>::as_default_on_t<boost::asio::basic_waitable_timer<boost::asio::chrono::system_clock>> CoroTimer;
typedef boost::beast::websocket::stream<boost::beast::tcp_stream> Websocket;
using namespace boost::beast;
using namespace boost::asio;
using boost::asio::ip::tcp;
using tcp_acceptor = use_awaitable_t<>::as_default_on_t<tcp::acceptor>;
struct User
{
boost::asio::awaitable<void> writeToClient (std::weak_ptr<Websocket> &connection);
std::deque<std::string> msgQueue{};
std::shared_ptr<CoroTimer> timer{};
};
void
handleMessage (std::string const &msg, std::list<std::shared_ptr<User>> &users, std::shared_ptr<User> user)
{
std::cout << "please implement handle message" << std::endl;
user->msgQueue.push_back ("please implement handle message");
user->timer->cancel ();
}
boost::asio::awaitable<void>
User::writeToClient (std::weak_ptr<Websocket> &connection)
{
try
{
while (not connection.expired ())
{
timer = std::make_shared<CoroTimer> (CoroTimer{ co_await this_coro::executor });
timer->expires_after (std::chrono::system_clock::time_point::max () - std::chrono::system_clock::now ());
try
{
co_await timer->async_wait ();
}
catch (boost::system::system_error &e)
{
using namespace boost::system::errc;
if (operation_canceled == e.code ())
{
// swallow cancel
}
else
{
std::cout << "error in timer boost::system::errc: " << e.code () << std::endl;
abort ();
}
}
while (not msgQueue.empty () && not connection.expired ())
{
auto tmpMsg = std::move (msgQueue.front ());
std::cout << " msg: " << tmpMsg << std::endl;
msgQueue.pop_front ();
co_await connection.lock ()->async_write (buffer (tmpMsg), use_awaitable);
}
}
}
catch (std::exception &e)
{
std::cout << "write Exception: " << e.what () << std::endl;
}
}
class Server
{
public:
Server (boost::asio::ip::tcp::endpoint const &endpoint);
boost::asio::awaitable<void> listener ();
private:
void removeUser (std::list<std::shared_ptr<User>>::iterator user);
boost::asio::awaitable<std::string> my_read (Websocket &ws_);
boost::asio::awaitable<void> readFromClient (std::list<std::shared_ptr<User>>::iterator user, Websocket &connection);
boost::asio::ip::tcp::endpoint _endpoint{};
std::list<std::shared_ptr<User>> users{};
};
namespace this_coro = boost::asio::this_coro;
Server::Server (boost::asio::ip::tcp::endpoint const &endpoint) : _endpoint{ endpoint } {}
awaitable<std::string>
Server::my_read (Websocket &ws_)
{
std::cout << "read" << std::endl;
flat_buffer buffer;
co_await ws_.async_read (buffer, use_awaitable);
auto msg = buffers_to_string (buffer.data ());
std::cout << "number of letters '" << msg.size () << "' msg: '" << msg << "'" << std::endl;
co_return msg;
}
awaitable<void>
Server::readFromClient (std::list<std::shared_ptr<User>>::iterator user, Websocket &connection)
{
try
{
for (;;)
{
auto readResult = co_await my_read (connection);
handleMessage (readResult, users, *user);
}
}
catch (std::exception &e)
{
removeUser (user);
std::cout << "read Exception: " << e.what () << std::endl;
}
}
void
Server::removeUser (std::list<std::shared_ptr<User>>::iterator user)
{
users.erase (user);
}
awaitable<void>
Server::listener ()
{
auto executor = co_await this_coro::executor;
tcp_acceptor acceptor (executor, _endpoint);
for (;;)
{
try
{
auto socket = co_await acceptor.async_accept ();
auto connection = std::make_shared<Websocket> (std::move (socket));
users.emplace_back (std::make_shared<User> ());
std::list<std::shared_ptr<User>>::iterator user = std::next (users.end (), -1);
connection->set_option (websocket::stream_base::timeout::suggested (role_type::server));
connection->set_option (websocket::stream_base::decorator ([] (websocket::response_type &res) { res.set (http::field::server, std::string (BOOST_BEAST_VERSION_STRING) + " websocket-server-async"); }));
co_await connection->async_accept (use_awaitable);
co_spawn (
executor, [connection, this, &user] () mutable { return readFromClient (user, *connection); }, detached);
co_spawn (
executor, [connectionWeakPointer = std::weak_ptr<Websocket>{ connection }, &user] () mutable { return user->get ()->writeToClient (connectionWeakPointer); }, detached);
}
catch (std::exception &e)
{
std::cout << "Server::listener () connect Exception : " << e.what () << std::endl;
}
}
}
auto const DEFAULT_PORT = u_int16_t{ 55555 };
int
main ()
{
try
{
using namespace boost::asio;
io_context io_context (1);
signal_set signals (io_context, SIGINT, SIGTERM);
signals.async_wait ([&] (auto, auto) { io_context.stop (); });
auto server = Server{ { ip::tcp::v4 (), DEFAULT_PORT } };
co_spawn (
io_context, [&server] { return server.listener (); }, detached);
io_context.run ();
}
catch (std::exception &e)
{
std::printf ("Exception: %s\n", e.what ());
}
return 0;
}
EDIT: updated code based on sehe's idea which is marked as answer.
The classical threading solution would be a condition variable. Of course, that's not what you want - I see you even explicitly disabled ASIO threading. Good.
One way - short of providing an Asio service to implement this behaviour - would be to use timers to emulate condition variables. You could use timer that "never" expires (deadline is at timepoint::max()) and manually reset it to timepoint::min() (canceling any async_wait) or any time in the past to signify the condition. Then you can use Timer::async_wait with use_awaitable like you already know how.
Note that you still need to "manually" signal the change. This is what you want because anything else requires kernel process tracing support/hardware debugger facilities which require massive priviliges and tend to be very slow.
You might want to know about associating the use_awaitable as the default completion token for the executor bound to your timer. See e.g. the examples: https://www.boost.org/doc/libs/1_78_0/doc/html/boost_asio/example/cpp17/coroutines_ts/echo_server_with_default.cpp (the HTML docs do NOT link these examples)

create Wayland desktop environment that simply binds keyboard shortcuts

There are dozens of questions on here asking how to create global keyboard bindings in a Wayland environment. Generally, the answer is "use your desktop environment" - an answer that is pretty much useless to most anyone asking the question.
So, in order to draw out a more useful answer, I ask how does one create a minimal Wayland desktop environment which can bind shortcut keys?
I've got Mutter running as my WM, and I'm using GNOME Do as a launcher. It's pretty much exactly the desktop environment I want, with the exception that I can't bind hotkeys.
I don't care if I have to write a 10k line C app to make this work. I just want to know how to proceed. How does GNOME bind keyboard shortcuts within Wayland? Where is the code for that? Where is the appropriate documentation for Wayland/Mutter?
After much research and experimentation, it looks like libevdev is maybe the right tool. I developed the program below as a proof-of-concept to bind Alt+X to launch xterm.
Unfortunately, it has to be run as root, so I'm thinking I need to somehow tie this into the local desktop session. For my purposes, it's probably good enough to just setuid using the root user and call it a day.
I'm also not convinced my keyboard detection heuristic is very good. I'm essentially looking for any device that has keys and a repeat rate, which on my system only matches my keyboard.
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <libevdev/libevdev.h>
#define DEVROOT "/dev/input/"
#define DEVROOT_LEN 12
#define PATH_LEN (DEVROOT_LEN + NAME_MAX)
int outerr(int, const char*);
struct libevdev* open_device(int);
bool kblike(struct libevdev*);
int main(int argc, char* argv[]) {
DIR* dir;
struct dirent* entry;
char path[PATH_LEN];
int fd, err;
struct libevdev* dev = NULL;
struct input_event ev;
bool key, rep, alt;
if (!(dir = opendir("/dev/input"))) {
return outerr(errno, "cannot enumerate devices");
}
// look for keyboard device
while (entry = readdir(dir)) {
if (DT_CHR == entry->d_type) {
sprintf(path, "/dev/input/%s", entry->d_name);
if (-1 == (fd = open(path, O_RDONLY|O_NONBLOCK))) {
return outerr(errno, "cannot read device");
}
if (dev = open_device(fd)) {
if (kblike(dev)) break;
libevdev_free(dev);
dev = NULL;
}
}
}
closedir(dir);
// check if keyboard was found
if (dev == NULL) {
return outerr(ENODEV, "could not detect keyboard");
} else do {
err = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
if (err == 0 && ev.type == EV_KEY) switch (ev.code) {
case KEY_LEFTALT:
alt = ev.value == 1;
break;
case KEY_X:
if (ev.value == 1 && alt) system("xterm");
break;
}
} while (err == 1 || err == 0 || err == -EAGAIN);
return 0;
}
int outerr(int errnum, const char* msg) {
fprintf(stderr, "%s (%s)\n", msg, strerror(errnum));
return errnum;
}
bool kblike(struct libevdev* dev) {
return libevdev_has_event_type(dev, EV_KEY)
&& libevdev_has_event_type(dev, EV_REP);
}
struct libevdev* open_device(int fd) {
struct libevdev* dev = libevdev_new();
int err;
if (dev == NULL) {
errno = ENOMEM;
} else if (0 > (err = libevdev_set_fd(dev, fd))) {
libevdev_free(dev);
dev = NULL;
errno = -err;
}
return dev;
}

Using Point Cloud Library to store Point Clouds from Kinect

Using Point Cloud Library on Ubuntu, I am trying to take multiple point clouds from the Kinect and store them in memory for later use in the program. My code shown at the bottom of this post is designed to store the first Point Cloud from the Kinect and output its width and height. The program gives me a runtime error:
/usr/include/boost/smart_ptr/shared_ptr.hpp:418: T* boost::shared_ptr<T>::operator->() const [with T = pcl::PointCloud<pcl::PointXYZ>]: Assertion `px != 0' failed.
All help is greatly appreciated and I always accept an answer!
The code:
#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
class SimpleOpenNIViewer
{
public:
SimpleOpenNIViewer () : viewer ("PCL OpenNI Viewer") {}
pcl::PointCloud<pcl::PointXYZ>::Ptr prevCloud;
void cloud_cb_ (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr &cloud)
{
if (!viewer.wasStopped())
viewer.showCloud (cloud);
//ICP start
if(!prevCloud) {
pcl::PointCloud<pcl::PointXYZ>::Ptr prevCloud( new pcl::PointCloud<pcl::PointXYZ>());
pcl::copyPointCloud<pcl::PointXYZ, pcl::PointXYZ>(*cloud, *prevCloud);
}
cout << prevCloud->width << " by " << prevCloud->height << endl;
}
void run ()
{
pcl::Grabber* interface = new pcl::OpenNIGrabber();
boost::function<void (const pcl::PointCloud<pcl::PointXYZ>::ConstPtr&)> f =
boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);
interface->registerCallback (f);
interface->start ();
while (!viewer.wasStopped())
{
boost::this_thread::sleep (boost::posix_time::seconds (1));
}
interface->stop ();
}
pcl::visualization::CloudViewer viewer;
};
int main ()
{
SimpleOpenNIViewer v;
v.run ();
return 0;
}
Try this, I don't have the Kinect drivers installed so I can't test. Basically in my version prevCloud is instantiated in the constructor so (!prevCloud) will always equal 'false'. Which is to say prevCloud.get() != NULL.
#include <pcl/io/openni_grabber.h>
#include <pcl/visualization/cloud_viewer.h>
class SimpleOpenNIViewer
{
typedef pcl::PointXYZ Point;
typedef pcl::PointCloud<Point> PointCloud;
public:
SimpleOpenNIViewer () : viewer ("PCL OpenNI Viewer") {
prevCloud = PointCloud::Ptr(NULL);
}
void cloud_cb_ (const PointCloud::ConstPtr &cloud)
{
if (!viewer.wasStopped())
viewer.showCloud (cloud);
if (!prevCloud) // init previous cloud if first frame
prevCloud = PointCloud::Ptr(new PointCloud);
else. // else RunICP between cloud and prevCloud
//RunICP(cloud,prevCloud);
//Copy new frame in to prevCloud
pcl::copyPointCloud<Point, Point>(*cloud, *prevCloud);
cout << prevCloud->width << " by " << prevCloud->height << endl;
}
void run ()
{
pcl::Grabber* interface = new pcl::OpenNIGrabber();
boost::function<void (const PointCloud::ConstPtr&)> f =
boost::bind (&SimpleOpenNIViewer::cloud_cb_, this, _1);
interface->registerCallback (f);
interface->start ();
while (!viewer.wasStopped())
{
boost::this_thread::sleep (boost::posix_time::seconds (1));
}
interface->stop ();
}
PointCloud::Ptr prevCloud;
pcl::visualization::CloudViewer viewer;
};
int main ()
{
SimpleOpenNIViewer v;
v.run ();
return 0;
}
You're creating a new local variable prevCloud and copying cloud into it, rather than copying into the prevCloud field. So, if the field's value was null before the if {}, it is still null after the if {} and so it throws an error when you try to dereference it.
May be this code can help you, the cloud is saved in a "pcd" file, take a look here
And other option is work with the "Kinfu" project from PCL

Controlling the volume of other applications

I am trying to make an app that controls the volume of another process using the Windows 7 Audio API.
What I'm looking for is the ISimpleAudioVolume for the session used by the other process.
I have tried using the IAudioSessionEnumerator but it will only give me the IAudioSessionControl2 of the session. Using the IAudioSessionControl I have managed to receive notifications when I change the volume through sndvol but not change it myself.
I have also tried using GetSimpleAudioVolume() from IAudioSessionManager but it will only give me sessions within the current process.
How do you do it? It should be possible since sndvol is doing this.
Here is an example of muting another process using Core Audio API.
#include <windows.h>
#include <iostream>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <Audiopolicy.h>
#include <comdef.h>
#include <comip.h>
#define CHECK_HR(hr) \
if(FAILED(hr)) { \
std::cout << "error" << std::endl; \
return 0; \
}
_COM_SMARTPTR_TYPEDEF(IMMDevice, __uuidof(IMMDevice));
_COM_SMARTPTR_TYPEDEF(IMMDeviceEnumerator, __uuidof(IMMDeviceEnumerator));
_COM_SMARTPTR_TYPEDEF(IAudioSessionManager2, __uuidof(IAudioSessionManager2));
_COM_SMARTPTR_TYPEDEF(IAudioSessionManager2, __uuidof(IAudioSessionManager2));
_COM_SMARTPTR_TYPEDEF(IAudioSessionEnumerator, __uuidof(IAudioSessionEnumerator));
_COM_SMARTPTR_TYPEDEF(IAudioSessionControl2, __uuidof(IAudioSessionControl2));
_COM_SMARTPTR_TYPEDEF(IAudioSessionControl, __uuidof(IAudioSessionControl));
_COM_SMARTPTR_TYPEDEF(ISimpleAudioVolume, __uuidof(ISimpleAudioVolume));
IAudioSessionManager2Ptr CreateSessionManager()
{
HRESULT hr = S_OK;
IMMDevicePtr pDevice;
IMMDeviceEnumeratorPtr pEnumerator;
IAudioSessionManager2Ptr pSessionManager;
// Create the device enumerator.
CHECK_HR(hr = CoCreateInstance(
__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_ALL,
__uuidof(IMMDeviceEnumerator),
(void**)&pEnumerator));
// Get the default audio device.
CHECK_HR(hr = pEnumerator->GetDefaultAudioEndpoint(
eRender, eConsole, &pDevice));
// Get the session manager.
CHECK_HR(hr = pDevice->Activate(
__uuidof(IAudioSessionManager2), CLSCTX_ALL,
NULL, (void**)&pSessionManager));
return pSessionManager;
}
bool MuteProcess(DWORD processId) {
IAudioSessionManager2Ptr mgr = CreateSessionManager();
if (!mgr) {
return false;
}
IAudioSessionEnumeratorPtr enumerator;
if (SUCCEEDED(mgr->GetSessionEnumerator(&enumerator))) {
int sessionCount;
if (SUCCEEDED(enumerator->GetCount(&sessionCount))) {
for (int i = 0; i < sessionCount; i++) {
IAudioSessionControlPtr control;
if (SUCCEEDED(enumerator->GetSession(i, &control))) {
IAudioSessionControl2Ptr control2;
if (SUCCEEDED(control->QueryInterface(__uuidof(IAudioSessionControl2), (void**)&control2))) {
DWORD foundProcessId;
if (SUCCEEDED(control2->GetProcessId(&foundProcessId))) {
if (foundProcessId == processId) {
ISimpleAudioVolumePtr volume;
if (SUCCEEDED(control2->QueryInterface(_uuidof(ISimpleAudioVolume), (void**)&volume))) {
if (SUCCEEDED(volume->SetMute(TRUE, 0))) {
return true;
}
}
}
}
}
}
}
}
}
return false;
}
int _tmain(int argc, _TCHAR* argv[]){
CoInitialize(NULL);
DWORD processId = 11944;
MuteProcess(processId);
return 0;
}
There is an MSDN forum question and Blog Post about this very question. Hope this helps.
According to Larry Osterman
"There is no publicly documented mechanism for doing what you're trying to do."