Qt: How to catch Ctrl + A key press on macOS - c++

I am trying to implement default Emacs shortcuts supported by macOS.
Example of the code:
void InputField::keyPressEventInner(QKeyEvent *e) {
if(e->modifiers().testFlag(Qt::MetaModifier) && e->key() == Qt::Key_A) {
// Does not work
}
I've tried to use QGuiApplication::keyboardModifiers():
if(QGuiApplication::keyboardModifiers().testFlag(Qt::MetaModifier) && e->key() == Qt::Key_A) {
// does not work
}
QKeyEvent::nativeModifiers() always returns 0 when a modifier key is pressed.
Note: I use MetaModifier because according to the official documentation:
On macOS, the ControlModifier value corresponds to the Command keys on the keyboard, and the MetaModifier value corresponds to the Control keys.
How do I catch the Control key?
Qt 5.12.8
XCode 11.7
Update:
I can catch either Ctrl or a:
if(e->modifiers() & Qt::MetaModifier))
or
if(e->key() == Qt::Key_A)

Related

Qt catch shift + 3 on one key press

I'm using Qt 5.11.
I need to catch shift + 3 on one key press. But this combination generates special character ^ because I'm using Turkish Q Keyboard. So I can't catch it without press shift + 3 again.
I tried shift modifiers and multiple key press solutions but not working.
I want to override ^. Is there any possible ways to do it?
Try the following it could work. Although according to the documentation, nativeVirtualKey could return 0 even if there is valid information. So not sure if it will work all the time. I tested it with a german, english and arabic keyboard.
Update (tested it with turkish keyboard layout)
void keyPressEvent(QKeyEvent *ev)
{
if ((ev->nativeVirtualKey() == Qt::Key_3 || ev->key() == Qt::Key_3) && ev->modifiers() == Qt::ShiftModifier)
{
//Do something
}
}
For turkish layout, ^ caret (a dead key), in addition to the above, you can catch the dead key press by overriding the nativeEvent function and calling the keyEvent function manually
bool nativeEvent(const QByteArray & eventType, void * message, long * result)
{
MSG *msg = reinterpret_cast<MSG*>(message);
if (msg->message == WM_DEADCHAR)
{
QKeyEvent *key = new QKeyEvent(QEvent::KeyPress, Qt::Key_3, Qt::ShiftModifier);
}
}
One minor issue, the keyEvent will be called even if ^ is pressed in another language, not necessarily only with Shift+3, so this is an unexpected behaviour, but maybe for your case you can tell the user that both shift+3 or ^ are the shortcut for your specific function

QT: Ignore key events on checkbox selection

I have a QT Application on Windows which has a mode of using arrow keys, and also a mode which should totally ignore these arrow keys. That is, I want the arrow keys to not to trigger any event once the user checks a box.
I saw a post where eventFilter() was suggested, but I did not get how I could use it. Here is the checkbox event that listens the user, and gets triggered once the user checks it. In the else part I want the eventFilter() to work for arrow keys, but so far I could not get it running.
void MainWindow::on_checkBoxSmartCutMode_stateChanged(int arg1)
{
if (arg1 == 0)
{
// do as usual, arrow keys should work
}
else
{
eventFilter(); // if any arrow key is pressed, ignore the event
}
}
Any suggestions?
You can use keyEvent as your key filter by override keyPressEvent and test your checkbox state.
example:
void MainWindow::keyPressEvent(QKeyEvent *event)
{
// check your checkbox state
if (ui->poCheckBox->checkState() == Qt::Unchecked)
// do as usual, arrow keys should work
return;
switch(event->key())
{
case Qt::Key_Left:
case Qt::Key_Right: // add more cases as needed
event->ignore(); // if any arrow key is pressed, ignore the event
return;
}
// handle the event
}

Quit application call twice the closeevent

I have wrote an application in Qt/c++ on OSX. When quitting the app, I'm catching the closeevent to display dialog box
void MainUI::closeEvent (QCloseEvent *event)
{
if( DeviceUnplugged == false) {
ExitDialog = new DialogExit;
ExitDialog->exec();
if(ExitDialog->result() == QDialog::Accepted) {
m_device.CloseDevice();
event->accept();
}
else {
event->ignore();
}
}
}
The dialog box is correctly displayed when closing using the red cross or using the menu "quit".
but when I'm closing the app using the right click on the icon in the dock, the dialog box appears twice the close event is called twice.
Any idea why ?
Yes, I think it is normal for Mac, at least I had this in my Qt application, too (only on Mac).
I used the following workaround:
void MainUI::closeEvent (QCloseEvent *event)
{
if (m_closing)
{
event->accept();
return;
}
if( DeviceUnplugged == false) {
ExitDialog = new DialogExit;
ExitDialog->exec();
if(ExitDialog->result() == QDialog::Accepted) {
m_device.CloseDevice();
m_closing = true;
event->accept();
}
else {
event->ignore();
}
}
}
By default, boolean variable m_closing should be initialized by false of course in your class. This way second time nothing will be done (processing will be skipped). This worked for me.
Looks like this is a QT bug:
See: https://bugreports.qt.io/browse/QTBUG-43344
Also had this problem when using qt-5.6_4 ,
In my case it happened when using CMD+Q but didn't happen when using the red x button.
Used a similar patch.
I avoided accept or ignore since this is a bug and I don't think we should "talk to it" :-)
Instead I simply return when called more then once.
static int numCalled = 0;
if (numCalled++ >= 1)
return;

Handling input with GLFW

Here is the definition of my keyboard callback method I'm using to check for user input for a 2D basic game. However I'm having a problem handling certain simultaneous key presses.
For example, If I hold the Right and Up arrows keys, the player moves 45 degrees toward the top right of the screen as it should. Then, while still holding the up and right keys, if I press Space (which fires a projectile), that works as well.
However, if I hold the Left and Down arrow keys, the player moves as it should, but when I press Space, I get no input response, so I can't fire a projectile when moving down and left. All other movement + fire projectile combinations work, just the down and left doesn't... I can't figure out why. Any ideas?
if (key == GLFW_KEY_LEFT)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_LEFT, action);
}
else if (key == GLFW_KEY_RIGHT)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_RIGHT, action);
}
else if (key == GLFW_KEY_UP)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_UP, action);
}
else if (key == GLFW_KEY_DOWN)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_DOWN, action);
}
else if (key == GLFW_KEY_SPACE)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_SPACE, action);
}
else { }
Rollover is the property that allows a keyboard to properly register many key presses at once. Keyboards are wired in rows and columns. Even if the keyboard is not square, the individual keys are in a roughly square matrix of wires connecting their switches. The controller connects one row and then tests to see which of the columns are hit. Some key combinations "shadow" others. The controller can tell when the input is ambiguous and send no keys.
Better keyboard use diodes arranged to avoid the ambiguity and thus support "full rollover", although in practice USB limits you to all the modifiers plus 6 distinct keycodes at once.
Sounds like a crappy keyboard.
You may have to procure a better one.
Or use different key combinations.
The code should be
if (key == GLFW_KEY_LEFT)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_LEFT, action);
}
if (key == GLFW_KEY_RIGHT)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_RIGHT, action);
}
if (key == GLFW_KEY_UP)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_UP, action);
}
if (key == GLFW_KEY_DOWN)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_DOWN, action);
}
if (key == GLFW_KEY_SPACE)
{
GameController::getInstance()->getPlayer()->changeKeyPress(GLFW_KEY_SPACE, action);
}
The problem is your code just detect 1 key press at a time so when you press left and right at the same time only the if (key == GLFW_KEY_LEFT) is fired

Capturing modifier keys Qt

I am trying to understand how to handle various events with Qt and have found an issue I cannot understand with key modifiers e.g. Ctrl Shift Alt etc. I have made a default Qt GUI Application in Qt Creator extending QMainWindow and have found that the following example does not produce understandable results.
void MainWindow::keyPressEvent(QKeyEvent *event)
{
qDebug() << "Modifier " << event->modifiers().testFlag(Qt::ControlModifier);
qDebug() << "Key " << event->key();
qDebug() << "Brute force " << (event->key() == Qt::Key_Control);
}
Using the modifiers() function on the event never is true while the brute force method returns the correct value.
What have I done wrong?
Try using this to check for shift:
if(event->modifiers() & Qt::ShiftModifier){...}
this to check for control:
if(event->modifiers() & Qt::ControlModifier){...}
and so on. That works well for me.
EDIT:
To get the modifiers of a wheel event, you need to check the QWheelEvent object passed to your wheelEvent() method:
void MainWindow::wheelEvent( QWheelEvent *wheelEvent )
{
if( wheelEvent->modifiers() & Qt::ShiftModifier )
{
// do something awesome
}
else if( wheelEvent->modifiers() & Qt::ControlModifier )
{
// do something even awesomer!
}
}
According to the documentation, QKeyEvent::modifiers cannot always be trusted. Try to use QApplication::keyboardModifiers() static function instead.
From Qt 5 Doc. – Qt::KeyboardModifiers QKeyEvent::modifiers() const:
Warning: This function cannot always be trusted. The user can confuse it by pressing both Shift keys simultaneously and releasing one of them, for example.