Search code examples
c++qtkeyboard

How to make a French keyboard's dot key (numeric keypad) work as input with Qt?


I'm designing a C++/Qt application. I'm with a French keyboard on a French Windows environment.

When I try to type a decimal number in a QDoubleSpinBox control, pressing the dot numeric keypad button does nothing....I would expect it to insert a decimal separator!

Here is a very simple Qt program isolating the problem:

main.cpp:

#include <QApplication>
#include <QVBoxLayout>
#include <QLabel>
#include <QSpinBox>
#include <QDialog>

class Dialog : public QDialog
{
public:
    Dialog()
    {
        QVBoxLayout* layout = new QVBoxLayout( this );

        layout->addWidget( new QLabel( QLocale().toString( 3.14 ), this ) );
        layout->addWidget( new QDoubleSpinBox( this ) );
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Dialog w;
    w.show();

    return a.exec();
}

I compiled it with Visual Studio 2010 and 5.2.1 on a French PC.

When the dialog opens:

enter image description here

Then:

  • The QLabel displays "3,14" which means french QLocale is correctly used (else, it would display 3.14, english default stype). OK
  • The QDoubleSpinBox diplays "0,00". OK
  • I can type a decimal value in the spinbox using the ',' standard keyboard key. OK
  • I cannot type a decimal value in the spinbox using the '.' standard keyboard key. OK
  • But when I press the dot key from my numerical French keypad, nothing happens! This is supposed to enter a decimal separator, whatever locale setting is being used!

I'm looking for a gloabl solution (at QApplication level), not something at QSpinBox level because I have many of them in my original project.


Solution

  • Until https://bugreports.qt.io/browse/QTBUG-41256 is fixed, the solution is an application-global event filter, so that any use of the '.' key on the numeric keyboard (and only there) is turned into a ',' -- on systems where the default locale uses ',' as decimal separator.

    class GlobalEventFilter : public QObject
    {
    public:
        explicit GlobalEventFilter(QObject *parent) : QObject(parent) {}
        bool eventFilter(QObject *obj, QEvent *ev) override {
            if (ev->type() == QEvent::KeyPress || ev->type() == QEvent::KeyRelease) {
                QKeyEvent *kev = static_cast<QKeyEvent *>(ev);
                if (kev->key() == Qt::Key_Period && (kev->modifiers() & Qt::KeypadModifier)) {
                    QChar decimalPoint = QLocale().decimalPoint();
                    if (decimalPoint == QLatin1Char(',')) {
                        QKeyEvent modifiedKeyEvent(kev->type(), Qt::Key_Comma, kev->modifiers(), QString(decimalPoint), kev->isAutoRepeat(), kev->count());
                        qApp->sendEvent(obj, &modifiedKeyEvent);
                        return true;
                    }
                }
            }
            return false;
        }
    };
    

    And in your main(), add qApp->installEventFilter(new GlobalEventFilter(qApp));.

    I tested this to work on a French Linux system.