Fix AltGr problem on Windows
authorNathan Letwory <nathan@letworyinteractive.com>
Sat, 16 Oct 2010 15:21:55 +0000 (15:21 +0000)
committerNathan Letwory <nathan@letworyinteractive.com>
Sat, 16 Oct 2010 15:21:55 +0000 (15:21 +0000)
It was impossible for keyboard layouts that use AltGr to create certain characters to insert
them in Text and Console.

The keyboard driver in Windows sends left control events when AltGr is pressed. This meant that
Blender thought control was being held, which is a PASS_THROUGH condition for the insert operator
in both editors.

Add testing of keyboard layout for AltGr, both on initialization and WM_INPUTLANGCHANGE.

To remedy AltGr problem, we send now a left control key up event to Blender before further processing
the AltGr key.

intern/ghost/intern/GHOST_SystemWin32.cpp
intern/ghost/intern/GHOST_SystemWin32.h

index d63ac70..1f1fc65 100644 (file)
@@ -34,6 +34,8 @@
  * @date       May 7, 2001
  */
 
+#include <iostream>
+
 #include "GHOST_SystemWin32.h"
 #include "GHOST_EventDragnDrop.h"
 
@@ -142,6 +144,8 @@ GHOST_SystemWin32::GHOST_SystemWin32()
        GHOST_ASSERT(m_displayManager, "GHOST_SystemWin32::GHOST_SystemWin32(): m_displayManager==0\n");
        m_displayManager->initialize();
        
+       this->keyboardAltGr();
+       
        // Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
        OleInitialize(0);
 }
