Repository: spyder-ide/spyder

Issue:
No curly brackets on Spyder 4.0.0b3 on macOS with a French keyboard
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

### Issue Report Checklist

* [x ] Searched the [issues page](https://github.com/spyder-ide/spyder/issues?q=is%3Aissue) for similar reports
* [x ] Read the relevant sections of the [Spyder Troubleshooting Guide](https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ) and followed its advice
* [x ] Reproduced the issue after updating with ``conda update spyder`` (or ``pip``, if not using Anaconda)
* [x ] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [x ] Tried basic troubleshooting (if a bug/error)
    * [x ] Restarted Spyder
    * [x ] Reset preferences with ``spyder --reset``
    * [ ] Reinstalled the latest version of [Anaconda](https://www.anaconda.com/download/)
    * [ ] Tried the other applicable steps from the Troubleshooting Guide
* [x ] Completed the **Problem Description**, **Steps to Reproduce** and **Version** sections below


## Problem Description
No curly brackets on Mac


### What steps reproduce the problem?

Type { }

### What is the expected output? What do you see instead?
I see only parentheses ( )



## 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.0beta3 (same in beta2)
* Python version: 3.7.3
* Qt version: 5.9.7
* PyQt version: 5.9.2
* Operating System name/version: MacOS 10.13.6

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```
pygments >=2.0    :  2.4.2 (OK)
qdarkstyle >=2.6.4:  2.7 (OK)
sphinx >=0.6.6    :  2.1.2 (OK)
psutil >=0.3      :  5.6.3 (OK)
pyls >=0.27.0     :  0.27.0 (OK)
nbconvert >=4.0   :  5.5.0 (OK)
pandas >=0.13.1   :  None (NOK)
numpy >=1.7       :  None (NOK)
sympy >=0.7.3     :  None (NOK)
cython >=0.21     :  None (NOK)
qtconsole >=4.5.0 :  4.5.1 (OK)
IPython >=4.0     :  6.5.0 (OK)
matplotlib >=2.0.0:  None (NOK)
pylint >=0.25     :  2.3.1 (OK)
```


Discussion:
I forgot to say that this is an editor problem. I can get { } at the console.
@steff456 or @juanis2112, can you reproduce this problem?
I am able to get curly brackets at the editor.

![curly](https://user-images.githubusercontent.com/20992645/60730148-0ee6b200-9f0a-11e9-8aac-15e40d465895.gif)

It is probably something going with the french keyboard. Could you contact another french person using Spyder 4.0.0beta3 (nobody around me using Spyder on MacOS)... I use 3.3.5 now.
@steff456, please use a French keyboard layout distribution to see what happens.

@jproy, sorry, we don't have French macOS developers in our team, so that's the best we can do.
@ccordoba12, I can reproduce the this problem using the French keyboard layout distribution. 
@steff456, what combination of keys are you using to enter curly braces?
With alt + 5
@jproy, is that the same combination you have to use?
@ccordoba12 Yes I use "Alt (" and "Alt )".
@ccordoba12 Do not confuse "5" and "(" because "Alt 5" is "Alt-Shift (" which gives "[" and "Alt (" gives "{".
@jproy yes, sorry is the same key combination I used "Alt ("
I'm not confusing anything because I didn't test this, @steff456 did.

@jnsebgosselin, any insights here?
@jproy does your keyboard look like this :

![image](https://user-images.githubusercontent.com/10170372/60998450-f40ba780-a326-11e9-873f-f8b4003f12ec.png)

versus this for the english keyboard :

![image](https://user-images.githubusercontent.com/10170372/60998620-4b117c80-a327-11e9-812b-ed12093d93fc.png)

@steff456 Can you comment out this block of code in `codeeditor.py` and test again if this bug is still occurring please. Thanks!

```
def event(self, event):
    """Qt method override."""
    if event.type() == QEvent.ShortcutOverride:
        event.ignore()
        return False
    else:
        return super(CodeEditor, self).event(event)
``` 
@steff456 If the bug still occur when testing the above (which I really hope it does...), can you test again but with commenting these lines in the `codeeditor.py` :

```
self.editor_extensions.add(CloseQuotesExtension())
self.editor_extensions.add(CloseBracketsExtension())
```

And replacing this line in `spyder.plugins.editor.extensions.manager.py`:

`return self._extensions[name_or_klass]`

by

`return self._extensions.get(name_or_klass, None)`

Thanks!
@jnsebgosselin the first option doesn't fix the bug, the second one does but now the editor does not close any bracket.

![image](https://user-images.githubusercontent.com/20992645/61022491-a4030400-a36b-11e9-8c95-d90b7efb9bb0.png)



> @jnsebgosselin the first option doesn't fix the bug, the second one does but now the editor does not close any bracket.
> 
> ![image](https://user-images.githubusercontent.com/20992645/61022491-a4030400-a36b-11e9-8c95-d90b7efb9bb0.png)

Ok thank you very much for your invaluable feedback. Now that we have been able to pinpoint the source of this issue, let me check and try to propose a valid fix for this.
@jnsebgosselin YES this is my french keyboard.
@jnsebgosselin OUPS, no, it is almost my keyboard. In fact, I have only three jeys on the left of the space bar, labelled "ctrl", "alt" and "cmd". It is named APPLE MAGIC KEYBOARD I think and has the numeric keypad included.

![image](https://user-images.githubusercontent.com/10170372/61051433-fa496480-a3b6-11e9-8862-12b1f737920a.png)

Resolving patch:
diff --git a/spyder/plugins/editor/extensions/closebrackets.py b/spyder/plugins/editor/extensions/closebrackets.py
--- a/spyder/plugins/editor/extensions/closebrackets.py
+++ b/spyder/plugins/editor/extensions/closebrackets.py
@@ -5,24 +5,18 @@
 # (see spyder/__init__.py for details)
 """This module contains the close quotes editor extension."""
 
-from qtpy.QtCore import Qt
 from qtpy.QtGui import QTextCursor
-
 from spyder.api.editorextension import EditorExtension
 
 
 class CloseBracketsExtension(EditorExtension):
     """Editor Extension for insert brackets automatically."""
-    BRACKETS_LIST = ["(", ")", "{", "}", "[", "]"]
-    BRACKETS_KEYS = [Qt.Key_ParenLeft, Qt.Key_ParenRight,
-                     Qt.Key_BraceLeft, Qt.Key_BraceRight,
-                     Qt.Key_BracketLeft, Qt.Key_BracketRight]
-    BRACKETS_CHAR = dict(zip(BRACKETS_KEYS, BRACKETS_LIST))
-    BRACKETS_LEFT = dict(zip(BRACKETS_KEYS[::2], BRACKETS_LIST[::2]))
-    BRACKETS_RIGHT = dict(zip(BRACKETS_KEYS[1::2], BRACKETS_LIST[1::2]))
-    BRACKETS_PAIR = {Qt.Key_ParenLeft: "()", Qt.Key_ParenRight: "()",
-                     Qt.Key_BraceLeft: "{}", Qt.Key_BraceRight: "{}",
-                     Qt.Key_BracketLeft: "[]", Qt.Key_BracketRight: "[]"}
+    BRACKETS_CHAR = ["(", ")", "{", "}", "[", "]"]
+    BRACKETS_LEFT = BRACKETS_CHAR[::2]
+    BRACKETS_RIGHT = BRACKETS_CHAR[1::2]
+    BRACKETS_PAIR = {"(": "()", ")": "()",
+                     "{": "{}", "}": "{}",
+                     "[": "[]", "]": "[]"}
 
     def on_state_changed(self, state):
         """Connect/disconnect sig_key_pressed signal."""
@@ -35,10 +29,13 @@ def _on_key_pressed(self, event):
         if event.isAccepted():
             return
 
-        key = event.key()
-        if key in self.BRACKETS_CHAR and self.enabled:
+        # It is necessary to use here the text of the event and not the key
+        # to avoid issues with international keyboards.
+        # See spyder-ide/spyder#9749
+        char = event.text()
+        if char in self.BRACKETS_CHAR and self.enabled:
             self.editor.completion_widget.hide()
-            self._autoinsert_brackets(key)
+            self._autoinsert_brackets(char)
             self.editor.document_did_change()
             event.accept()
 
@@ -50,8 +47,8 @@ def unmatched_brackets_in_line(self, text, closing_brackets_type=None):
         (')', ']' or '}')
         """
         if closing_brackets_type is None:
-            opening_brackets = self.BRACKETS_LEFT.values()
-            closing_brackets = self.BRACKETS_RIGHT.values()
+            opening_brackets = self.BRACKETS_LEFT
+            closing_brackets = self.BRACKETS_RIGHT
         else:
             closing_brackets = [closing_brackets_type]
             opening_brackets = [{')': '(', '}': '{',
@@ -71,10 +68,9 @@ def unmatched_brackets_in_line(self, text, closing_brackets_type=None):
                     return True
         return False
 
-    def _autoinsert_brackets(self, key):
+    def _autoinsert_brackets(self, char):
         """Control automatic insertation of brackets in various situations."""
-        char = self.BRACKETS_CHAR[key]
-        pair = self.BRACKETS_PAIR[key]
+        pair = self.BRACKETS_PAIR[char]
 
         line_text = self.editor.get_text('sol', 'eol')
         line_to_cursor = self.editor.get_text('sol', 'cursor')
@@ -89,9 +85,9 @@ def _autoinsert_brackets(self, key):
             cursor.movePosition(QTextCursor.Left, QTextCursor.KeepAnchor,
                                 len(text))
             self.editor.setTextCursor(cursor)
-        elif key in self.BRACKETS_LEFT:
+        elif char in self.BRACKETS_LEFT:
             if (not trailing_text or
-                    trailing_text[0] in self.BRACKETS_RIGHT.values() or
+                    trailing_text[0] in self.BRACKETS_RIGHT or
                     trailing_text[0] in [',', ':', ';']):
                 # Automatic insertion of brackets
                 self.editor.insert_text(pair)
@@ -101,7 +97,7 @@ def _autoinsert_brackets(self, key):
                 self.editor.insert_text(char)
             if char in self.editor.signature_completion_characters:
                 self.editor.request_signature()
-        elif key in self.BRACKETS_RIGHT:
+        elif char in self.BRACKETS_RIGHT:
             if (self.editor.next_char() == char and
                     not self.editor.textCursor().atBlockEnd() and
                     not self.unmatched_brackets_in_line(


Test patch: