Beeping while KeyDown is triggered - c++

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!

Related

How to set focus for button in KeyPressEvent for key_up, key_down. QT

I have a Form with buttons called "Up", "Down", etc.
I need to process keyboard buttons (arrow_up, arrow_down, etc). Parallelly I want to set focus for relevant buttons.
For Example: If I pressed the arrow_down button on keyboard then the "Down" button would be a focus on my Form.
My variant how to do this:
bool ClientWindow::eventFilter(QObject *obj, QEvent *e)
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *event= dynamic_cast<QKeyEvent*>(e);
switch(event->key()) {
case Qt::Key_Up: ui->up->setFocus(); ;break;
case Qt::Key_Down: ui->down->setFocus(); break;
case Qt::Key_Left: ui->left->setFocus(); break;
case Qt::Key_Right: ui->right->setFocus(); break;
}
}
return QObject::eventFilter(obj, event);
}
But, focus isn't set, and
1) If I return true from eventFilter then focus wouldn't set.
2) If I return QObject::eventFilter(obj, event) then focus would be transferred to next Object.
How to set focus for the relevant button?
Since you're trying to change a standard feature of Qt (arrow keys move focus just like TAB key does), you may want to try an extreme solution.
The point is: are your arrow key press events even being filtered at all? My guess is no. Something above (or before) the widget is consuming them and keeps the standard behavior unchanged (focus move from button to button according to their tab-indexes as usual).
I would try installing your filter onto the QApplication object, in the widget constructor this way:
qApp->installEventFilter(this);
The filter should look like this:
bool Widget::eventFilter(QObject *obj, QEvent *e)
{
if (e->type() == QEvent::KeyPress)
{
if(qApp->activeWindow() == this)
{
QKeyEvent *event= dynamic_cast<QKeyEvent*>(e);
switch(event->key()) {
case Qt::Key_Up: ui->up->setFocus(); break;
case Qt::Key_Down: ui->down->setFocus(); break;
case Qt::Key_Left: ui->left->setFocus(); break;
case Qt::Key_Right: ui->right->setFocus(); break;
default:
return qApp->eventFilter(obj, e);
}
return true;
}
}
return qApp->eventFilter(obj, e);
}
Please notice this line:
if(qApp->activeWindow() == this)
which should prevent the rule in the filter to be applied whenever the arrow keys get pressed (i.e. when the widget isn't the topmost one). You can ignore that, if your application hasn't other widget than this one.
Final advice: try to never change the standard UI behavior. Users do expect things to work as usual, and solutions that look absolutely cool to the developer, sometimes (often), brings no improvements at all and only confuse the user.

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;

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.

How to change the state of button to clicked in cocos2d-x

I am pretty new to cocos2d-x.I have created a button and i wanted to change the state of the button when i tap the button . i am having trouble changing the state from play to pause similar to a music player.Below is the code.
void Gallery::buttonUI(Size visibleSize,Vec2 origin)
{
button = Button::create("play.png");
//button->loadTextures("pause.png","play.png","pause.png");
button->setPosition(Point((visibleSize.width/2)+origin.x,(visibleSize.height/2)+origin.y-80));
button->setContentSize(Size(100.0f, button->getVirtualRendererSize().height));
button->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
switch (type)
{
case Widget::TouchEventType::BEGAN:
break;
case Widget::TouchEventType::ENDED:
CCLOG("Characters: %c %c", 'a', 65);
if (!flag)
Gallery::pauseSong();
else
Gallery::resumeSong();
break;
default:
break;
}
});
this->addChild(button);
}
void Gallery::playSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("1.mp3");
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("1.mp3");
flag = false;
}
void Gallery::pauseSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
flag = true;
}
void Gallery::resumeSong()
{
CocosDenshion::SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
flag = false;
}
I don’t know of such methods for the ui::Button. But I don’t see the use of specific ui::Button items (capinsets, different methods for different touch events etc.) in your method also.
So, I think the MenuItemImage is better in your case:
bool flag = true;
MenuItemImage *button = MenuItemImage::create("play.png", "play_pressed.png", CC_CALLBACK_0(Gallery::playSong, this));
button->setPosition(Vec2((visibleSize.width/2)+origin.x,(visibleSize.height/2)+origin.y-80)); // better is use Vec2, Point can be ambiguous
Menu* menu = Menu::create(button, NULL); // add created button on Menu
menu ->setPosition(0,0);
this->addChild(menu);
And then set the images in handler pressing:
void Gallery::playSong()
{
if(flag)
{
// preload better move to AppDelegate.cpp
// CocosDenshion::SimpleAudioEngine::getInstance()->preloadBackgroundMusic("1.mp3");
flag = false;
CocosDenshion::SimpleAudioEngine::getInstance()->playBackgroundMusic("1.mp3");
button->setNormalImage(Sprite::create(“pause.png”));
button->setSelectedImage(Sprite::create(“pause_pressed.png”)); // if you use selected image
}
else
{
flag = true;
CocosDenshion::SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
button->setNormalImage(Sprite::create(“play.png”));
button->setSelectedImage(Sprite::create(“play_pressed.png”));
}
}
In cocos 3.x use property: setHighlighted(bool)
Example:
When press a key: button->setHighlighted(true);
When release the key:
button->setHighlighted(false);

