Repository: Textualize/textual

Issue:
(Shift/Ctrl)+Alt+Up/Down are reversed
1. Run `textual keys` in xterm
2. Press `ctrl-alt-Up`, see this instead:
```
Key(key='escape', character=None, name='escape', is_printable=False, aliases=['escape', 'ctrl+left_square_brace'])                                                                                                                                                                                                             
Key(key='ctrl+down', character=None, name='ctrl_down', is_printable=False)
```
3. Press `alt-shift-Down`:
```
Key(key='escape', character=None, name='escape', is_printable=False, aliases=['escape', 'ctrl+left_square_brace'])                                                                                                                                                                                                             
Key(key='shift+up', character=None, name='shift_up', is_printable=False)                                                                                                                                                                                                                                                       
```
4. Notice that anytime `alt`/`meta` is combined with another modifier, `up`/`down` are reversed


# Textual Diagnostics

## Versions

| Name    | Value  |
|---------|--------|
| Textual | 0.18.0 |
| Rich    | 13.3.3 |

## Python

| Name           | Value                                           |
|----------------|-------------------------------------------------|
| Version        | 3.11.2                                          |
| Implementation | CPython                                         |
| Compiler       | GCC 12.2.0                                      |
| Executable     | ~/textual/venv/bin/python |

## Operating System

| Name    | Value                                              |
|---------|----------------------------------------------------|
| System  | Linux                                              |
| Release | 6.1.0-2-amd64                                      |
| Version | `#1` SMP PREEMPT_DYNAMIC Debian 6.1.7-1 (2023-01-18) |

## Terminal

| Name                 | Value          |
|----------------------|----------------|
| Terminal Application | *Unknown*      |
| TERM                 | xterm-256color |
| COLORTERM            | *Not set*      |
| FORCE_COLOR          | *Not set*      |
| NO_COLOR             | *Not set*      |

## Rich Console options

| Name           | Value                |
|----------------|----------------------|
| size           | width=319, height=90 |
| legacy_windows | False                |
| min_width      | 1                    |
| max_width      | 319                  |
| is_terminal    | True                 |
| encoding       | utf-8                |
| max_height     | 90                   |
| justify        | None                 |
| overflow       | None                 |
| no_wrap        | False                |
| highlight      | None                 |
| markup         | None                 |
| height         | None                 |



Discussion:
Thank you for your issue. Give us a little time to review it.

PS. You might want to check the [FAQ](https://github.com/textualize/textual/blob/main/FAQ.md) if you haven't done so already.

This is an automated reply, generated by [FAQtory](https://github.com/willmcgugan/faqtory)
Possibly related. SHIFT+OPTION+(UP / DOWN) doesn't register as a key, but it does look like a key sequence is generated.

This must be a sequence we haven't parsed.
Hey @mistotebe, thanks for reporting this!
I'll be honest with you: I am still trying to set up my local machine in the correct way to be able to _reproduce_ the issue you are reporting. Only then will I be able to tackle your issue.

However, I think I have a pretty good guess of where the issue might be, if you indulge me and give it a go yourself.
There's a file `_ansi_sequences.py` which pairs escape codes with key combos.
I found a couple of suspicious pairs that appear to be in the wrong order.

Would you mind going to 

https://github.com/Textualize/textual/blob/6369c3790751098fbc075b22d594ed1cb8362343/src/textual/_ansi_sequences.py#L243-L244

and change those two lines to

```py
    "\x1b[1;8A": (Keys.Escape, Keys.ControlShiftUp),
    "\x1b[1;8B": (Keys.Escape, Keys.ControlShiftDown),
```

Similarly, just seven lines below that location, can you go to

https://github.com/Textualize/textual/blob/6369c3790751098fbc075b22d594ed1cb8362343/src/textual/_ansi_sequences.py#L250-L251

and change those two lines to

```py
    "\x1b[1;8A": (Keys.Escape, Keys.ControlShiftUp),
    "\x1b[1;8B": (Keys.Escape, Keys.ControlShiftDown),
```

If you _do_ give this a try, let me know if it fixed your issue!
Thanks for your help 🙏 
@rodrigogiraoserrao If you do `TEXTUAL_DEBUG=1` before any comment, it will write `keys.log` which contains the key data from stdin.



> @rodrigogiraoserrao If you do `TEXTUAL_DEBUG=1` before any comment, it will write `keys.log` which contains the key data from stdin.

I have no idea what this means. I should write `TEXTUAL_DEBUG=1` in an arbitrary location in the Textual codebase, immediately before an inline comment? And that does what?
It's an evironment variable. 

```
TEXTUAL_DEBUG=1 python my_app.py
```
Hi @rodrigogiraoserrao, yes, it seems some definitions in _ansi_sequences.py are swapped: `ctrl?alt?shift?+Up` is always `\e[<something>A` and `ctrl?alt?shift?+Down` are always `\e[<something>B` (you can see that for yourself running `cat -A`), where the mappings in `ANSI_SEQUENCES_KEYS` are mixed in that regard.
> Hi @rodrigogiraoserrao, yes, it seems some definitions in _ansi_sequences.py are swapped [...]

Yeah, exactly.
But were you able to swap them and the original problem was fixed?
Right, yeah a quick `sed -i -e '/[0-9]A/s/Down/Up/' -e '/[0-9]B/s/Up/Down/' _ansi_sequences.py` did that (6 lines affected).

Resolving patch:
diff --git a/src/textual/_ansi_sequences.py b/src/textual/_ansi_sequences.py
--- a/src/textual/_ansi_sequences.py
+++ b/src/textual/_ansi_sequences.py
@@ -210,8 +210,8 @@
     "\x1b[1;3F": (Keys.Escape, Keys.End),
     "\x1b[1;3H": (Keys.Escape, Keys.Home),
     # Alt+shift+number.
-    "\x1b[1;4A": (Keys.Escape, Keys.ShiftDown),
-    "\x1b[1;4B": (Keys.Escape, Keys.ShiftUp),
+    "\x1b[1;4A": (Keys.Escape, Keys.ShiftUp),
+    "\x1b[1;4B": (Keys.Escape, Keys.ShiftDown),
     "\x1b[1;4C": (Keys.Escape, Keys.ShiftRight),
     "\x1b[1;4D": (Keys.Escape, Keys.ShiftLeft),
     "\x1b[1;4F": (Keys.Escape, Keys.ShiftEnd),
@@ -240,15 +240,15 @@
     "\x1b[1;6F": (Keys.ControlShiftEnd,),
     "\x1b[1;6H": (Keys.ControlShiftHome,),
     # Control + Meta + arrows.
-    "\x1b[1;7A": (Keys.Escape, Keys.ControlDown),
-    "\x1b[1;7B": (Keys.Escape, Keys.ControlUp),
+    "\x1b[1;7A": (Keys.Escape, Keys.ControlUp),
+    "\x1b[1;7B": (Keys.Escape, Keys.ControlDown),
     "\x1b[1;7C": (Keys.Escape, Keys.ControlRight),
     "\x1b[1;7D": (Keys.Escape, Keys.ControlLeft),
     "\x1b[1;7F": (Keys.Escape, Keys.ControlEnd),
     "\x1b[1;7H": (Keys.Escape, Keys.ControlHome),
     # Meta + Shift + arrows.
-    "\x1b[1;8A": (Keys.Escape, Keys.ControlShiftDown),
-    "\x1b[1;8B": (Keys.Escape, Keys.ControlShiftUp),
+    "\x1b[1;8A": (Keys.Escape, Keys.ControlShiftUp),
+    "\x1b[1;8B": (Keys.Escape, Keys.ControlShiftDown),
     "\x1b[1;8C": (Keys.Escape, Keys.ControlShiftRight),
     "\x1b[1;8D": (Keys.Escape, Keys.ControlShiftLeft),
     "\x1b[1;8F": (Keys.Escape, Keys.ControlShiftEnd),


Test patch: