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;
Related
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);
}
}
}
I have a custom class, CustomButton that extends Fl_Button. On my screen there are a bunch of Fl_Input and CustomButton widgets that I want to be able to navigate between using a tab keypress. Tabbing between input fields works fine, but once a CustomButton gets focus, I can't seem to tab away from it.
Here's my handle function
int CustomButton::handle ( int event )
{
int is_event_handled = 0;
switch (event)
{
case FL_KEYBOARD:
// If the keypress was enter, toggle the button on/off
if (Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter)
{
// Do stuff...
}
is_event_handled = 1;
break;
case FL_FOCUS:
case FL_UNFOCUS:
// The default Fl_Button handling does not allow Focus/Unfocus
// for the button so mark the even as handled to skip the Fl_Button processing
is_event_handled = 1;
break;
default:
is_event_handled = 0;
break;
}
if ( is_event_handled == 1 ) return 1;
return Fl_Round_Button::handle ( event );
}
I am using fltk 1.1.10.
For a very simple, minimal example which demonstrates how to control the focus, please check the navigation.cxx test file.
Maybe your widget did get the focus (check this with Fl::focus()), but it does not show that up (you need to handle the FL_FOCUS and/or FL_UNFOCUS events)?
My problem was my CustomButton::handle() returning 1 after a FL_KEYBOARD event without actually using the tab key press.
Moving is_event_handled = 1 into the if statement lets me consume the FL_Enter keypress only and lets other widgets (i.e. the Fl_Group that controls navigation) take any other keypresses.
Alternatively get rid of the if and replace with something like
switch(Fl::event_key())
{
case FL_Enter:
case FL_KP_Enter:
// Do stuff
is_event_handled = 1;
break;
default:
is_event_handled = 0;
break;
}
I have a TListView (it is focused all the time) and an OnKeyDown event handler on my Form (its KeyPreview property is true).
playlist is my TListView component (Style = vsReport).
void __fastcall Tmform::mformKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
if(Shift.Contains(ssCtrl)) // hotkeys with CTRL
{
switch(Key)
{
case vkF: findDoublesbtnClick(mform); break; // [FIND TWINS]
case vkD: dbsClick(mform); break; // [DELETE BAD SONGS]
case vkA: playlist->SelectAll(); break; // [CTRL + A]
case vkS: settingsClick(mform); break; // [SETTINGS]
}
}
else // just keys
{
switch(Key)
{
case vkReturn: if(playlist->SelCount) pl.refreshSong(); break; // [ENTER]
case vkDelete: af.deleteFiles(); break; // [DELETE]
case vkSpace:
case vkNumpad3: pl.playPauseResume(); break;
case vkSubtract: prevbtnClick(mform); break; // [PREVIOUS]
case vkAdd: nextbtnClick(mform); break; // [NEXT]
case vkC: counterClick(mform); break; // [LISTENINGS WIN]
}
}
Why does it beep when I press any key (with the TListView focused)?
So, I found out, why it beeps. It seems to be standard behavior of TListView component. When one item in TListView is selected (and TListView has focus), any character input triggers "select the typed item" method, that trying to find and select item by our input. That was the answer I was interested about. To make work hot keys (including one-key) I used next code:
void __fastcall TForm1::ListViewKeyPress(TObject *Sender, System::WideChar &Key)
{ Key = 0; } // here TListView calls "find" method. I reset Key value,
// thus I have only vkCode for FormKeyDown which triggers
// after FormKeyPress
void __fastcall TForm1::FormKeyDown(TObject *Sender, WORD &Key, TShiftState Shift)
{
if (Shift.Contains(ssAlt) && Key == vkF) // use any key or shortcut
{ Form1->Color = RGB(random(255), 0, 0); return; } // you wish
if (Key == vkF)
Form1->Color = RGB(0, random(255), 0);
if (Key == vkSpace)
Form1->Color = RGB(0, 0, random(255));
}
It works with all existing PC keyboard layouts. But with 'alt' and 'win' keys still beeps, because any key
with 'alt' or 'win' does not triger the ListViewKeyPress event.
Thank for your help!
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.
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);
}