Repository: spyder-ide/spyder

Issue:
AltGr closes completion widget
## Problem Description

AltGr closes the autocompletion popup menu. That's bad for me because in [my keyboard layout](https://maximilian-schillinger.de/kou-layout.html) I have the arrow keys on a higher level: AltGr+E = Up arrow, AltGr+D = Down arrow. Many other layouts use the same mapping, for example:

* [Neo2](https://www.neo-layout.org/) (in [Wikipedia](https://en.wikipedia.org/wiki/Keyboard_layout#Neo))
* [Aus der Neo-Welt](http://www.adnw.de/)
* [KOY](http://www.adnw.de/index.php?n=Main.SeitlicheNachbaranschl%c3%a4ge)
* [bone](https://web.archive.org/web/20180721192908/http://wiki.neo-layout.org/wiki/Bone)

(All linked layout description pages are in German, sorry!)

I don't see any need for closing the autocompletion menu when a modifier key is pressed.

### What steps reproduce the problem?

1. Activate the layout "neo_qwerty": `setxkbmap de neo_qwerty` (This will give you a QWERTY layout, with level 3 to 6 of the Neo2 layout.)
2. Open a file in spyder, enter some text and move the cursor around with AltGr+E/S/D/F.
2. Enter `sys.` and press tab, you should see a autocompletion window now.
3. Press AltGr+D.

### What is the expected output? What do you see instead?

After pressing AltGr the autocompletion window closes. I would expect that pressing only AltGr has no effect and pressing AltGr+D selects the next entry in the autocompletion window.

## Versions
<!--- You can get this information from Help > About Spyder...
or (if Spyder won't launch) the "conda list" command
from the Anaconda Prompt/Terminal/command line. --->

* Spyder version: 4.0.1
* Python version: 3.8.0 64-bit
* Qt version: 5.12.6
* PyQt version: 5.12.3
* Operating System name/version: Linux 4.15.0-74-generic (Ubuntu 18.04)

### Dependencies

```
atomicwrites >=1.2.0         :  1.3.0 (OK)
chardet >=2.0.0              :  3.0.4 (OK)
cloudpickle >=0.5.0          :  1.2.2 (OK)
diff_match_patch >=20181111  :  20181111 (OK)
intervaltree                 :  None (OK)
IPython >=4.0                :  7.11.1 (OK)
jedi =0.14.1                 :  0.14.1 (OK)
keyring                      :  None (OK)
nbconvert >=4.0              :  5.6.1 (OK)
numpydoc >=0.6.0             :  0.9.2 (OK)
pexpect >=4.4.0              :  4.7.0 (OK)
pickleshare >=0.4            :  0.7.5 (OK)
psutil >=0.3                 :  5.6.7 (OK)
pygments >=2.0               :  2.5.2 (OK)
pylint >=0.25                :  2.4.4 (OK)
pyls >=0.31.2;<0.32.0        :  0.31.4 (OK)
xdg >=0.26                   :  0.26 (OK)
zmq >=17                     :  18.1.1 (OK)
qdarkstyle >=2.7             :  2.7 (OK)
qtawesome >=0.5.7            :  0.6.1 (OK)
qtconsole >=4.6.0            :  4.6.0 (OK)
qtpy >=1.5.0                 :  1.9.0 (OK)
sphinx >=0.6.6               :  2.3.1 (OK)
spyder_kernels >=1.8.1;<2.0.0:  1.8.1 (OK)
watchdog                     :  None (OK)
cython >=0.21                :  None (NOK)
matplotlib >=2.0.0           :  None (NOK)
numpy >=1.7                  :  None (NOK)
pandas >=0.13.1              :  None (NOK)
scipy >=0.17.0               :  None (NOK)
sympy >=0.7.3                :  None (NOK)
```



Discussion:
@jnsebgosselin, any ideas about how we could improve this situation?
Thanks for your comment!
I suppose it's about the function [keyPressEvent in completion.py](https://github.com/spyder-ide/spyder/blob/a05d71399d17e48b4b5ff9a2aca2b2795afbba70/spyder/plugins/editor/widgets/completion.py#L297).

```python
        alt = event.modifiers() & Qt.AltModifier
        shift = event.modifiers() & Qt.ShiftModifier
        ctrl = event.modifiers() & Qt.ControlModifier
        modifier = shift or ctrl or alt
...
        elif modifier:
            self.textedit.keyPressEvent(event)
        else:
            self.hide()
            QListWidget.keyPressEvent(self, event)
```

Maybe `Qt.AltModifier` doesn't include *AltGr*?
Alt modifier should include Alt + Ctrl (that is what Altgr does in reality) so it should be working. @ccordoba12 maybe we could add something like check for the key  `Key_AltGr` ?
I have tested what happens with the autocompletion menu for different modifier keys (QWERTZ layout):

* Shift: stays open
* Ctrl: stays open
* Alt: closes on keyup
* AltGr: closes on keydown
* Win: closes on keydown
@MaxGyver83, given that you already have an idea on how to fix this problem and it happens for your specific keyboard layout, please submit a PR to fix it.
@ccordoba12 , this is the result of my analysis:

| Key | `text` | `key`   | `int(event.modifiers())` | `modifier` |
|:-------|:------| -------:|-------------------------:|------------|
| a     | a    |       65|         0|False |
| 0     | 0    |       48|         0|False |
| Shift |      | 16777248|  33554432|True |
| Ctrl  |      | 16777249|  67108864|True |
| Alt   |      | 16777251| 134217728|True |
| AltGr |      |        0|         0|False |
| Tab   |      | 16777219|         0|False |
| Esc   | 001B placeholder | 16777216| 0|False |
| Pause |      | 16777224|         0|False |
| Win   | nothing printed ||        |      |

So my bugfix is easy:

```diff
--- a/spyder/plugins/editor/widgets/completion.py
+++ b/spyder/plugins/editor/widgets/completion.py
@@ -300,7 +300,8 @@ class CompletionWidget(QListWidget):
         alt = event.modifiers() & Qt.AltModifier
         shift = event.modifiers() & Qt.ShiftModifier
         ctrl = event.modifiers() & Qt.ControlModifier
-        modifier = shift or ctrl or alt
+        altgr = (key==0)
+        modifier = shift or ctrl or alt or altgr
         if key in (Qt.Key_Return, Qt.Key_Enter, Qt.Key_Tab):
             # Check that what was selected can be selected,
             # otherwise timing issues
```

I made my own branch but I can't push it upstream. Do I have to fork spyder for making a push plus a pull request?
> Do I have to fork spyder for making a push plus a pull request?

That is correct
> I made my own branch but I can't push it upstream. Do I have to fork spyder for making a push plus a pull request?

Yes, because you don't have write permissions to this repo. Please also do your bugfix branch against our `4.x` to include this in our next bugfix release.

And finally, thanks a lot for taking the time to fix this!

Resolving patch:
diff --git a/spyder/plugins/editor/widgets/completion.py b/spyder/plugins/editor/widgets/completion.py
--- a/spyder/plugins/editor/widgets/completion.py
+++ b/spyder/plugins/editor/widgets/completion.py
@@ -300,7 +300,11 @@ def keyPressEvent(self, event):
         alt = event.modifiers() & Qt.AltModifier
         shift = event.modifiers() & Qt.ShiftModifier
         ctrl = event.modifiers() & Qt.ControlModifier
-        modifier = shift or ctrl or alt
+        altgr = event.modifiers() and (key == Qt.Key_AltGr)
+        # Needed to properly handle Neo2 and other keyboard layouts
+        # See spyder-ide/spyder#11293
+        neo2_level4 = (key == 0)  # AltGr (ISO_Level5_Shift) in Neo2 on Linux
+        modifier = shift or ctrl or alt or altgr or neo2_level4
         if key in (Qt.Key_Return, Qt.Key_Enter, Qt.Key_Tab):
             # Check that what was selected can be selected,
             # otherwise timing issues


Test patch: