Detect mouse click anywhere on screen using Gtk3 - c++

I am trying to make a program that follows the mouse position and checks whether the mouse button has been pressed anywhere on the screen by only using gtk. Right now i can get the position of the mouse, however i am unable to do the latter. i did some research but i couldnt find any really good example that only used gtk to do this.
Initially i tried something similar in the code of screenshot-area-selection.c from the gnome-screenshot app which do click and drag area select, and based on my understanding there was a part of the code which took the member variable of the GdkEventButton "button" to see whether there was a button click or not, however this i couldnt get it to work
/*void check_button(GdkEventButton *event, GdkWindow *root_window, GdkDevice *prim_device){
event->device = prim_device;
event->window = root_window;
switch(event->button){
case 1:
printf("button clicked: left mouse\n");
sleep(2);
break;
case 2:
printf("button clicked: middle mouse\n");
sleep(2);
break;
case 3:
printf("button clicked: right mouse\n");
sleep(2);
break;
}
}*/
so i tried using the functions available in the gtk documents but it still doesn't display whether there was a button press or not. i just started using gtk pls helpp iam going crazy.
#include <gtk/gtk.h>
#include <stdlib.h>
//#include <unistd.h>
void check_button(GdkWindow* root_window, GdkDevice* prim_device){
switch(gdk_window_get_device_events(root_window, prim_device)){
case GDK_BUTTON_PRESS_MASK:
printf("button pressed: pressed\n");
sleep(3);
break;
case GDK_BUTTON_RELEASE_MASK:
printf("button released: released\n");
sleep(3);
break;
}
}
int main (int argc, char **argv){
gdk_init(&argc, &argv);
//GdkEventButton *event;
GdkWindow *window = gdk_get_default_root_window ();
GdkDisplay* display = gdk_display_get_default();
GdkSeat* seat = gdk_display_get_default_seat(display);
GdkDevice* device = gdk_seat_get_pointer(seat);
int x, y;
while(TRUE){
//check_button(event, window, device);
check_button(window, device);
int a, b;
a = x;
b = y;
gdk_window_get_device_position (window, device, &x, &y, NULL);
if(a != x | b != y){
system("clear");
printf("x= %d, y= %d\n",x,y);
}
}
}

Related

Issue with printing sub-menu in ncurses with c++

I'm trying to print a sub-menu associated with a main menu shown with ncurses.
This is the way i've organized it :
do{} while (); loop with wgetch gets keypad input from user
if user presses the enter key, the subMenu entry is shown after clearing the whole screen.
Unfortunately, I can't make it past the 2nd step, the sub-menu never shows up on screen.
#include <ncurses.h>
#include <iostream>
#include <string>
int main()
{
std::string nameMainMenuExample = "/parent1/folder";
std::string nameSubMenuExample = "/folder/file";
// initialize ncurses
WINDOW *win;
win = initscr();
raw();
curs_set(0);
cbreak();
box(win, 0, 0);
refresh();
wrefresh(win);
keypad(win, true);
// end initialize ncurses
int highlight = 0;
int choice;
// PRESS 'a' to ESCAPE LOOP
do {
mvwprintw(win, 1, 1, nameMainMenuExample.c_str());
switch (choice) {
case KEY_UP:
--highlight;
if (highlight == -1) {
highlight = 0;
}
break;
case KEY_DOWN:
++highlight;
if (highlight == 1) {
highlight = 0;
}
break;
case KEY_ENTER: // Enter key pressed
clear();
mvwprintw(win, 1, 1, nameSubMenuExample.c_str());
refresh();
break;
default:
break;
}
} while ((choice = wgetch(win)) != 97); // random choice a == 97
endwin();
return 0;
}
I just expect the sub menu to be printed on screen after ncurses clears the screen of the main menu.
Thanks
If you wanted to activate the submenu on the enter key, you should be checking the value wgetch returned against KEY_ENTER (which is something like 16777221 numerically), not 10.
You're mixing calls to different windows (clear and refresh use stdscr) and the one your wgetch call uses is getting its own wrefresh. Since the menu-window is not being refreshed, it never appears, and since wgetch does a wrefresh, that may additionally obscure things.
Start by making the wrefresh calls apply to the windows you want to be repainted.
Using ncurses in C++, ENTER key value is just '\n'
For example:
case '\n':
clear();
mvwprintw(win, 1, 1, nameSubMenuExample.c_str());
refresh();
break;

SDL_MOUSEBUTTONUP occurring even before releasing mouse button?

I'm trying to make a video player using SDL and ffmpeg in C++. I've created two separate threads, one that renders the video on the SDL window and one that handles window events. When the user clicks and releases on the video I want it to toggle playback/pause. However, it fires multiple times and the event occurs even before I release the mouse which results in unpredictable behavior.
My code:
SDL_Event event;
while (1)
{
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
SDL_DestroyWindow(screen);
SDL_Quit();
break;
case SDL_MOUSEBUTTONUP:
if (event.button.state == SDL_RELEASED)
{
printf("Mouse released\n");
}
break;
}
}
When I click the window and hold down I would expect it wouldn't print Mouse released until I release the button. However, it prints Mouse released the entire time I hold down the mouse button. I don't know if maybe this has to do with me using a touchpad on my laptop.
SDL_PollEvent has a return value, you are ignoring.
[It] returns 1 if there are any pending events, or 0 if there are none available.
Given your code logic, whenever there is no pending event, you keep handling the previous event over and over again, until a new event arrives. This leads to the observed behavior.
The easiest fix would be to wrap the entire event handling inside an if (SDL_PollEvent(&event)) { /* Event handling */ } conditional.
EDIT: My answer is wrong, check IInspectable's answer.
Your error is that you're not checking all the pending events given by pollEvent, just one. Try this code and tell me how many button ups you get.
#include <SDL2/SDL.h>
#include <iostream>
int main(int argc, char *argv[]) {
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
throw std::runtime_error("SDL failed to initialize.\n");
}
SDL_Window *window = SDL_CreateWindow("App", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 640, 480, NULL);
bool done = false;
while(!done) {
SDL_Event event;
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
done = true;
}
if (event.type == SDL_MOUSEBUTTONUP) {
if (event.button.state == SDL_RELEASED) {
printf("Mouse released\n");
}
}
}
}
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

SDL2 and measuring the time a key is pressed

I have written the follow (typical) code snippet for handling key events in SDL2:
#include <SDL.h>
#include <iostream>
using std::cout;
using std::endl;
// Custom key types
typedef enum Keys {
Back,
Reset
} KeyType;
// Structure that holds the type and pressed state of custom keys
typedef struct Button {
KeyType type;
bool pressed;
} Button;
int main(int argc, char ** argv)
{
// Variables
bool quit = false;
SDL_Event event;
Button buttons[] = {
{Back, false},
{Reset, false}
};
// Initialize SDL sub-systems, window, renderer and texture
SDL_Init(SDL_INIT_VIDEO);
SDL_Window * window = SDL_CreateWindow("SDL2 Keyboard/Mouse events",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 640, 0);
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
// Loop while quit not disabled
while (!quit)
{
// Pool events
while(SDL_PollEvent(&event))
{
// Filter events
switch (event.type)
{
case SDL_QUIT: // Window closed
quit = true;
break;
case SDL_KEYDOWN: // Key pressed
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
quit = true;
break;
case SDLK_LEFT:
buttons[Back].pressed = true; // Toggle Back button to pressed
cout << "Back held" << endl;
// TODO Measure elapsed time and artificially toggle the pressed state to false if > 5s
break;
case SDLK_DOWN:
buttons[Reset].pressed = true; // Toggle Reset button to pressed
break;
}
break;
case SDL_KEYUP: // Key released
switch (event.key.keysym.sym)
{
case SDLK_LEFT:
if (buttons[Back].pressed) {
// TODO Measure elapsed time and print "Back emitted" if less than 5s
buttons[Back].pressed = false; // Toggle Back button to unpressed and emit Back event
}
break;
case SDLK_DOWN:
buttons[Reset].pressed = false; // Toggle Reset button to unpressed
cout << "Reset emitted" << endl;
break;
}
break;
case SDL_USEREVENT:
break;
}
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
}
// Cleanup resources
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
// Stop all SDL sub-systems
SDL_Quit();
return 0;
}
I'm trying to figure out a way to measure the time between the moment when buttons[Back].pressed is set to true (even when holding the key down only the exact begin of the "holding" is what I'm interested in) and then to false. The "key released" part is easy since this a single event anyway.
I want to distinguish between a short (single "key pressed" event received or holding the key for less than let's say 5s) and long (more than 5s holding the key down) strokes which is basically mapping two actions to the same key based on the time a key is held by the user.
I can't figure out how to do that. Any ideas? I need to handle the time event in two location (imho):
Given key is released - if elapsed time is less/equal to 5s detect a short key stroke else long key stroke
While given key is in being pressed - if the timeout kicks in, the pressed state needs to be artificially toggled to false in order to prevent a short key stroke to be detected when the user actually releases the key. In this case a long key stroke is detected
I expanded upon #keltar 's suggestion and it works although not that precise (but in my case it's not required.
I added elapsedTime in the Button struct to hold the time information and initialized it to 0:
typedef struct Button {
KeyType type;
bool pressed;
uint32_t elapsedTime;
} Button;
Whenever the given key is pressed down I check if the elapsedTime == 0 and if so I call SDL_GetTicks(). Upon releasing the key I get the currentTime which is just another call of SDL_GetTicks() at that point in time. I calculate the difference between elapsedTime and currenTime and check if a specific time interval has elapsed and then make a decision what function is called.
This solution can be expanded by making the calculation above during every loop iteration and making the exact same check. This makes it possible to check the elapsed time not only upon releasing the given key and it is a more accurate answer to my initial question. However the first solution (without the extra check) works fine. I just had to adapt my scenario a little bit.

SDL_PollEvent() skips events

Very Simple program, for drawing on screen (like with pen in Paint)
I'm using SDL 1.2. Only events I'm proccesing are mouse motion, mouse left click and quiting program. My problem is that SDL_MOUSEMOTION events are 'skipped' when I'm moving mouse fast (when I say fast I mean faster than 1 pixel/second)
Why this happens?
screen shots:
http://postimg.org/image/gcb87v9zr/
http://postimg.org/image/i5e4w6v6f/
#include <SDL/SDL.h>
SDL_Event event;
SDL_Surface* screen;
bool clicked = false;
Uint32 whiteColor;
int W = 200; // screen width
int H = 200; // screen height
Uint32* screenPixels;
bool handleInput();
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(W,H,32,SDL_SWSURFACE);
whiteColor = SDL_MapRGB(screen->format,255,255,255);
screenPixels = (Uint32*) screen->pixels;
while(handleInput())
{
}
SDL_Quit();
return 0;
}
bool handleInput()
{
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:{
return false;
break;
}
case SDL_MOUSEBUTTONDOWN:{
clicked = true;
break;
}
case SDL_MOUSEBUTTONUP:{
clicked = false;
break;
}
case SDL_MOUSEMOTION:{
if(clicked)
{
int P_x = event.motion.x;
int P_y = event.motion.y;
screenPixels[P_y * W + P_x] = whiteColor;
SDL_Flip(screen);
}
break;
}
}
}
return true;
}
It is because you SDL_Flip for all your screen, it takes too many time.
Better call SDL_Flip in another thread (using std::async, for example).
Or you may update not the all surface, but only the part which is changed color to white.

C++ Ncurses on Mac - Nothing displaying in Terminal

I'm trying to run this code through Eclipse. It has no errors when compiling and opens up Terminal (as I set it to) when it runs, but nothing shows up in the Terminal even though (supposedly) I have coded it to display a box. Could anyone let me know what I need to do so that it displays properly?
Thanks
#include <iostream>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
void set_difficulty(int level,int &v);
void SetMenuBox(WINDOW*&);
int main(){
int speed = 0;
chtype a=219;
initscr(); //initialize screen
WINDOW *win = newwin(20,40,15,20); //create new window (row,col,x,y) where (x,y) is top left corner
wrefresh(stdscr); //refresh standard screen
start_color(); //enable color changes
init_pair(1,COLOR_RED,COLOR_BLACK); //create color pair of red text with black outline
init_pair(2,COLOR_GREEN,COLOR_BLACK);
attron(COLOR_PAIR(1)); //use the color pair
wattron(win,COLOR_PAIR(1));
wrefresh(win);
wborder(stdscr,0,0,0,0,0,0,0,0); //create border around win using lines
wborder(win,a,a,a,a,a,a,a,a); //create border around standard window
wrefresh(stdscr);
wrefresh(win);
wmove(win,2,18); //move cursor
wprintw(win,"MENU"); //print "MENU" at cursor
wmove(win,5,2);
wprintw(win,"Select Difficulty:");
wmove(win,7,2);
wprintw(win,"1==Easy");
wmove(win,9,2);
wprintw(win,"2==Medium");
wmove(win,11,2);
wprintw(win,"3==Hard");
wmove(win,13,2);
wprintw(win,"0==EXIT");
wmove(win,18,19);
wrefresh(win); //the character typed will be green not blue
int d=wgetch(win); //get character from win, d is the ascii number
sleep(500); //pause for 1000 ms
wmove(win,28,25);
while(d<48||d>51){ //keeps getting character until an allowable
wborder(win,32,32,32,32,32,32,32,32); //character is selected
mvwdelch(win,18,19);
wborder(win,a,a,a,a,a,a,a,a);
wmove(win,18,19);
wrefresh(win);
d = wgetch(win);
sleep(500);
}
if(d==48)
return 0;
else if(d>48&&d<=51){
set_difficulty(d,speed);
}
wrefresh(win);
sleep(1000);
wclear(win);
SetMenuBox(win);
wrefresh(win);
wmove(win,15,18);
wprintw(win,"%d",speed);
wrefresh(win);
sleep(1000);
//endwin(); //close window
return 0;
}
void set_difficulty(int level,int &v){
switch (level){
case 49:
v = 2500;
break;
case 50:
v = 1750;
break;
case 51:
v = 1250;
break;
}
}
void SetMenuBox(WINDOW *&w){
chtype a = 219;
delwin(w);
wrefresh(stdscr);
w = newwin(30,40,15,20);
wrefresh(stdscr);
wrefresh(w);
init_pair(1,COLOR_RED,COLOR_BLACK); //create color pair of red text with blue outline
attron(COLOR_PAIR(1)); //use the color pair
wattron(w,COLOR_PAIR(1));
wrefresh(w);
wborder(w,a,a,a,a,a,a,a,a);
wrefresh(w);
}