Resolving inconsistent SDL2 key press detection?

I am trying to detect when a key is pressed down using the SDL_Event system.
I am using this code to detect the key presses:
void GameLoop::update(SDL_Event eventHandler, Camera &camera){
Vector2 move = Vector2();
if (eventHandler.type == SDL_KEYDOWN){
switch (eventHandler.key.keysym.sym){
case SDLK_w:
move = Vector2(0, -1);
break;
case SDLK_s:
move = Vector2(0, 1);
break;
case SDLK_a:
move = Vector2(-1, 0);
break;
case SDLK_d:
move = Vector2(1, 0);
break;
}
}
camera.translateCamera(move);
}
If I switch out 'WASD' inputs to 'UP DOWN LEFT RIGHT' The system works and if I remove the line:
if (eventHandler.type == SDL_KEYDOWN){
It works due to the SDL_KEYUP type, using 'WASD' or 'UP DOWN LEFT RIGHT'
What is causing this behaviour and how to fix it?
SDL literally checks IF the keyboard is pressed, it just so happens that the program reads faster than the actual press which will result in numerous presses, I'm not sure about your up, down, left, right buttons, maybe they are meant to be read by SDL but their physical connection might not be the same with the letters in the keyboard.
Now if you change KEYDOWN to KEYUP, all it would read is IF it is up, this isn't really good.
What you would want to do is use booleans and ticks
if (eventHandler.type == SDL_KEYDOWN && !clicked){
ticking2 = SDL_GetTicks();
switch (eventHandler.key.keysym.sym){
case SDLK_w:
clicked = true;
break;
case SDLK_s:
clicked = true;
break;
}
}
if (eventHandler.type == SDL_KEYUP && clicked){
ticking = SDL_GetTicks();
switch (eventHandler.key.keysym.sym){
case SDLK_w:
if(ticking-ticking2 >= 3000)
{
move = Vector2(0, -1);
clicked = false;
}
break;
case SDLK_s:
if(ticking-ticking2 >= 3000)
{
move = Vector2(0, 1);
clicked = false;
}
break;
}
}
Upon pressing a button, it gets the time and pushes it into ticking2 but then after upon a click, it turns the bool clicked into true which then makes it stop reading the loop, thus, freezing the value of ticking 2.
Upon releasing a button, it checks if clicked is true so that the actions will only be made IF the button was actually pressed.
It gets the time and pushes it into ticking, ticking-ticking2 should equal to something around 0, I made those to ensure that effects won't be instant since it might cause some glitches.