@@ -285,18 +289,18 @@ GHOST_TSuccess GHOST_SystemWin32::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32
 
 GHOST_TSuccess GHOST_SystemWin32::getModifierKeys(GHOST_ModifierKeys& keys) const
 {
-       bool down = HIBYTE(::GetKeyState(VK_LSHIFT)) != 0;
+       bool down = HIBYTE(::GetKeyState(VK_SHIFT)) != 0;
        keys.set(GHOST_kModifierKeyLeftShift, down);
-       down = HIBYTE(::GetKeyState(VK_RSHIFT)) != 0;
        keys.set(GHOST_kModifierKeyRightShift, down);
-       down = HIBYTE(::GetKeyState(VK_LMENU)) != 0;
+       
+       down = HIBYTE(::GetKeyState(VK_MENU)) != 0;
        keys.set(GHOST_kModifierKeyLeftAlt, down);
-       down = HIBYTE(::GetKeyState(VK_RMENU)) != 0;
        keys.set(GHOST_kModifierKeyRightAlt, down);
-       down = HIBYTE(::GetKeyState(VK_LCONTROL)) != 0;
+       
+       down = HIBYTE(::GetKeyState(VK_CONTROL)) != 0;
        keys.set(GHOST_kModifierKeyLeftControl, down);
-       down = HIBYTE(::GetKeyState(VK_RCONTROL)) != 0;
        keys.set(GHOST_kModifierKeyRightControl, down);
+       
        bool lwindown = HIBYTE(::GetKeyState(VK_LWIN)) != 0;
        bool rwindown = HIBYTE(::GetKeyState(VK_RWIN)) != 0;
        if(lwindown || rwindown)
@@ -365,7 +369,7 @@ GHOST_TSuccess GHOST_SystemWin32::init()
                wc.hbrBackground= (HBRUSH)::GetStockObject(BLACK_BRUSH);
                wc.lpszMenuName = 0;
                wc.lpszClassName= GHOST_WindowWin32::getWindowClassName();
-    
+
                // Use RegisterClassEx for setting small icon
                if (::RegisterClass(&wc) == 0) {
                        success = GHOST_kFailure;
@@ -381,14 +385,14 @@ GHOST_TSuccess GHOST_SystemWin32::exit()
 }
 
 
-GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
+GHOST_TKey GHOST_SystemWin32::convertKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) const
 {
+       bool isExtended = (lParam&(1<<24))?true:false;
+       
        GHOST_TKey key;
        GHOST_ModifierKeys oldModifiers, newModifiers;
        ((GHOST_SystemWin32*)getSystem())->retrieveModifierKeys(oldModifiers);
        ((GHOST_SystemWin32*)getSystem())->getModifierKeys(newModifiers);
-       
-       bool isExtended = (lParam&(1<<24))?true:false;
 
        if ((wParam >= '0') && (wParam <= '9')) {
                // VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39)
@@ -474,6 +478,16 @@ GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
                        break;
                case VK_MENU:
                        {
+                               if(m_hasAltGr && isExtended) {
+                                       // We have here an extended RAlt, which is AltGr. The keyboard driver on Windows sends before this a LControl, so
+                                       // to be able to input characters created with AltGr (normal on German, French, Finnish and other keyboards) we
+                                       // push an extra LControl up event. This ensures we don't have a 'hanging' ctrl event in Blender windowmanager
+                                       // when typing in Text editor or Console.
+                                       GHOST_Event *extra = new GHOST_EventKey(getSystem()->getMilliSeconds(), GHOST_kEventKeyUp, window, GHOST_kKeyLeftControl, '\0');
+                                       ((GHOST_SystemWin32*)getSystem())->pushEvent(extra);
+                                       newModifiers.set(GHOST_kModifierKeyRightControl, false);
+                                       newModifiers.set(GHOST_kModifierKeyLeftControl, false);
+                               }
                                bool lchanged = oldModifiers.get(GHOST_kModifierKeyLeftAlt) != newModifiers.get(GHOST_kModifierKeyLeftAlt);
                                if(lchanged) {
                                        key = GHOST_kKeyLeftAlt;
@@ -494,6 +508,7 @@ GHOST_TKey GHOST_SystemWin32::convertKey(WPARAM wParam, LPARAM lParam) const
                        break;
                }
        }
+       ((GHOST_SystemWin32*)getSystem())->storeModifierKeys(newModifiers);
        return key;
 }
 
@@ -573,7 +588,7 @@ GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WP
 
 GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool keyDown, WPARAM wParam, LPARAM lParam)
 {
-       GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(wParam, lParam);
+       GHOST_TKey key = ((GHOST_SystemWin32*)getSystem())->convertKey(window, wParam, lParam);
        GHOST_EventKey* event;
        if (key != GHOST_kKeyUnknown) {
                MSG keyMsg;
@@ -582,6 +597,7 @@ GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, bool k
                        /* Eat any character related messages */
                if (::PeekMessage(&keyMsg, NULL, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) {
                        ascii = (char) keyMsg.wParam;
+                       
                }
 
                event = new GHOST_EventKey(getSystem()->getMilliSeconds(), keyDown ? GHOST_kEventKeyDown: GHOST_kEventKeyUp, window, key, ascii);
@@ -630,6 +646,10 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
                GHOST_WindowWin32* window = (GHOST_WindowWin32*)::GetWindowLong(hwnd, GWL_USERDATA);
                if (window) {
                        switch (msg) {
+                               // we need to check if new key layout has altgr
+                               case WM_INPUTLANGCHANGE:
+                                       system->keyboardAltGr();
+                                       break;
                                ////////////////////////////////////////////////////////////////////////
                                // Keyboard events, processed
                                ////////////////////////////////////////////////////////////////////////
index 03f5349..3cd1dee 100644 (file)
@@ -239,7 +239,7 @@ protected:
         * @param lParam        The lParam from the wndproc
         * @return The GHOST key (GHOST_kKeyUnknown if no match).
         */
-       virtual GHOST_TKey convertKey(WPARAM wParam, LPARAM lParam) const;
+       virtual GHOST_TKey convertKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam) const;
 
        /**
         * Creates modifier key event(s) and updates the key data stored locally (m_modifierKeys).
@@ -310,6 +310,11 @@ protected:
         * @param keys The new state of the modifier keys.
         */
        inline virtual void storeModifierKeys(const GHOST_ModifierKeys& keys);
+       
+       /**
+        * Check current key layout for AltGr
+        */
+       inline virtual void keyboardAltGr();
 
        /**
         * Windows call back routine for our window class.
@@ -324,6 +329,8 @@ protected:
        __int64 m_freq;
        /** High frequency timer variable. */
        __int64 m_start;
+       /** AltGr on current keyboard layout. */
+       bool m_hasAltGr;
 };
 
 inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const
@@ -336,5 +343,22 @@ inline void GHOST_SystemWin32::storeModifierKeys(const GHOST_ModifierKeys& keys)
        m_modifierKeys = keys;
 }
 
+inline void GHOST_SystemWin32::keyboardAltGr()
+{
+       HKL keylayout = GetKeyboardLayout(0); // get keylayout for current thread
+       int i;
+       SHORT s;
+       for(m_hasAltGr = false, i = 32; i < 256; ++i) {
+               s = VkKeyScanEx((char)i, keylayout);
+               // s == -1 means no key that translates passed char code
+               // high byte contains shift state. bit 2 ctrl pressed, bit 4 alt pressed
+               // if both are pressed, we have AltGr keycombo on keylayout
+               if(s!=-1 && (s & 0x600) == 0x600) {
+                       m_hasAltGr = true;
+                       break;
+               }
+       }
+}
+
 #endif // _GHOST_SYSTEM_WIN32_H_