Qt - know whether a pressed key is just a modifier - c++

I'd like the child's handling of QKeyEvent not to be executed when it's just a modifier key that's being pressed. The following code does the job, but it's unwieldy to list them all like that. Is there a built-in way to do that?
void TextEditor::keyPressEvent(QKeyEvent *event)
{
switch(event->key())
{
case Qt::Key_Shift:
case Qt::Key_Control:
case Qt::Key_Alt:
case Qt::Key_Meta:
case Qt::Key_Mode_switch:
return QPlainTextEdit::keyPressEvent(event);
}
// handle the event...
}

You can use this QKeyEvent::modifiers() member for this purpose. If the result is
const bool isModifier = ( event->modifiers() != Qt::NoModifier );
true then the pressed key was a modifier.
So for you code it means the following modifications.
void TextEditor::keyPressEvent( QKeyEvent* event )
{
if ( event->modifiers() != Qt::NoModifier )
{
return QPlainTextEdit::keyPressEvent(event);
}
// Handle the event ...
}
Or if you want to handle some special key combination why not just use this way:
void TextEditor::keyPressEvent( QKeyEvent* aKeyEvent )
{
if ( aKeyEvent->matches( QKeySequence::Copy ) )
{
// Your copy stuff ...
return;
}
// else if ( aKeyEvent->matches( ... ) ) // Other key combinations ...
return QPlainTextEdit::keyPressEvent( aKeyEvent);
}

a better way to do this in 3 lines:
if(event->modifiers()){
event->ignore(); // or don't ignore and handle the event
// switching the modifiers
}
this is the modifiers defined by qt:
Qt::NoModifier
Qt::ShiftModifier
Qt::ControlModifier
Qt::AltModifier
Qt::MetaModifier
Qt::KeypadModifier
Qt::GroupSwitchModifier
you can do a switch for filtering.

Related

How to capture Ctrl+Plus in Qt?

How can I capture Ctrl++ in QWidget::keyPressEvent?
This is my current code (simplified):
void foo::keyPressEvent(QKeyEvent *event)
{
if (event->modifiers() == Qt::ControlModifier)
{
switch (event->key())
{
case Qt::Key_Plus:
// do something
break;
}
}
}
Which works, but only for + on the alphanumeric part of the keyboard. When I press Ctrl++ on the numeric keypad, it doesn't do anything.
Thank you
After some debugging I found out that when a key is pressed on the numeric keypad, the Qt::KeypadModifier is added to event modifiers. So the simple solution is to add this to the if statement:
if (event->modifiers() == (Qt::ControlModifier | Qt::KeypadModifiers))
{
// ...

Check Q button is held down using GLUT?

What function can I use to check if the Q button (or any other button is pressed down) and what will be the value needed to specify this for the Q button?
Using glut you need to define a Keyboard Handler function, and tell GLUT to use it for handling key strokes. Something along the lines of:
bool is_q_pressed = false;
void KeyboardHandler(unsigned char key, int x, int y)
{
switch (key)
{
case "q":
case "Q":
is_q_pressed = !is_q_pressed;
if (is_q_pressed)
// do something... or elsewhere in program
break;
}
}
void KeyboardUpHandler(unsigned char key, int x, int y)
{
switch (key)
{
case "q":
case "Q":
is_q_pressed = false;
break;
}
}
int main()
{
// Other glut init functions...
...
// Keyboard handler
glutKeyboardFunc(KeyboardHandler);
// Keyboard up handler
glutKeyboardUpFunc(KeyboardUpHandler);
...
glutMainLoop();
return 0;
}
EDIT: Added support for keyboard up. Using global variables isn't the best practice, but GLUT almost forces you to use them to keep track of program states. The good thing is that you can use the global variable (is_q_pressed) anywhere in your program... like in the idle() for some logic, or in the draw function to draw something if that key is pressed.
And, as #aslg said, you can make an array of bools to keep track of every key pressed, check his answer for ideas too :)
The simplest thing you can do is to use an array of bools with enough bools to contain the 256 regular keys and the special keys (right, left, etc.. ).
bool keys[256];
Use the KeyDown func to set the matching key to true, and KeyUp to set false.
void KeyboardDown( int key, int x, int y ) {
if ( isalpha( key ) ) {
key = toupper( key );
}
keys[ key ] = true;
}
void KeyboardUp( int key, int x, int y ) {
if ( isalpha( key ) ) {
key = toupper( key );
}
keys[ key ] = false;
}
The toupper just makes sure that pressing q or Q is the same whether Caps-lock is on or off. You don't have to use it if you don't need it.
Then somewhere in the update code you can check if a key was pressed like
if ( keys['Q'] ) {
// do things
}

wxWidgets keyboard event

I have a problem with using Key event:
there is example in documentation:
void OnChar(wxKeyEvent& event, double moveSpeed)
{
wxChar uc = event.GetUnicodeKey();
if ( uc != WXK_NONE )
{
...
}
else // No Unicode equivalent.
{
// It's a special key, deal with all the known ones:
switch ( event.GetKeyCode() )
{
case WXK_LEFT:
case WXK_RIGHT:
break;
case WXK_F1:
break;
}
}
but what if i have to use keyboards event in different function ?
I know that in other library you can simply use:
if (keyDown(SDLK_DOWN))
{
//code
}
but how can I use that in wxwidgets ?
You can use wxGetKeyStats() function if you really need to, but usually you definitely want to react to keyboard events instead of checking for the key state.

How to find the row from which drag has started QTableView

I was working on QTableView and I want to achieve drag and drop on it.
The way I want it is:
When I drag, I want to take out the row which is to be dragged and place an empty place holder there, this is how I have reimplemented dragEnterEvent:
void dragEnterEvent ( QDragEnterEvent * event )
{
if( event->source() == this )
{
// Get the row to be dragged
int mItemDraggedRowPosition = rowAt( event->pos().y() );
auto currentModel = model();
auto standardModel = boost::polymorphic_cast< QStandardItemModel *>( currentModel );
// Take out the dragged row
QList<QStandardItem *> mDraggedItem = standardModel->takeRow ( ( mItemDraggedRowPosition ) );
// Insert an empty row there
standardModel->insertRow( ( mItemDraggedRowPosition ), new QStandardItem() );
}
event->accept();
}
}
Now the problem I am facing here is the row number which I am getting is incorrect some times.
Am I not doing it correctly .?
Is there any alternative way to find out the row from which the drag was started,
seems like the way I am trying to get it:
int mItemDraggedRowPosition = rowAt( event->pos().y() );
does not return correct value always.
I finally reproduced problem and I got incorrect values too (drag very close to the joining area of 2 rows). So I solved this issue with next event filter:
ui->tableView->setDragEnabled(true);//somewhere in constructor
ui->tableView->setAcceptDrops(true);
//...
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == ui->tableView->viewport() && event->type() == QEvent::DragEnter)
{
QDragEnterEvent * e = static_cast<QDragEnterEvent *>(event);
qDebug( ) << ui->tableView->rowAt(e->pos().y());
}
return QObject::eventFilter(obj, event);
}
To use eventFilter you should also:
protected:
bool eventFilter(QObject *obj, QEvent *event);//in header
and
qApp->installEventFilter(this);//in constructor
I finally ended up overriding "mousePressEvent" and saving the start position there.
I use the same saved position in "dragEnterEvent".
This one works perfectly for me.
void
PrePressView::TableWidget::mousePressEvent( QMouseEvent * inEvent )
{
if ( inEvent->button() == Qt::LeftButton )
{
int rowToMove = rowAt( inEvent->y() );
}
}

How to catch Ctrl+C key event with Qt when Ctrl is released before 'C'?

I would like to call some custom copy code when the user releases Ctrl+C. When C is released before Ctrl, Qt sends a key event that matches with QKeySequence::Copy. When Ctrl is released before C, the release event does not match.
When the key release event comes in with Ctrl, is there a way to see if C is still being held down?
When I don't handle Ctrl being released first, the event gets passed along and it does a regular copy, which is exactly what I don't want to happen.
bool
MyWidget::eventFilter(QObject* object, QEvent* event)
{
// the text edit box filters its events through here
if (object == m_text_edit_box)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
if (key_event->matches(QKeySequence::Copy))
{
// don't do anything and don't pass along event
return true;
}
}
else if (event->type() == QEvent::KeyRelease)
{
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
if (key_event->matches(QKeySequence::Copy))
{
// we only get in here if 'c' is released before ctrl
callCustomCopy();
return true;
}
}
}
// pass along event
return false;
}
You could query the letter 'C' and the meta key Ctrl specifically and not rely on key_even->matches(). you can of course in the object where you located the eventfilter on the keydown event store the fact wether the keydown sequence did match copy.
This (untested) might work for you, note that the static variable should be a member variable of the class that this is contained in, this just seemed clearer in the context of this example. The exact logic of what you want to accomplish might need more state information to be carried between events.
bool MyWidget::eventFilter(QObject* object, QEvent* event)
{
// Remember state between events
static foundCopy = false;
// the text edit box filters its events through here
if (object == m_text_edit_box)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
if (key_event->matches(QKeySequence::Copy))
{
foundCopy = true;
// don't do anything and don't pass along event
return true;
}
else
{
foundCopy = false;
// This is another sequence, ignore and pass event
// Note that this will trigger with ctrl+c+a and others
}
}
else if (event->type() == QEvent::KeyRelease)
{
QKeyEvent *key_event = static_cast<QKeyEvent*>(event);
if (foundCopy)
{
callCustomCopy();
foundCopy = false;
return true;
}
// This should keep the system copy from triggering
if (key_event->matches(QKeySequence::Copy))
{
return true;
}
}
}
// pass along event
return false;
}
Another way would be to collect the actual state of all the keys pressed at the current time and then when one is released see which ones are still pressed.
From a UI point of view please bear in mind that all keyboard actions are performed on press, (e.g. typeing, windows paste), performing actions on release in general might confuse the user, especially when there is a visible result to the action. I can't tell from your example what you are trying to accomplish.