]> git.lyx.org Git - features.git/commitdiff
Respect OS-level keyboard language
authorJean-Marc Lasgouttes <lasgouttes@lyx.org>
Tue, 16 Jul 2019 23:01:49 +0000 (01:01 +0200)
committerJean-Marc Lasgouttes <lasgouttes@lyx.org>
Thu, 18 Jun 2020 13:48:37 +0000 (15:48 +0200)
This bug provides two features:

1/ when a new document is created the language is set to the current
  keyboard language.

2/ when keyboard is switched at OS level, the input language of
   current window is changed. The language is set preferably to one of
   those of the document. Ex. if the keyboard changes to en_GB but one
   is typing a document in US English and Hebrew, then US English will
   be selected rather that adding UK English to the list.

The implementation depends a lot on Qt. The platform status is :

* working on Windows 10

* not working with Linux (although 1/ works with Qt4); it seems that
  Qt5 supports switching through ibus, but I do not know what this
  means.

* not yet tested on macOS.

This addresses bugs #6450, #6247 and somehow #10514.

src/Buffer.cpp
src/BufferView.cpp
src/BufferView.h
src/Language.cpp
src/Language.h
src/frontends/Application.h
src/frontends/qt4/GuiApplication.cpp
src/frontends/qt4/GuiApplication.h

index 3ab6c611f40f7892e1fec5c95696dc77278a964c..85e27952ff84dff199dbd95a2bb13b54402c24ff 100644 (file)
@@ -83,6 +83,7 @@
 #include "graphics/GraphicsCache.h"
 #include "graphics/PreviewLoader.h"
 
+#include "frontends/Application.h"
 #include "frontends/alert.h"
 #include "frontends/Delegates.h"
 #include "frontends/WorkAreaManager.h"
@@ -465,6 +466,9 @@ Buffer::Impl::Impl(Buffer * owner, FileName const & file, bool readonly_,
        if (!cloned_buffer_) {
                temppath = createBufferTmpDir();
                lyxvc.setBuffer(owner_);
+               Language const * inplang = languages.getFromCode(theApp()->inputLanguageCode());
+               if (inplang)
+                       params.language = inplang;
                if (use_gui)
                        wa_ = new frontend::WorkAreaManager;
                return;
index 97adab820cfcec1599658a14d3a6dc15f5e16b56..40d8643363763547574d93a1c887a4cdbf765fe5 100644 (file)
@@ -2739,6 +2739,17 @@ Cursor const & BufferView::cursor() const
 }
 
 
+void BufferView::setCursorLanguage(std::string const & code)
+{
+       Language const * lang = languages.getFromCode(code, buffer_.getLanguages());
+       if (lang) {
+               d->cursor_.current_font.setLanguage(lang);
+               d->cursor_.real_current_font.setLanguage(lang);
+       } else
+               LYXERR0("setCursorLanguage: unknown language code " << code);
+}
+
+
 bool BufferView::singleParUpdate()
 {
        Text & buftext = buffer_.text();
index 40dd0d29c352a4496ef0b3301b2910fda1c67226..bb75c160c66e83b2e53c3d0736d449362ff1e2cc 100644 (file)
@@ -267,6 +267,12 @@ public:
        /// sets cursor.
        /// This is used when handling LFUN_MOUSE_PRESS.
        bool mouseSetCursor(Cursor & cur, bool select = false);
+       /// Set the cursor language from language code.
+       /* Considers first exact math with the codes used in the document,
+        * then approximate match among the same list, and finally exact
+        * or partial match with the whole list of languages.
+        */
+       void setCursorLanguage(std::string const & code);
 
        /// sets the selection.
        /* When \c backwards == false, set anchor
index 52c1c4fcfc2324e93a74c2af15bb0577cc2aee85..a1f356247b00616cb645068fca9ff6aebb5d5472 100644 (file)
@@ -367,6 +367,7 @@ bool readTranslations(Lexer & lex, Language::TranslationMap & trans)
 enum Match {
        NoMatch,
        ApproximateMatch,
+       VeryApproximateMatch,
        ExactMatch
 };
 
@@ -389,6 +390,8 @@ Match match(string const & code, Language const & lang)
        if ((code.size() == 2) && (langcode.size() > 2)
                && (code + '_' == langcode.substr(0, 3)))
                return ApproximateMatch;
+       if (code.substr(0,2) == langcode.substr(0,2))
+               return VeryApproximateMatch;
        return NoMatch;
 }
 
@@ -398,17 +401,41 @@ Match match(string const & code, Language const & lang)
 
 Language const * Languages::getFromCode(string const & code) const
 {
-       // Try for exact match first
+       // 1/ exact match with any known language
        for (auto const & l : languagelist_) {
                if (match(code, l.second) == ExactMatch)
                        return &l.second;
        }
-       // If not found, look for lang prefix (without country) instead
+
+       // 2/ approximate with any known language
        for (auto const & l : languagelist_) {
                if (match(code, l.second) == ApproximateMatch)
                        return &l.second;
        }
-       LYXERR0("Unknown language `" + code + "'");
+       return 0;
+}
+
+
+Language const * Languages::getFromCode(string const & code,
+                       set<Language const *> const & tryfirst) const
+{
+       // 1/ exact match with tryfirst list
+       for (auto const * lptr : tryfirst) {
+               if (match(code, *lptr) == ExactMatch)
+                       return lptr;
+       }
+
+       // 2/ approximate match with tryfirst list
+       for (auto const * lptr : tryfirst) {
+               Match const m = match(code, *lptr);
+               if (m == ApproximateMatch || m == VeryApproximateMatch)
+                       return lptr;
+       }
+
+       // 3/ stricter match in all languages
+       return getFromCode(code);
+
+       LYXERR0("Unknown language `" << code << "'");
        return 0;
 }
 
index 5627dd48cc8a2193cd71cbf52e51119691e7042f..9201b00d96a578fbedbdc1eae53894fc068b51c7 100644 (file)
@@ -21,6 +21,7 @@
 #include "support/trivstring.h"
 
 #include <map>
+#include <set>
 #include <vector>
 
 
@@ -168,6 +169,9 @@ public:
        ///
        Language const * getFromCode(std::string const & code) const;
        ///
+       Language const * getFromCode(std::string const & code,
+                       std::set<Language const *> const & tryfirst) const;
+       ///
        void readLayoutTranslations(support::FileName const & filename);
        ///
        Language const * getLanguage(std::string const & language) const;
index cf82776039e98217d779f2a013475fd395c27f8e..415cea147671f47ac2080d7f5db00a853b723f55 100644 (file)
@@ -240,6 +240,8 @@ public:
        /// \return the math icon name for the given command.
        static docstring mathIcon(docstring const & c);
 
+       /// The language associated to current keyboard
+       virtual std::string inputLanguageCode() const = 0;
        /// Handle a accented char key sequence
        /// FIXME: this is only needed for LFUN_ACCENT_* in Text::dispatch()
        virtual void handleKeyFunc(FuncCode action) = 0;
index 666b961095e0700e7c682f27c807b0ccd4eb85d2..dd343241c55379f87ff785aec740d636ab055963 100644 (file)
@@ -1089,6 +1089,12 @@ GuiApplication::GuiApplication(int & argc, char ** argv)
        if (lyxrc.typewriter_font_name.empty())
                lyxrc.typewriter_font_name = fromqstr(typewriterFontName());
 
+#if (QT_VERSION >= 0x050000)
+       // Qt4 does this in event(), see below.
+       // Track change of keyboard
+       connect(inputMethod(), SIGNAL(localeChanged()), this, SLOT(onLocaleChanged()));
+#endif
+
        d->general_timer_.setInterval(500);
        connect(&d->general_timer_, SIGNAL(timeout()),
                this, SLOT(handleRegularEvents()));
@@ -2115,6 +2121,26 @@ docstring GuiApplication::viewStatusMessage()
 }
 
 
+string GuiApplication::inputLanguageCode() const
+{
+#if (QT_VERSION < 0x050000)
+       QLocale loc = keyboardInputLocale();
+#else
+       QLocale loc = inputMethod()->locale();
+#endif
+       //LYXERR0("input lang = " << fromqstr(loc.name()));
+       return fromqstr(loc.name());
+}
+
+
+void GuiApplication::onLocaleChanged()
+{
+       //LYXERR0("Change language to " << inputLanguage()->lang());
+       if (currentView() && currentView()->currentBufferView())
+               currentView()->currentBufferView()->setCursorLanguage(inputLanguageCode());
+}
+
+
 void GuiApplication::handleKeyFunc(FuncCode action)
 {
        char_type c = 0;
@@ -2718,6 +2744,15 @@ bool GuiApplication::event(QEvent * e)
                e->accept();
                return true;
        }
+#if (QT_VERSION < 0x050000)
+       // Qt5 uses a signal for that, see above.
+       case QEvent::KeyboardLayoutChange:
+               //LYXERR0("keyboard change");
+               if (currentView() && currentView()->currentBufferView())
+                       currentView()->currentBufferView()->setCursorLanguage(inputLanguageCode());
+               e->accept();
+               return true;
+#endif
        default:
                return QApplication::event(e);
        }
index 22d4365821773463de99962655b65a4285f53aaf..f5b11c9faefa9f2666e0c7c9f90a2377af22923b 100644 (file)
@@ -77,6 +77,7 @@ public:
        void unregisterSocketCallback(int fd) override;
        bool searchMenu(FuncRequest const & func, docstring_list & names) const override;
        bool hasBufferView() const override;
+       std::string inputLanguageCode() const override;
        void handleKeyFunc(FuncCode action) override;
        bool unhide(Buffer * buf) override;
        //@}
@@ -214,6 +215,8 @@ private Q_SLOTS:
        ///
        void onLastWindowClosed();
        ///
+       void onLocaleChanged();
+       ///
        void slotProcessFuncRequestQueue() { processFuncRequestQueue(); }
 
 private: