From 9ea3014c591e5057cb00e95cdd40c35e60276a66 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 7 Apr 2023 15:23:09 +0200 Subject: [PATCH 01/53] The keyboard controller now correctly processes IBF even if OBF is set, fixes AMIBIOS 6.x machines such as the Supermicro P6SBA. --- src/device/keyboard_at.c | 51 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 4035a8fc6..7ab2d111f 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -823,33 +823,32 @@ kbd_poll(void *priv) break; /* Process commands and/or monitor the attached devices. */ case KBC_STATE_NORMAL: - if (!(dev->status & STAT_OFULL)) { - if (dev->status & STAT_IFULL) { + /* Always process IBF, even if OBF is set. */ + if (dev->status & STAT_IFULL) { + dev->status &= ~STAT_IFULL; + if ((dev->status & STAT_CD) || dev->want60) + kbc_process_cmd(dev); + else if (!(dev->status & STAT_CD) && !dev->want60) { dev->status &= ~STAT_IFULL; - if ((dev->status & STAT_CD) || dev->want60) - kbc_process_cmd(dev); - else if (!(dev->status & STAT_CD) && !dev->want60) { - dev->status &= ~STAT_IFULL; - set_enable_kbd(dev, 1); - kbc_queue_reset(4); - dev->key_wantcmd = 1; - dev->key_dat = dev->ib; - dev->kbc_state = KBC_STATE_KBD; - } - } else { - if (key_ctrl_queue_start != key_ctrl_queue_end) { - kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); - add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; - } else if (mouse_enabled && (dev->out_new_mouse != -1)) { - kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse); - add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); - dev->out_new_mouse = -1; - } else if (!(dev->mem[0x20] & 0x10) && (dev->out_new != -1)) { - kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new); - add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); - dev->out_new = -1; - } + set_enable_kbd(dev, 1); + kbc_queue_reset(4); + dev->key_wantcmd = 1; + dev->key_dat = dev->ib; + dev->kbc_state = KBC_STATE_KBD; + } + } else if (!(dev->status & STAT_OFULL)) { + if (key_ctrl_queue_start != key_ctrl_queue_end) { + kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); + add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; + } else if (mouse_enabled && (dev->out_new_mouse != -1)) { + kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse); + add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); + dev->out_new_mouse = -1; + } else if (!(dev->mem[0x20] & 0x10) && (dev->out_new != -1)) { + kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new); + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; } } break; From 1c8fd2c7fcd317c1d4ea553bb72e431cf5b05a1d Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 7 Apr 2023 23:36:02 +0200 Subject: [PATCH 02/53] Rewritten the AT KBC polling, PS/2 is coming soon. --- src/device/keyboard_at.c | 148 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 146 insertions(+), 2 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 7ab2d111f..4179f5fd3 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -95,9 +95,13 @@ enum { KBC_STATE_RESET = 0, KBC_STATE_NORMAL, + KBC_STATE_KBC_OUT, + KBC_STATE_KBC_PARAM, KBC_STATE_KBD, KBC_STATE_MOUSE }; +#define KBC_STATE_SCAN_KBD KBC_STATE_KBD +#define KBC_STATE_SCAN_MOUSE KBC_STATE_MOUSE typedef struct { uint8_t command, status, ib, out, @@ -584,6 +588,7 @@ static const scancode scancode_set3[512] = { static void add_data_kbd(uint16_t val); +// #define ENABLE_KEYBOARD_AT_LOG 1 #ifdef ENABLE_KEYBOARD_AT_LOG int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; @@ -804,6 +809,117 @@ set_enable_mouse(atkbd_t *dev, uint8_t enable) dev->mem[0x20] |= (enable ? 0x00 : 0x20); } +static void +kbc_ibf_process(atkbd_t *dev) +{ + /* IBF set, process both commands and data. */ + dev->status &= ~STAT_IFULL; + dev->kbc_state = KBC_STATE_NORMAL; + if (dev->status & STAT_CD) + kbc_process_cmd(dev); + else { + set_enable_kbd(dev, 1); + kbc_queue_reset(4); + dev->key_wantcmd = 1; + dev->key_dat = dev->ib; + dev->kbc_state = KBC_STATE_SCAN_KBD; + } +} + +static void +kbc_scan_kbd_at(atkbd_t *dev) +{ + if (!(dev->mem[0x20] & 0x10)) { + /* Both OBF and IBF clear and keyboard is enabled. */ + /* XT mode. */ + if (dev->mem[0x20] & 0x20) { + if (dev->out_new != -1) { + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_NORMAL; + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + /* AT mode. */ + } else { + // dev->t = dev->mem[0x28]; + if (dev->mem[0x2e] != 0x00) { + // if (!(dev->t & 0x02)) + // return; + dev->mem[0x2e] = 0x00; + } + dev->output_port &= 0xbf; + if (dev->out_new != -1) { + /* In our case, we never have noise on the line, so we can simplify this. */ + /* Read data from the keyboard. */ + if (dev->mem[0x20] & 0x40) { + if ((dev->mem[0x20] & 0x08) || (dev->input_port & 0x80)) + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->mem[0x2d] = (dev->out_new == 0xf0) ? 0x80 : 0x00; + } else + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_NORMAL; + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + } + } +} + +static void +kbc_poll_at(atkbd_t *dev) +{ + switch (dev->kbc_state) { + case KBC_STATE_RESET: + if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + break; + case KBC_STATE_NORMAL: + if (dev->status & STAT_OFULL) { + /* OBF set, wait until it is cleared but still process commands. */ + if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD)) { + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + } else if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else + kbc_scan_kbd_at(dev); + break; + case KBC_STATE_KBC_OUT: + /* Keyboard controller command want to output multiple bytes. */ + if (dev->status & STAT_IFULL) { + /* Data from host aborts dumping. */ + dev->kbc_state = KBC_STATE_NORMAL; + kbc_ibf_process(dev); + } + /* Do not continue dumping until OBF is clear. */ + if (!(dev->status & STAT_OFULL)) { + kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); + add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; + if (key_ctrl_queue_start == key_ctrl_queue_end) + dev->kbc_state = KBC_STATE_NORMAL; + } + break; + case KBC_STATE_KBC_PARAM: + /* Keyboard controller command wants data, wait for said data. */ + if (dev->status & STAT_IFULL) { + /* Command written, abort current command. */ + if (dev->status & STAT_CD) + dev->kbc_state = KBC_STATE_NORMAL; + + dev->status &= ~STAT_IFULL; + kbc_process_cmd(dev); + } + break; + case KBC_STATE_SCAN_KBD: + kbc_scan_kbd_at(dev); + break; + } +} + /* TODO: State machines for controller, keyboard, and mouse. */ static void kbd_poll(void *priv) @@ -815,14 +931,19 @@ kbd_poll(void *priv) mouse_enabled = !(dev->mem[0x20] & 0x20) && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF); - switch (dev->kbc_state) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) + kbc_poll_at(dev); + else switch (dev->kbc_state) { /* Reset state. */ case KBC_STATE_RESET: - if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) + if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { + dev->status &= ~STAT_IFULL; kbc_process_cmd(dev); + } break; /* Process commands and/or monitor the attached devices. */ case KBC_STATE_NORMAL: + case KBC_STATE_KBC_PARAM: /* Always process IBF, even if OBF is set. */ if (dev->status & STAT_IFULL) { dev->status &= ~STAT_IFULL; @@ -1408,6 +1529,7 @@ write64_generic(void *priv, uint8_t val) if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { kbd_log("ATkbc: write mouse output buffer\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; } break; @@ -1417,6 +1539,7 @@ write64_generic(void *priv, uint8_t val) set_enable_mouse(dev, 1); kbc_queue_reset(3); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; case 0xf0 ... 0xff: @@ -1453,6 +1576,7 @@ write60_ami(void *priv, uint8_t val) if (dev->secr_phase == 1) { dev->mem_addr = val; dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; dev->secr_phase = 2; } else if (dev->secr_phase == 2) { dev->mem[dev->mem_addr] = val; @@ -1489,11 +1613,13 @@ write64_ami(void *priv, uint8_t val) case 0x40 ... 0x5f: kbd_log("ATkbc: AMI - alias write to %08X\n", dev->command); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; case 0xa0: /* copyright message */ kbc_queue_add(dev, 0x28, 0); kbc_queue_add(dev, 0x00, 0); + dev->kbc_state = KBC_STATE_KBC_OUT; break; case 0xa1: /* get controller version */ @@ -1548,6 +1674,7 @@ write64_ami(void *priv, uint8_t val) } else { kbd_log("ATkbc: get extended controller RAM\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; } return 0; @@ -1590,6 +1717,7 @@ write64_ami(void *priv, uint8_t val) } else { kbd_log("ATkbc: set extended controller RAM\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; dev->secr_phase = 1; } return 0; @@ -1630,6 +1758,7 @@ write64_ami(void *priv, uint8_t val) case 0xc1: /* write input port */ kbd_log("ATkbc: AMI MegaKey - write input port\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; case 0xc4: @@ -1764,6 +1893,7 @@ write64_quadtel(void *priv, uint8_t val) case 0xcf: /*??? - sent by MegaPC BIOS*/ kbd_log("ATkbc: ??? - sent by MegaPC BIOS\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; } @@ -1828,6 +1958,7 @@ write64_toshiba(void *priv, uint8_t val) case 0xb6: /* T3100e: Set colour / mono byte */ kbd_log("ATkbc: T3100e: Set colour / mono byte\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; case 0xb7: /* T3100e: Emulate PS/2 keyboard */ @@ -2072,6 +2203,10 @@ kbc_process_cmd(void *priv) if (dev->status & STAT_CD) { /* Controller command. */ dev->want60 = 0; + dev->kbc_state = KBC_STATE_NORMAL; + + /* Clear the keyboard controller queue. */ + kbc_queue_reset(0); switch (dev->ib) { /* Read data from KBC memory. */ @@ -2082,6 +2217,7 @@ kbc_process_cmd(void *priv) /* Write data to KBC memory. */ case 0x60 ... 0x7f: dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xaa: /* self-test */ @@ -2167,6 +2303,7 @@ kbc_process_cmd(void *priv) kbc_queue_add(dev, cmd_ac_conv[dev->mem[i + 0x20] & 0x0f], 0); kbc_queue_add(dev, 0x39, 0); } + dev->kbc_state = KBC_STATE_KBC_OUT; } break; @@ -2183,6 +2320,7 @@ kbc_process_cmd(void *priv) case 0xc7: /* set port1 bits */ kbd_log("ATkbc: Phoenix - set port1 bits\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xca: /* read keyboard mode */ @@ -2193,6 +2331,7 @@ kbc_process_cmd(void *priv) case 0xcb: /* set keyboard mode */ kbd_log("ATkbc: AMI - set keyboard mode\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xd0: /* read output port */ @@ -2206,11 +2345,13 @@ kbc_process_cmd(void *priv) case 0xd1: /* write output port */ kbd_log("ATkbc: write output port\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xd2: /* write keyboard output buffer */ kbd_log("ATkbc: write keyboard output buffer\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; break; case 0xdd: /* disable A20 address line */ @@ -2244,6 +2385,7 @@ kbc_process_cmd(void *priv) } else if (dev->want60) { /* Write data to controller. */ dev->want60 = 0; + dev->kbc_state = KBC_STATE_NORMAL; switch (dev->command) { case 0x60 ... 0x7f: @@ -2339,6 +2481,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) } write_output(dev, val | 0x01); dev->want60 = 0; + dev->kbc_state = KBC_STATE_NORMAL; return; } break; @@ -2348,6 +2491,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) if (val == 0xd1) { kbd_log("ATkbc: write output port\n"); dev->want60 = 1; + dev->kbc_state = KBC_STATE_KBC_PARAM; dev->command = 0xd1; return; } From 289962319ff3d030f3e2186936dca8d129729e20 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 00:40:57 +0200 Subject: [PATCH 03/53] Rewritten the PS/2 poll (without the password security state, that is yet to be done) and enabled the PS/2 KBC IRQ latch on all PCI machines as well (it is present at the very least on Intel SIO and PIIX), fixes Windows for Workgroups 3.11 input, and reduced mouse polling to 255 Hz (the maximums supported by PS/2 mice). --- src/device/keyboard_at.c | 157 +++++++++++++++++++++++++-------------- src/device/mouse.c | 8 +- src/include/86box/pic.h | 1 + src/pic.c | 6 ++ 4 files changed, 113 insertions(+), 59 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 4179f5fd3..31bd91c53 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -920,78 +920,125 @@ kbc_poll_at(atkbd_t *dev) } } -/* TODO: State machines for controller, keyboard, and mouse. */ -static void -kbd_poll(void *priv) +static int +kbc_scan_kbd_ps2(atkbd_t *dev) { - atkbd_t *dev = (atkbd_t *) priv; - int mouse_enabled; + if (dev->out_new != -1) { + add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); + dev->out_new = -1; + dev->kbc_state = KBC_STATE_NORMAL; + return 1; + } - timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); + return 0; +} - mouse_enabled = !(dev->mem[0x20] & 0x20) && ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF); +static int +kbc_scan_aux_ps2(atkbd_t *dev) +{ + if (dev->out_new_mouse != -1) { + add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); + dev->out_new_mouse = -1; + dev->kbc_state = KBC_STATE_NORMAL; + return 1; + } - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) - kbc_poll_at(dev); - else switch (dev->kbc_state) { - /* Reset state. */ + return 0; +} + +static void +kbc_poll_ps2(atkbd_t *dev) +{ + switch (dev->kbc_state) { case KBC_STATE_RESET: if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { dev->status &= ~STAT_IFULL; kbc_process_cmd(dev); } break; - /* Process commands and/or monitor the attached devices. */ case KBC_STATE_NORMAL: - case KBC_STATE_KBC_PARAM: - /* Always process IBF, even if OBF is set. */ + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else if (!(dev->status & STAT_OFULL)) { + if (dev->mem[0x20] & 0x20) { + if (!(dev->mem[0x20] & 0x10)) { + dev->output_port &= 0xbf; + + if (kbc_scan_kbd_ps2(dev) == 0) { + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + } + } + } else { + dev->output_port &= 0xf7; + if (dev->mem[0x20] & 0x10) { + if (kbc_scan_aux_ps2(dev) == 0) { + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + } + } else { + dev->output_port &= 0xbf; + + if (kbc_scan_kbd_ps2(dev) == 0) { + if (kbc_scan_aux_ps2(dev) == 0) { + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + } + } + } + } + } + break; + case KBC_STATE_KBC_OUT: + /* Keyboard controller command want to output multiple bytes. */ if (dev->status & STAT_IFULL) { + /* Data from host aborts dumping. */ + dev->kbc_state = KBC_STATE_NORMAL; + kbc_ibf_process(dev); + } + /* Do not continue dumping until OBF is clear. */ + if (!(dev->status & STAT_OFULL)) { + kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); + add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; + if (key_ctrl_queue_start == key_ctrl_queue_end) + dev->kbc_state = KBC_STATE_NORMAL; + } + break; + case KBC_STATE_KBC_PARAM: + /* Keyboard controller command wants data, wait for said data. */ + if (dev->status & STAT_IFULL) { + /* Command written, abort current command. */ + if (dev->status & STAT_CD) + dev->kbc_state = KBC_STATE_NORMAL; + dev->status &= ~STAT_IFULL; - if ((dev->status & STAT_CD) || dev->want60) - kbc_process_cmd(dev); - else if (!(dev->status & STAT_CD) && !dev->want60) { - dev->status &= ~STAT_IFULL; - set_enable_kbd(dev, 1); - kbc_queue_reset(4); - dev->key_wantcmd = 1; - dev->key_dat = dev->ib; - dev->kbc_state = KBC_STATE_KBD; - } - } else if (!(dev->status & STAT_OFULL)) { - if (key_ctrl_queue_start != key_ctrl_queue_end) { - kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); - add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; - } else if (mouse_enabled && (dev->out_new_mouse != -1)) { - kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse); - add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); - dev->out_new_mouse = -1; - } else if (!(dev->mem[0x20] & 0x10) && (dev->out_new != -1)) { - kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new); - add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); - dev->out_new = -1; - } + kbc_process_cmd(dev); } break; - /* Wait for keyboard command response. */ - case KBC_STATE_KBD: - if (!(dev->mem[0x20] & 0x10) && (dev->out_new != -1)) { - kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new); - add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); - dev->out_new = -1; - dev->kbc_state = KBC_STATE_NORMAL; - } + case KBC_STATE_SCAN_KBD: + (void) kbc_scan_kbd_ps2(dev); break; - /* Wait for keyboard mouse response. */ - case KBC_STATE_MOUSE: - if (mouse_enabled && (dev->out_new_mouse != -1)) { - kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse); - add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); - dev->out_new_mouse = -1; - dev->kbc_state = KBC_STATE_NORMAL; - } + case KBC_STATE_SCAN_MOUSE: + (void) kbc_scan_aux_ps2(dev); break; } +} + +/* TODO: State machines for controller, keyboard, and mouse. */ +static void +kbd_poll(void *priv) +{ + atkbd_t *dev = (atkbd_t *) priv; + + timer_advance_u64(&dev->send_delay_timer, (100ULL * TIMER_USEC)); + + /* TODO: Use a fuction pointer for this (also needed to the AMI KBC mode switching) + and implement the password security state. */ + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) + kbc_poll_at(dev); + else + kbc_poll_ps2(dev); if (dev->reset_delay) { dev->reset_delay--; @@ -2520,7 +2567,7 @@ kbd_read(uint16_t port, void *priv) This also means that in AT mode, the IRQ is level-triggered. */ if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) picintc(1 << 1); - else if ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF) { + else if (pic_get_pci_flag() || ((dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF)) { /* PS/2 MCA: Latched as level-sensitive until port 0x60 is read (and with it, OBF is cleared), in accordance with the IBM PS/2 Model 80 Technical Reference Manual. */ kbc_irq(dev, dev->irq_levels, 0); diff --git a/src/device/mouse.c b/src/device/mouse.c index 46bbc4ac2..13d9999c7 100644 --- a/src/device/mouse.c +++ b/src/device/mouse.c @@ -152,8 +152,8 @@ mouse_close(void) static void mouse_timer_poll(void *priv) { - /* Poll at 3600 Hz. */ - timer_on_auto(&mouse_timer, 277.0 + (7.0 / 9.0)); + /* Poll at 255 Hz, maximum supported by PS/2 mic. */ + timer_on_auto(&mouse_timer, 1000000.0 / 255.0); #ifdef USE_GDBSTUB /* avoid a KBC FIFO overflow when CPU emulation is stalled */ if (gdbstub_step == GDBSTUB_EXEC) @@ -186,8 +186,8 @@ mouse_reset(void) timer_add(&mouse_timer, mouse_timer_poll, NULL, 0); - /* Poll at 3600 Hz. */ - timer_on_auto(&mouse_timer, 277.0 + (7.0 / 9.0)); + /* Poll at 255 Hz, maximum supported by PS/2 mic. */ + timer_on_auto(&mouse_timer, 1000000.0 / 255.0); } /* Callback from the hardware driver. */ diff --git a/src/include/86box/pic.h b/src/include/86box/pic.h index 318ce2fad..52bc920e4 100644 --- a/src/include/86box/pic.h +++ b/src/include/86box/pic.h @@ -43,6 +43,7 @@ extern void pic_elcr_write(uint16_t port, uint8_t val, void *priv); extern uint8_t pic_elcr_read(uint16_t port, void *priv); extern void pic_set_shadow(int sh); +extern int pic_get_pci_flag(void); extern void pic_set_pci_flag(int pci); extern void pic_set_pci(void); extern void pic_init(void); diff --git a/src/pic.c b/src/pic.c index bdff7f59c..9920a23e9 100644 --- a/src/pic.c +++ b/src/pic.c @@ -284,6 +284,12 @@ pic_set_shadow(int sh) shadow = sh; } +int +pic_get_pci_flag(void) +{ + return pic_pci; +} + void pic_set_pci_flag(int pci) { From c786eb0924da4fda5f755f300dfe17c743826bc0 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 01:42:09 +0200 Subject: [PATCH 04/53] Fixed input port intialization, fixes the logo on the Epson Action PC. --- src/device/keyboard_at.c | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 31bd91c53..0d433188e 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2287,7 +2287,9 @@ kbc_process_cmd(void *priv) } else { if (dev->kbc_state != KBC_STATE_RESET) { kbd_log("ATkbc: self-test reinitialization\n"); - dev->input_port |= 0xff; + /* Yes, the firmware has an OR, but we need to make sure to keep any forcibly lowered bytes lowered. */ + /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */ + dev->input_port = dev->input_port & 0xff; write_output(dev, 0xcf); } @@ -2309,27 +2311,6 @@ kbc_process_cmd(void *priv) dev->kbc_state = KBC_STATE_NORMAL; add_to_kbc_queue_front(dev, 0x55, 0, 0x00); - -#if 0 - write_output(dev, ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x4b : 0xcf); - - /* Always reinitialize all queues - the real hardware pulls keyboard and mouse - clocks high, which stops keyboard scanning. */ - kbd_log("ATkbc: self-test reinitialization\n"); - dev->out_new = dev->out_new_mouse = -1; - for (i = 0; i < 3; i++) - kbc_queue_reset(i); - keyboard_scan = 0; - mouse_scan = 0; - kbd_last_scan_code = 0x00; - dev->status &= ~STAT_OFULL; - - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) - write_cmd(dev, 0x30 | STAT_SYSFLAG); - else - write_cmd(dev, 0x10 | STAT_SYSFLAG); - add_to_kbc_queue_front(dev, 0x55, 0, 0x00); -#endif break; case 0xab: /* interface test */ From cdf413c985b165c8e3446255406f8727321ced37 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 02:09:47 +0200 Subject: [PATCH 05/53] Gave the Epson Action PC 2600 a PS/2 mouse port, per the manual. --- src/machine/m_at_386dx_486.c | 2 +- src/machine/machine_table.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 0ee7b51a2..8b743af2f 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -1657,7 +1657,7 @@ machine_at_actionpc2600_init(const machine_t *model) device_add(&umc_8886af_device); device_add(&um8669f_device); device_add(&intel_flash_bxt_device); - device_add(&keyboard_at_ami_device); + device_add(&keyboard_ps2_ami_device); return ret; } diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 9047342e8..3a11769f8 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -7036,7 +7036,7 @@ const machine_t machines[] = { .min_multi = 0, .max_multi = 0 }, - .bus_flags = MACHINE_PCI, + .bus_flags = MACHINE_PS2_PCI, .flags = MACHINE_IDE_DUAL | MACHINE_APM, .ram = { .min = 1024, From c0be988ec4f3fbbb2f33a5aab971d1a25537909e Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 02:44:12 +0200 Subject: [PATCH 06/53] Added the TriGem AMI keyboard controllers. --- src/machine/m_at_386dx_486.c | 8 ++++---- src/machine/m_at_socket5.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 8b743af2f..ee54758e2 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -220,7 +220,7 @@ machine_at_spc6000a_init(const machine_t *model) if (fdc_type == FDC_INTERNAL) device_add(&fdc_at_device); - device_add(&keyboard_at_samsung_device); + device_add(&keyboard_at_ami_device); return ret; } @@ -1657,7 +1657,7 @@ machine_at_actionpc2600_init(const machine_t *model) device_add(&umc_8886af_device); device_add(&um8669f_device); device_add(&intel_flash_bxt_device); - device_add(&keyboard_ps2_ami_device); + device_add(&keyboard_ps2_tg_ami_device); return ret; } @@ -1782,7 +1782,7 @@ machine_at_tg486gp_init(const machine_t *model) device_add(&ali1435_device); device_add(&sst_flash_29ee010_device); - device_add(&keyboard_ps2_ami_device); + device_add(&keyboard_ps2_tg_ami_device); return ret; } @@ -1806,7 +1806,7 @@ machine_at_tg486g_init(const machine_t *model) device_add(&sis_85c471_device); device_add(&ide_isa_device); device_add(&fdc37c651_ide_device); - device_add(&keyboard_ps2_intel_ami_pci_device); + device_add(&keyboard_ps2_tg_ami_pci_device); return ret; } diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 842554713..9a45e71bf 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -237,7 +237,7 @@ machine_at_hawk_init(const machine_t *model) pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_tg_ami_pci_device); device_add(&i430fx_device); device_add(&piix_device); device_add(&fdc37c665_device); From d4b57298ad8d6503d7c679d7e0fc8a4e849d7bf8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 8 Apr 2023 03:11:53 +0200 Subject: [PATCH 07/53] Fixed the keyboard controller reset state, fixes Xi8088. --- src/device/keyboard_at.c | 119 ++++++++++++++++++++++++----------- src/include/86box/keyboard.h | 5 +- 2 files changed, 88 insertions(+), 36 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 0d433188e..e440b3b07 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -37,7 +37,6 @@ #include <86box/mem.h> #include <86box/device.h> #include <86box/machine.h> -#include <86box/m_xt_xi8088.h> #include <86box/m_at_t3100e.h> #include <86box/fdd.h> #include <86box/fdc.h> @@ -81,15 +80,15 @@ #define KBC_VEN_IBM_MCA 0x08 #define KBC_VEN_QUADTEL 0x0c #define KBC_VEN_TOSHIBA 0x10 -#define KBC_VEN_XI8088 0x14 -#define KBC_VEN_IBM_PS1 0x18 -#define KBC_VEN_ACER 0x1c -#define KBC_VEN_INTEL_AMI 0x20 -#define KBC_VEN_OLIVETTI 0x24 -#define KBC_VEN_NCR 0x28 -#define KBC_VEN_SAMSUNG 0x2c -#define KBC_VEN_ALI 0x30 -#define KBC_VEN_PHOENIX 0x3c +#define KBC_VEN_IBM_PS1 0x14 +#define KBC_VEN_ACER 0x18 +#define KBC_VEN_INTEL_AMI 0x1c +#define KBC_VEN_OLIVETTI 0x20 +#define KBC_VEN_NCR 0x24 +#define KBC_VEN_PHOENIX 0x28 +#define KBC_VEN_ALI 0x2c +#define KBC_VEN_TG 0x30 +#define KBC_VEN_TG_GREEN 0x34 #define KBC_VEN_MASK 0x3c enum { @@ -109,9 +108,9 @@ typedef struct { output_port, old_output_port, key_command, output_locked, ami_stat, want60, key_wantdata, ami_flags, key_wantcmd, key_dat, mouse_wantcmd, mouse_dat, - kbc_state, kbd_state, mouse_state, pad; + kbc_state, kbd_state, mouse_state, pci; - uint16_t irq_levels, pad0; + uint16_t irq_levels, pad; uint8_t mem[0x100]; @@ -713,7 +712,8 @@ add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_ { uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) + if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) || + (kbc_ven == KBC_VEN_TG_GREEN) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) stat_hi |= ((dev->input_port & 0x80) ? 0x10 : 0x00); else stat_hi |= 0x10; @@ -870,9 +870,10 @@ kbc_poll_at(atkbd_t *dev) { switch (dev->kbc_state) { case KBC_STATE_RESET: - if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { - dev->status &= ~STAT_IFULL; - kbc_process_cmd(dev); + if (dev->status & STAT_IFULL) { + dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) + kbc_process_cmd(dev); } break; case KBC_STATE_NORMAL: @@ -951,9 +952,10 @@ kbc_poll_ps2(atkbd_t *dev) { switch (dev->kbc_state) { case KBC_STATE_RESET: - if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD) && (dev->ib == 0xaa)) { - dev->status &= ~STAT_IFULL; - kbc_process_cmd(dev); + if (dev->status & STAT_IFULL) { + dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; + if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) + kbc_process_cmd(dev); } break; case KBC_STATE_NORMAL: @@ -1451,13 +1453,15 @@ write_cmd(atkbd_t *dev, uint8_t val) /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. The AMIKEY firmware apparently uses this bit for something else. */ - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { + if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) || + (kbc_ven == KBC_VEN_TG_GREEN) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) { keyboard_mode &= ~CCB_PCMODE; kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); } - if ((kbc_ven == KBC_VEN_AMI) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { + if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) || + (kbc_ven == KBC_VEN_TG_GREEN) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { /* Update the output port to mirror the IBF and OBF bits, if active. */ write_output(dev, (dev->output_port & 0x0f) | ((val & 0x03) << 4) | ((val & 0x20) ? 0xc0 : 0x00)); } @@ -1559,7 +1563,16 @@ write64_generic(void *priv, uint8_t val) 0, 0x00); dev->input_port = ((dev->input_port + 1) & 3) | (dev->input_port & 0xfc); } else { - if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) + if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN)) { + /* Bit 3, 2: + 1, 1: TriGem logo; + 1, 0: Garbled logo; + 0, 1: Epson logo; + 0, 0: Generic AMI logo. */ + if (dev->pci) + fixed_bits |= 8; + add_to_kbc_queue_front(dev, dev->input_port | fixed_bits, 0, 0x00); + } else if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && ((dev->flags & KBC_VEN_MASK) != KBC_VEN_INTEL_AMI)) #if 0 add_to_kbc_queue_front(dev, (dev->input_port | fixed_bits) & (((dev->flags & KBC_VEN_MASK) == KBC_VEN_ACER) ? 0xeb : 0xef), 0, 0x00); @@ -1671,18 +1684,25 @@ write64_ami(void *priv, uint8_t val) case 0xa1: /* get controller version */ kbd_log("ATkbc: AMI - get controller version\n"); - if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + if ((kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN)) + add_to_kbc_queue_front(dev, 'Z', 0, 0x00); + else if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { if (kbc_ven == KBC_VEN_ALI) add_to_kbc_queue_front(dev, 'F', 0, 0x00); else if ((dev->flags & KBC_VEN_MASK) == KBC_VEN_INTEL_AMI) add_to_kbc_queue_front(dev, '5', 0, 0x00); - else if (is_pentium) + else if (cpu_64bitbus) add_to_kbc_queue_front(dev, 'R', 0, 0x00); + else if (is486) + add_to_kbc_queue_front(dev, 'P', 0, 0x00); else add_to_kbc_queue_front(dev, 'H', 0, 0x00); - } else if (is386 && !is486) - add_to_kbc_queue_front(dev, 'B', 0, 0x00); - else if (!is386) + } else if (is386 && !is486) { + if (cpu_16bitbus) + add_to_kbc_queue_front(dev, 'D', 0, 0x00); + else + add_to_kbc_queue_front(dev, 'B', 0, 0x00); + } else if (!is386) add_to_kbc_queue_front(dev, '8', 0, 0x00); else add_to_kbc_queue_front(dev, 'F', 0, 0x00); @@ -2583,7 +2603,7 @@ kbd_reset(void *priv) dev->key_wantdata = 0; /* Set up the correct Video Type bits. */ - if ((kbc_ven == KBC_VEN_XI8088) || (kbc_ven == KBC_VEN_ACER)) + if (!is286 || (kbc_ven == KBC_VEN_ACER)) dev->input_port = video_is_mda() ? 0xb0 : 0xf0; else dev->input_port = video_is_mda() ? 0xf0 : 0xb0; @@ -2664,6 +2684,7 @@ kbd_init(const device_t *info) memset(dev, 0x00, sizeof(atkbd_t)); dev->flags = info->local; + dev->pci = !!(info->flags & DEVICE_PCI); video_reset(gfxcard[0]); kbd_reset(dev); @@ -2683,7 +2704,6 @@ kbd_init(const device_t *info) case KBC_VEN_GENERIC: case KBC_VEN_NCR: case KBC_VEN_IBM_PS1: - case KBC_VEN_XI8088: dev->write64_ven = write64_generic; break; @@ -2693,8 +2713,9 @@ kbd_init(const device_t *info) case KBC_VEN_AMI: case KBC_VEN_INTEL_AMI: - case KBC_VEN_SAMSUNG: case KBC_VEN_ALI: + case KBC_VEN_TG: + case KBC_VEN_TG_GREEN: dev->write60_ven = write60_ami; dev->write64_ven = write64_ami; break; @@ -2748,11 +2769,11 @@ const device_t keyboard_at_ami_device = { .config = NULL }; -const device_t keyboard_at_samsung_device = { - .name = "PC/AT Keyboard (Samsung)", - .internal_name = "keyboard_at_samsung", +const device_t keyboard_at_tg_ami_device = { + .name = "PC/AT Keyboard (TriGem AMI)", + .internal_name = "keyboard_at_tg_ami", .flags = 0, - .local = KBC_TYPE_ISA | KBC_VEN_SAMSUNG, + .local = KBC_TYPE_ISA | KBC_VEN_TG, .init = kbd_init, .close = kbd_close, .reset = kbd_reset, @@ -2850,7 +2871,7 @@ const device_t keyboard_ps2_xi8088_device = { .name = "PS/2 Keyboard (Xi8088)", .internal_name = "keyboard_ps2_xi8088", .flags = 0, - .local = KBC_TYPE_PS2_1 | KBC_VEN_XI8088, + .local = KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, .init = kbd_init, .close = kbd_close, .reset = kbd_reset, @@ -2874,6 +2895,20 @@ const device_t keyboard_ps2_ami_device = { .config = NULL }; +const device_t keyboard_ps2_tg_ami_device = { + .name = "PS/2 Keyboard (TriGem AMI)", + .internal_name = "keyboard_ps2_tg_ami", + .flags = 0, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_ps2_mca_device = { .name = "PS/2 Keyboard", .internal_name = "keyboard_ps2_mca", @@ -2972,6 +3007,20 @@ const device_t keyboard_ps2_intel_ami_pci_device = { .config = NULL }; +const device_t keyboard_ps2_tg_ami_pci_device = { + .name = "PS/2 Keyboard (TriGem AMI)", + .internal_name = "keyboard_ps2_tg_ami_pci", + .flags = DEVICE_PCI, + .local = KBC_TYPE_PS2_NOREF | KBC_VEN_TG, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_ps2_acer_pci_device = { .name = "PS/2 Keyboard (Acer 90M002A)", .internal_name = "keyboard_ps2_acer_pci", diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 2ff0325cb..767ffdca7 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -159,7 +159,7 @@ extern const device_t keyboard_xt_zenith_device; extern const device_t keyboard_xtclone_device; extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; -extern const device_t keyboard_at_samsung_device; +extern const device_t keyboard_at_tg_ami_device; extern const device_t keyboard_at_toshiba_device; extern const device_t keyboard_at_olivetti_device; extern const device_t keyboard_at_ncr_device; @@ -168,6 +168,8 @@ extern const device_t keyboard_ps2_ps1_device; extern const device_t keyboard_ps2_ps1_pci_device; extern const device_t keyboard_ps2_xi8088_device; extern const device_t keyboard_ps2_ami_device; +extern const device_t keyboard_ps2_tg_ami_device; +extern const device_t keyboard_ps2_tg_ami_green_device; extern const device_t keyboard_ps2_olivetti_device; extern const device_t keyboard_ps2_mca_device; extern const device_t keyboard_ps2_mca_2_device; @@ -177,6 +179,7 @@ extern const device_t keyboard_ps2_ami_pci_device; extern const device_t keyboard_ps2_intel_ami_pci_device; extern const device_t keyboard_ps2_acer_pci_device; extern const device_t keyboard_ps2_ali_pci_device; +extern const device_t keyboard_ps2_tg_ami_pci_device; #endif /*EMU_DEVICE_H*/ extern void keyboard_init(void); From 05b3cd16078497a326bb604d475289f1719dc96d Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 7 Apr 2023 22:33:53 -0300 Subject: [PATCH 08/53] qt: Initial xkbcommon keyboard support for X11 --- .ci/build.sh | 4 +- .ci/static2dll.sh | 0 src/qt/CMakeLists.txt | 15 ++ src/qt/qt_mainwindow.cpp | 57 ++++--- src/qt/xkbcommon_keyboard.cpp | 258 ++++++++++++++++++++++++++++++ src/qt/xkbcommon_keyboard.hpp | 19 +++ src/qt/xkbcommon_x11_keyboard.cpp | 85 ++++++++++ src/qt/xkbcommon_x11_keyboard.hpp | 17 ++ 8 files changed, 432 insertions(+), 23 deletions(-) mode change 100755 => 100644 .ci/build.sh mode change 100755 => 100644 .ci/static2dll.sh create mode 100644 src/qt/xkbcommon_keyboard.cpp create mode 100644 src/qt/xkbcommon_keyboard.hpp create mode 100644 src/qt/xkbcommon_x11_keyboard.cpp create mode 100644 src/qt/xkbcommon_x11_keyboard.hpp diff --git a/.ci/build.sh b/.ci/build.sh old mode 100755 new mode 100644 index 9b4494c46..67320c2e2 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -584,7 +584,7 @@ else # ...and the ones we do want listed. Non-dev packages fill missing spots on the list. libpkgs="" longest_libpkg=0 - for pkg in libc6-dev libstdc++6 libopenal-dev libfreetype6-dev libx11-dev libsdl2-dev libpng-dev librtmidi-dev qtdeclarative5-dev libwayland-dev libevdev-dev libglib2.0-dev libslirp-dev libfaudio-dev libaudio-dev libjack-jackd2-dev libpipewire-0.3-dev libsamplerate0-dev libsndio-dev + for pkg in libc6-dev libstdc++6 libopenal-dev libfreetype6-dev libx11-dev libsdl2-dev libpng-dev librtmidi-dev qtdeclarative5-dev libwayland-dev libevdev-dev libxkbcommon-x11-dev libglib2.0-dev libslirp-dev libfaudio-dev libaudio-dev libjack-jackd2-dev libpipewire-0.3-dev libsamplerate0-dev libsndio-dev do libpkgs="$libpkgs $pkg:$arch_deb" length=$(echo -n $pkg | sed 's/-dev$//' | sed "s/qtdeclarative/qt/" | wc -c) @@ -1014,7 +1014,7 @@ else mkdir -p "$icon_dir" cp -rp "$icon_size" "$icon_dir/apps" done - project_icon=$(ls "$icon_base/"[0-9]*x[0-9]*/* | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)') + project_icon=$(find "$icon_base/"[0-9]*x[0-9]*/* -type f -name '*.png' -o -name '*.svg' | head -1 | grep -oP '/\K([^/]+)(?=\.[^\.]+$)') # Archive executable, while also stripping it if requested. mkdir -p archive_tmp/usr/local/bin diff --git a/.ci/static2dll.sh b/.ci/static2dll.sh old mode 100755 new mode 100644 diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 1cb26a239..0cce392a9 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -373,6 +373,21 @@ if (UNIX AND NOT APPLE AND NOT HAIKU) target_link_libraries(ui PUBLIC PkgConfig::LIBEVDEV) target_sources(ui PRIVATE evdev_mouse.cpp) endif() + pkg_check_modules(XKBCOMMON IMPORTED_TARGET xkbcommon) + if (XKBCOMMON_FOUND) + target_compile_definitions(ui PRIVATE XKBCOMMON) + target_link_libraries(ui PUBLIC PkgConfig::XKBCOMMON) + target_sources(ui PRIVATE xkbcommon_keyboard.cpp) + + if (X11_xcb_FOUND) + pkg_check_modules(XKBCOMMON_X11 IMPORTED_TARGET xkbcommon-x11) + if (XKBCOMMON_X11_FOUND) + target_compile_definitions(ui PRIVATE XKBCOMMON_X11) + target_link_libraries(ui PRIVATE X11::xcb PUBLIC PkgConfig::XKBCOMMON_X11) + target_sources(ui PRIVATE xkbcommon_x11_keyboard.cpp) + endif() + endif() + endif() find_package(ECM NO_MODULE) if (ECM_FOUND) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index f360a83e9..de7bceafb 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -96,8 +96,11 @@ extern int qt_nvr_save(void); #include "qt_util.hpp" #if defined __unix__ && !defined __HAIKU__ -# ifdef WAYLAND -# include "wl_mouse.hpp" +# ifdef XKBCOMMON +# include "xkbcommon_keyboard.hpp" +# ifdef XKBCOMMON_X11 +# include "xkbcommon_x11_keyboard.hpp" +# endif # endif # include # include @@ -648,6 +651,11 @@ MainWindow::MainWindow(QWidget *parent) } else { ui->actionCursor_Puck->setChecked(true); } + +#ifdef XKBCOMMON_X11 + if (QApplication::platformName().contains("xcb")) + xkbcommon_x11_init(); +#endif } void @@ -1504,29 +1512,36 @@ x11_keycode_to_keysym(uint32_t keycode) #elif defined(__HAIKU__) finalkeycode = be_to_xt[keycode]; #else - static Display *x11display = nullptr; - if (QApplication::platformName().contains("wayland")) { - selected_keycode = x11_to_xt_2; - } else if (QApplication::platformName().contains("eglfs")) { - keycode -= 8; - if (keycode <= 88) - finalkeycode = keycode; - else - finalkeycode = evdev_to_xt[keycode]; - } else if (!x11display) { - x11display = XOpenDisplay(nullptr); - if (XKeysymToKeycode(x11display, XK_Home) == 110) { - selected_keycode = x11_to_xt_2; - } else if (XKeysymToKeycode(x11display, XK_Home) == 69) { - selected_keycode = x11_to_xt_vnc; +# ifdef XKBCOMMON + if (xkbcommon_keymap) { + finalkeycode = xkbcommon_translate(keycode); + } else +# endif + { + static Display *x11display = nullptr; + if (QApplication::platformName().contains("eglfs")) { + keycode -= 8; + if (keycode <= 88) + finalkeycode = keycode; + else + finalkeycode = evdev_to_xt[keycode]; + } else { + if (QApplication::platformName().contains("wayland")) { + selected_keycode = x11_to_xt_2; + } else if (!x11display) { + x11display = XOpenDisplay(nullptr); + if (XKeysymToKeycode(x11display, XK_Home) == 110) { + selected_keycode = x11_to_xt_2; + } else if (XKeysymToKeycode(x11display, XK_Home) == 69) { + selected_keycode = x11_to_xt_vnc; + } + } + finalkeycode = selected_keycode[keycode]; } } - if (!QApplication::platformName().contains("eglfs")) - finalkeycode = selected_keycode[keycode]; #endif - if (rctrl_is_lalt && finalkeycode == 0x11D) { + if (rctrl_is_lalt && finalkeycode == 0x11D) finalkeycode = 0x38; - } return finalkeycode; } diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp new file mode 100644 index 000000000..1b4998b1f --- /dev/null +++ b/src/qt/xkbcommon_keyboard.cpp @@ -0,0 +1,258 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * xkbcommon keyboard input module. + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +extern "C" { +#include +}; + +#include +#include + +#define IS_HEX_DIGIT(c) ((((c) >= '0') && ((c) <= '9')) || (((c) >= 'A') && ((c) <= 'F')) || (((c) >= 'a') && ((c) <= 'f'))) + +std::unordered_map xkb_keycodes{ + {"ESC", 0x01}, + {"AE01", 0x02}, + {"AE02", 0x03}, + {"AE03", 0x04}, + {"AE04", 0x05}, + {"AE05", 0x06}, + {"AE06", 0x07}, + {"AE07", 0x08}, + {"AE08", 0x09}, + {"AE09", 0x0a}, + {"AE10", 0x0b}, + {"AE11", 0x0c}, + {"AE12", 0x0d}, + {"BKSP", 0x0e}, + + {"TAB", 0x0f}, + {"AD01", 0x10}, + {"AD02", 0x11}, + {"AD03", 0x12}, + {"AD04", 0x13}, + {"AD05", 0x14}, + {"AD06", 0x15}, + {"AD07", 0x16}, + {"AD08", 0x17}, + {"AD09", 0x18}, + {"AD10", 0x19}, + {"AD11", 0x1a}, + {"AD12", 0x1b}, + {"RTRN", 0x1c}, + + {"LCTL", 0x1d}, + {"AC01", 0x1e}, + {"AC02", 0x1f}, + {"AC03", 0x20}, + {"AC04", 0x21}, + {"AC05", 0x22}, + {"AC06", 0x23}, + {"AC07", 0x24}, + {"AC08", 0x25}, + {"AC09", 0x26}, + {"AC10", 0x27}, + {"AC11", 0x28}, + + {"TLDE", 0x29}, + {"LFSH", 0x2a}, + {"BKSL", 0x2b}, + {"AB01", 0x2c}, + {"AB02", 0x2d}, + {"AB03", 0x2e}, + {"AB04", 0x2f}, + {"AB05", 0x30}, + {"AB06", 0x31}, + {"AB07", 0x32}, + {"AB08", 0x33}, + {"AB09", 0x34}, + {"AB10", 0x35}, + {"RTSH", 0x36}, + + {"KPMU", 0x37}, + {"LALT", 0x38}, + {"SPCE", 0x39}, + {"CAPS", 0x3a}, + {"FK01", 0x3b}, + {"FK02", 0x3c}, + {"FK03", 0x3d}, + {"FK04", 0x3e}, + {"FK05", 0x3f}, + {"FK06", 0x40}, + {"FK07", 0x41}, + {"FK08", 0x42}, + {"FK09", 0x43}, + {"FK10", 0x44}, + + {"NMLK", 0x45}, + {"SCLK", 0x46}, + {"FK14", 0x46}, /* F14 as Scroll Lock */ + {"KP7", 0x47}, + {"KP8", 0x48}, + {"KP9", 0x49}, + {"KPSU", 0x4a}, + {"KP4", 0x4b}, + {"KP5", 0x4c}, + {"KP6", 0x4d}, + {"KPAD", 0x4e}, + {"KP1", 0x4f}, + {"KP2", 0x50}, + {"KP3", 0x51}, + {"KP0", 0x52}, + {"KPDL", 0x53}, + + {"LSGT", 0x56}, + {"FK11", 0x57}, + {"FK12", 0x58}, + + /* Japanese keys. */ + {"HKTG", 0x70}, /* hiragana-katakana toggle... */ + {"HIRA", 0x70}, /* ...and individual keys */ + {"KATA", 0x70}, + {"AB11", 0x73}, /* \_ and Brazilian /? */ + {"HENK", 0x79}, + {"MUHE", 0x7b}, + {"AE13", 0x7d}, /* \| */ + {"KPPT", 0x7e}, /* Brazilian Num. */ + {"I06", 0x7e}, /* alias of KPPT on keycodes/xfree86 (i.e. X11 forwarding) */ + + /* Korean keys. */ + {"HJCV", 0xf1}, /* hancha toggle */ + {"HNGL", 0xf2}, /* latin toggle */ + + {"KPEN", 0x11c}, + {"RCTL", 0x11d}, + {"KPDV", 0x135}, + {"PRSC", 0x137}, + {"SYRQ", 0x137}, + {"FK13", 0x137}, /* F13 as SysRq */ + {"RALT", 0x138}, + {"PAUS", 0x146}, /* special case */ + {"FK15", 0x146}, /* F15 as Pause */ + {"HOME", 0x147}, + {"UP", 0x148}, + {"PGUP", 0x149}, + {"LEFT", 0x14b}, + {"RGHT", 0x14d}, + {"END", 0x14f}, + {"DOWN", 0x150}, + {"PGDN", 0x151}, + {"INS", 0x152}, + {"DELE", 0x153}, + + {"LWIN", 0x15b}, + {"RWIN", 0x15c}, + {"COMP", 0x15d}, + + /* Multimedia keys, using Linux evdev-specific keycodes where required. Guideline is to try + and follow the Microsoft standard, then fill in some OEM-specific keys for redundancy sake. + Keys marked with # are not translated into evdev codes by the standard atkbd driver. */ + {"KPEQ", 0x59}, /* Num= */ + {"FRNT", 0x101}, /* # Logitech Task Select */ + {"I224", 0x105}, /* CHAT# => Messenger/Files */ + {"I190", 0x107}, /* REDO */ + {"UNDO", 0x108}, + {"PAST", 0x10a}, /* # Paste */ + {"I185", 0x10b}, /* SCROLLUP# => normal speed */ + {"I173", 0x110}, /* PREVIOUSSONG */ + {"FIND", 0x112}, /* # Logitech */ + {"I156", 0x113}, /* PROG1# => Word */ + {"I157", 0x114}, /* PROG2# => Excel */ + {"I210", 0x115}, /* PROG3# => Calendar */ + {"I182", 0x116}, /* EXIT# => Log Off */ + {"CUT", 0x117}, + {"COPY", 0x118}, + {"I171", 0x119}, /* NEXTSONG */ + {"I162", 0x11e}, /* CYCLEWINDOWS => Application Right (no left counterpart) */ + {"MUTE", 0x120}, + {"I148", 0x121}, /* CALC */ + {"I172", 0x122}, /* PLAYPAUSE */ + {"I158", 0x123}, /* WWW# => Compaq online start */ + {"I174", 0x124}, /* STOPCD */ + {"I147", 0x126}, /* MENU# => Shortcut/Menu/Help for a few OEMs */ + {"VOL-", 0x12e}, + {"I168", 0x12f}, /* CLOSECD# => Logitech Eject */ + {"I169", 0x12f}, /* EJECTCD# => Logitech */ + {"I170", 0x12f}, /* EJECTCLOSECD# => Logitech */ + {"VOL+", 0x130}, + {"I180", 0x132}, /* HOMEPAGE */ + {"HELP", 0x13b}, /* # */ + {"I221", 0x13c}, /* SOUND# => My Music */ + {"I212", 0x13d}, /* DASHBOARD# => Task Pane */ + {"I189", 0x13e}, /* NEW# */ + {"OPEN", 0x13f}, /* # */ + {"I214", 0x140}, /* CLOSE# */ + {"I240", 0x141}, /* REPLY# */ + {"I241", 0x142}, /* FORWARDMAIL# */ + {"I239", 0x143}, /* SEND# */ + {"I159", 0x144}, /* MSDOS# */ + {"I120", 0x14c}, /* MACRO */ + {"I187", 0x14c}, /* KPLEFTPAREN# */ + {"I243", 0x155}, /* DOCUMENTS# => Logitech */ + {"I242", 0x157}, /* SAVE# */ + {"I218", 0x158}, /* PRINT# */ + {"POWR", 0x15e}, + {"I150", 0x15f}, /* SLEEP */ + {"I151", 0x163}, /* WAKEUP */ + {"I188", 0x164}, /* KPRIGHTPAREN# */ + {"I220", 0x164}, /* CAMERA# => My Pictures */ + {"I225", 0x165}, /* SEARCH */ + {"I164", 0x166}, /* BOOKMARKS => Favorites */ + {"I181", 0x167}, /* REFRESH */ + {"STOP", 0x168}, + {"I167", 0x169}, /* FORWARD */ + {"I166", 0x16a}, /* BACK */ + {"I165", 0x16b}, /* COMPUTER */ + {"I163", 0x16c}, /* MAIL */ + {"I223", 0x16c}, /* EMAIL# */ + {"I234", 0x16d}, /* MEDIA */ + {"I175", 0x178}, /* RECORD# => Logitech */ + {"I160", 0x17a}, /* COFFEE# */ + {"I186", 0x18b}, /* SCROLLDOWN# => normal speed */ +}; +struct xkb_keymap *xkbcommon_keymap = nullptr; + +void +xkbcommon_init(struct xkb_keymap *keymap) +{ + xkbcommon_keymap = keymap; +} + +uint16_t +xkbcommon_translate(uint32_t keycode) +{ + const char *key_name = xkb_keymap_key_get_name(xkbcommon_keymap, keycode); + if (!key_name) { + qWarning() << "XKB Keyboard: Unknown keycode" << Qt::hex << keycode; + return 0; + } + + std::string key_name_s(key_name); + uint16_t ret = xkb_keycodes[key_name_s]; + + /* Observed with multimedia keys on a Windows X11 client. */ + if (!ret && (key_name_s.length() == 3) && (key_name_s[0] == 'I') && IS_HEX_DIGIT(key_name_s[1]) && IS_HEX_DIGIT(key_name_s[2])) + ret = 0x100 | stoi(key_name_s.substr(1), nullptr, 16); + + if (!ret) + qWarning() << "XKB Keyboard: Unknown key" << Qt::hex << keycode << "/" << QString::fromStdString(key_name_s); +#if 0 + else + qInfo() << "XKB Keyboard: Key" << Qt::hex << keycode << "/" << QString::fromStdString(key_name_s) << "scancode" << Qt::hex << ret; +#endif + + return ret; +} diff --git a/src/qt/xkbcommon_keyboard.hpp b/src/qt/xkbcommon_keyboard.hpp new file mode 100644 index 000000000..afcba41bb --- /dev/null +++ b/src/qt/xkbcommon_keyboard.hpp @@ -0,0 +1,19 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for xkbcommon keyboard input module. + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +extern void *xkbcommon_keymap; +void xkbcommon_init(struct xkb_keymap *keymap); +uint16_t xkbcommon_translate(uint32_t keycode); diff --git a/src/qt/xkbcommon_x11_keyboard.cpp b/src/qt/xkbcommon_x11_keyboard.cpp new file mode 100644 index 000000000..b9c16cc9b --- /dev/null +++ b/src/qt/xkbcommon_x11_keyboard.cpp @@ -0,0 +1,85 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * xkbcommon-x11 keyboard input module. + * + * Heavily inspired by libxkbcommon interactive-x11.c + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +extern "C" { +/* xkb.h has identifiers named "explicit", which is a C++ keyword now... */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wkeyword-macro" +#endif +#define explicit explicit_ +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#include +#undef explicit + +#include +}; +#include "xkbcommon_keyboard.hpp" + +#include + +void +xkbcommon_x11_init() +{ + xcb_connection_t *conn; + struct xkb_context *ctx; + int32_t core_kbd_device_id; + struct xkb_keymap *keymap; + + conn = xcb_connect(NULL, NULL); + if (!conn || xcb_connection_has_error(conn)) { + qWarning() << "XKB Keyboard: X server connection failed with error" << (conn ? xcb_connection_has_error(conn) : -1); + return; + } + + int ret = xkb_x11_setup_xkb_extension(conn, + XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION, + XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS, + NULL, NULL, NULL, NULL); + if (!ret) { + qWarning() << "XKB Keyboard: XKB extension setup failed"; + goto err_conn; + } + + ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!ctx) { + qWarning() << "XKB Keyboard: XKB context creation failed"; + goto err_conn; + } + + core_kbd_device_id = xkb_x11_get_core_keyboard_device_id(conn); + if (core_kbd_device_id == -1) { + qWarning() << "XKB Keyboard: Core keyboard device not found"; + goto err_ctx; + } + + keymap = xkb_x11_keymap_new_from_device(ctx, conn, core_kbd_device_id, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!keymap) { + qWarning() << "XKB Keyboard: Keymap loading failed"; + goto err_ctx; + } + + xkbcommon_init(keymap); + +err_ctx: + xkb_context_unref(ctx); +err_conn: + xcb_disconnect(conn); +} diff --git a/src/qt/xkbcommon_x11_keyboard.hpp b/src/qt/xkbcommon_x11_keyboard.hpp new file mode 100644 index 000000000..d8c063acb --- /dev/null +++ b/src/qt/xkbcommon_x11_keyboard.hpp @@ -0,0 +1,17 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for xkbcommon-x11 keyboard input module. + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +void xkbcommon_x11_init(); From 0b2b8807fd9624837d04b10bdbfb574d5150f9eb Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 7 Apr 2023 22:39:26 -0300 Subject: [PATCH 09/53] Fix file permissions --- .ci/build.sh | 0 .ci/static2dll.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .ci/build.sh mode change 100644 => 100755 .ci/static2dll.sh diff --git a/.ci/build.sh b/.ci/build.sh old mode 100644 new mode 100755 diff --git a/.ci/static2dll.sh b/.ci/static2dll.sh old mode 100644 new mode 100755 From fda95509f9bbca9cd0987f27ba62fc7ecf50807c Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 7 Apr 2023 22:42:48 -0300 Subject: [PATCH 10/53] Add AppImageBuilder directive for libxkbcommon --- .ci/AppImageBuilder.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/AppImageBuilder.yml b/.ci/AppImageBuilder.yml index 3d83e2851..22967e2f4 100644 --- a/.ci/AppImageBuilder.yml +++ b/.ci/AppImageBuilder.yml @@ -67,6 +67,7 @@ AppDir: - libxcb-shape0 # if QT:BOOL=ON - libxcb-shm0 # if QT:BOOL=ON - libxcb-xfixes0 # if QT:BOOL=ON + - libxkbcommon-x11-0 # if QT:BOOL=ON - zlib1g files: exclude: From ce4723b6de5ea7153fbd6ba3439765ffa7066505 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 7 Apr 2023 23:43:45 -0300 Subject: [PATCH 11/53] Jenkins: Add Qt Wayland support to AppImage --- .ci/AppImageBuilder.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/AppImageBuilder.yml b/.ci/AppImageBuilder.yml index 22967e2f4..39997a7a8 100644 --- a/.ci/AppImageBuilder.yml +++ b/.ci/AppImageBuilder.yml @@ -68,6 +68,7 @@ AppDir: - libxcb-shm0 # if QT:BOOL=ON - libxcb-xfixes0 # if QT:BOOL=ON - libxkbcommon-x11-0 # if QT:BOOL=ON + - qtwayland5 # if QT:BOOL=ON - zlib1g files: exclude: From 078e8cca0cdd4be2d52b67dcc0463962869cccb9 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 00:29:40 -0300 Subject: [PATCH 12/53] Add more AppImage build stuff to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0a21bf105..acb28baf7 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,8 @@ Makefile *.tar.* *.AppImage /appimage-builder-cache +/appimage-build +/AppImageBuilder-generated.yml # Visual Studio Code /.vs From bbbe0ec88d4dff35843f7acdaeab253151241deb Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 00:31:25 -0300 Subject: [PATCH 13/53] qt: Add xkbcommon keyboard support for Wayland --- src/qt/CMakeLists.txt | 3 + src/qt/qt_mainwindow.cpp | 14 +- src/qt/xkbcommon_keyboard.cpp | 9 +- src/qt/xkbcommon_keyboard.hpp | 1 + src/qt/xkbcommon_wl_keyboard.cpp | 236 ++++++++++++++++++++++++++++++ src/qt/xkbcommon_wl_keyboard.hpp | 17 +++ src/qt/xkbcommon_x11_keyboard.cpp | 1 + 7 files changed, 279 insertions(+), 2 deletions(-) create mode 100644 src/qt/xkbcommon_wl_keyboard.cpp create mode 100644 src/qt/xkbcommon_wl_keyboard.hpp diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 0cce392a9..dd3bc6f79 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -402,6 +402,9 @@ if (UNIX AND NOT APPLE AND NOT HAIKU) ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1) target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS}) target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp) + if (XKBCOMMON_FOUND) + target_sources(ui PRIVATE xkbcommon_wl_keyboard.cpp) + endif() target_compile_definitions(ui PRIVATE WAYLAND) endif() endif() diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index de7bceafb..40f01c2f6 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -101,6 +101,9 @@ extern int qt_nvr_save(void); # ifdef XKBCOMMON_X11 # include "xkbcommon_x11_keyboard.hpp" # endif +# ifdef WAYLAND +# include "xkbcommon_wl_keyboard.hpp" +# endif # endif # include # include @@ -652,9 +655,18 @@ MainWindow::MainWindow(QWidget *parent) ui->actionCursor_Puck->setChecked(true); } -#ifdef XKBCOMMON_X11 +#ifdef XKBCOMMON +# ifdef XKBCOMMON_X11 if (QApplication::platformName().contains("xcb")) xkbcommon_x11_init(); + else +# endif +# ifdef WAYLAND + if (QApplication::platformName().contains("wayland")) + xkbcommon_wl_init(); + else +# endif + {} #endif } diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index 1b4998b1f..87bc02aa5 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -228,7 +228,14 @@ struct xkb_keymap *xkbcommon_keymap = nullptr; void xkbcommon_init(struct xkb_keymap *keymap) { - xkbcommon_keymap = keymap; + if (keymap) + xkbcommon_keymap = keymap; +} + +void +xkbcommon_close() +{ + xkbcommon_keymap = NULL; } uint16_t diff --git a/src/qt/xkbcommon_keyboard.hpp b/src/qt/xkbcommon_keyboard.hpp index afcba41bb..c3b28eeec 100644 --- a/src/qt/xkbcommon_keyboard.hpp +++ b/src/qt/xkbcommon_keyboard.hpp @@ -16,4 +16,5 @@ */ extern void *xkbcommon_keymap; void xkbcommon_init(struct xkb_keymap *keymap); +void xkbcommon_close(); uint16_t xkbcommon_translate(uint32_t keycode); diff --git a/src/qt/xkbcommon_wl_keyboard.cpp b/src/qt/xkbcommon_wl_keyboard.cpp new file mode 100644 index 000000000..2dda6368a --- /dev/null +++ b/src/qt/xkbcommon_wl_keyboard.cpp @@ -0,0 +1,236 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * xkbcommon Wayland keyboard input module. + * + * Heavily inspired by libxkbcommon interactive-wayland.c + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +extern "C" { +#include +#include +#include +#include <86box/86box.h> +}; +#include "xkbcommon_keyboard.hpp" +#include +#include + +#include +#include +#include + +typedef struct { + struct wl_seat *wl_seat; + struct wl_keyboard *wl_kbd; + uint32_t version; + + struct xkb_keymap *keymap; + + struct wl_list link; +} seat_t; + +static bool wl_init_ok = false; +static struct wl_list seats; +static struct xkb_context *ctx; + +static void +xkbcommon_wl_set_keymap() +{ + /* Grab keymap from the first seat with one. */ + seat_t *seat, *tmp; + wl_list_for_each_safe(seat, tmp, &seats, link) { + if (seat->keymap) { + xkbcommon_init(seat->keymap); + return; + } + } + xkbcommon_close(); +} + +static void +kbd_keymap(void *data, struct wl_keyboard *wl_kbd, uint32_t format, + int fd, uint32_t size) +{ + seat_t *seat = (seat_t *) data; + + char *buf = (char *) mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (!buf) { + qWarning() << "XKB Keyboard: Failed to mmap keymap with error" << errno; + return; + } + + seat->keymap = xkb_keymap_new_from_buffer(ctx, buf, size - 1, + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(buf, size); + close(fd); + if (!seat->keymap) { + qWarning() << "XKB Keyboard: Keymap compilation failed"; + return; + } + + xkbcommon_wl_set_keymap(); +} + +static void +kbd_enter(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, + struct wl_surface *surf, struct wl_array *keys) +{ +} + +static void +kbd_leave(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, + struct wl_surface *surf) +{ +} + +static void +kbd_key(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, uint32_t time, + uint32_t key, uint32_t state) +{ +} + +static void +kbd_modifiers(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) +{ +} + +static void +kbd_repeat_info(void *data, struct wl_keyboard *wl_kbd, int32_t rate, + int32_t delay) +{ +} + +static const struct wl_keyboard_listener kbd_listener = { + kbd_keymap, + kbd_enter, + kbd_leave, + kbd_key, + kbd_modifiers, + kbd_repeat_info +}; + +static void +seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t caps) +{ + seat_t *seat = (seat_t *) data; + + if (!seat->wl_kbd && (caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + seat->wl_kbd = wl_seat_get_keyboard(seat->wl_seat); + wl_keyboard_add_listener(seat->wl_kbd, &kbd_listener, seat); + } else if (seat->wl_kbd && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) { + if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION) + wl_keyboard_release(seat->wl_kbd); + else + wl_keyboard_destroy(seat->wl_kbd); + + static struct xkb_keymap *keymap = seat->keymap; + seat->keymap = NULL; + xkbcommon_wl_set_keymap(); + xkb_keymap_unref(keymap); + + seat->wl_kbd = NULL; + } +} + +static void +seat_name(void *data, struct wl_seat *wl_seat, const char *name) +{ +} + +static const struct wl_seat_listener seat_listener = { + seat_capabilities, + seat_name +}; + +static void +display_handle_global(void *data, struct wl_registry *wl_registry, uint32_t id, + const char *interface, uint32_t version) +{ + if (!strcmp(interface, "wl_seat")) { + seat_t *seat = (seat_t *) malloc(sizeof(seat_t)); + memset(seat, 0, sizeof(seat_t)); + + seat->wl_seat = (wl_seat *) wl_registry_bind(wl_registry, id, &wl_seat_interface, MIN(version, 5)); + wl_seat_add_listener(seat->wl_seat, &seat_listener, seat); + wl_list_insert(&seats, &seat->link); + } +} + +static void +display_global_remove(void *data, struct wl_registry *wl_registry, uint32_t id) +{ + xkbcommon_close(); + + seat_t *seat, *tmp; + wl_list_for_each_safe(seat, tmp, &seats, link) { + if (seat->wl_kbd) { + if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION) + wl_keyboard_release(seat->wl_kbd); + else + wl_keyboard_destroy(seat->wl_kbd); + + xkb_keymap_unref(seat->keymap); + } + + if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION) + wl_seat_release(seat->wl_seat); + else + wl_seat_destroy(seat->wl_seat); + + wl_list_remove(&seat->link); + free(seat); + } +} + +static const struct wl_registry_listener registry_listener = { + display_handle_global, + display_global_remove +}; + +void +xkbcommon_wl_init() +{ + if (wl_init_ok) + return; + + wl_list_init(&seats); + + ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!ctx) { + qWarning() << "XKB Keyboard: XKB context creation failed"; + return; + } + + wl_display *display = (wl_display *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_display"); + if (display) { + auto registry = wl_display_get_registry(display); + if (registry) { + wl_registry_add_listener(registry, ®istry_listener, nullptr); + wl_display_roundtrip(display); + wl_display_roundtrip(display); + } else { + goto err_ctx; + } + } else { + goto err_ctx; + } + wl_init_ok = true; + return; + +err_ctx: + xkb_context_unref(ctx); +} diff --git a/src/qt/xkbcommon_wl_keyboard.hpp b/src/qt/xkbcommon_wl_keyboard.hpp new file mode 100644 index 000000000..a70cb9e9b --- /dev/null +++ b/src/qt/xkbcommon_wl_keyboard.hpp @@ -0,0 +1,17 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for xkbcommon Wayland keyboard input module. + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +void xkbcommon_wl_init(); diff --git a/src/qt/xkbcommon_x11_keyboard.cpp b/src/qt/xkbcommon_x11_keyboard.cpp index b9c16cc9b..8cba2c4d1 100644 --- a/src/qt/xkbcommon_x11_keyboard.cpp +++ b/src/qt/xkbcommon_x11_keyboard.cpp @@ -77,6 +77,7 @@ xkbcommon_x11_init() } xkbcommon_init(keymap); + goto err_conn; err_ctx: xkb_context_unref(ctx); From 4dd6b168557235630cd6ad3f89b748939edc8362 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 00:38:24 -0300 Subject: [PATCH 14/53] qt: Add another xkb Num. alias --- src/qt/xkbcommon_keyboard.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index 87bc02aa5..f5a7ca0eb 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -128,6 +128,7 @@ std::unordered_map xkb_keycodes{ {"AE13", 0x7d}, /* \| */ {"KPPT", 0x7e}, /* Brazilian Num. */ {"I06", 0x7e}, /* alias of KPPT on keycodes/xfree86 (i.e. X11 forwarding) */ + {"I129", 0x7e}, /* another alias: KPCOMMA */ /* Korean keys. */ {"HJCV", 0xf1}, /* hancha toggle */ From 08158571c0fa19f420b14fb70c60e6d4431cde64 Mon Sep 17 00:00:00 2001 From: richardg867 Date: Sat, 8 Apr 2023 01:02:45 -0300 Subject: [PATCH 15/53] Jenkins: Remove forgotten debug line --- .ci/build.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci/build.sh b/.ci/build.sh index 67320c2e2..1d50e304c 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -948,7 +948,6 @@ else -S "$prefix" -B "$prefix_build" || exit 99 cmake --build "$prefix_build" -j$(nproc) || exit 99 cmake --install "$prefix_build" || exit 99 - cp -p "$cwd_root/archive_tmp/usr/bin/fluidsynth" fluidsynth # Build SDL2 for joystick and FAudio support, with most components # disabled to remove the dependencies on PulseAudio and libdrm. From 080859f184a6ddba8c4b41d106ea0be1de6df8f7 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 01:03:21 -0300 Subject: [PATCH 16/53] qt: Fix xkb Pause key handling --- src/qt/qt_mainwindow.cpp | 4 ++++ src/qt/xkbcommon_keyboard.cpp | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 40f01c2f6..a8957b476 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1552,6 +1552,10 @@ x11_keycode_to_keysym(uint32_t keycode) } } #endif + /* Special case for Ctrl+Pause. */ + if ((finalkeycode == 0x145) && (keyboard_recv(0x1d) || keyboard_recv(0x11d))) + finalkeycode = 0x146; + if (rctrl_is_lalt && finalkeycode == 0x11D) finalkeycode = 0x38; return finalkeycode; diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index f5a7ca0eb..15833cd9b 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -141,8 +141,8 @@ std::unordered_map xkb_keycodes{ {"SYRQ", 0x137}, {"FK13", 0x137}, /* F13 as SysRq */ {"RALT", 0x138}, - {"PAUS", 0x146}, /* special case */ - {"FK15", 0x146}, /* F15 as Pause */ + {"PAUS", 0x145}, + {"FK15", 0x145}, /* F15 as Pause */ {"HOME", 0x147}, {"UP", 0x148}, {"PGUP", 0x149}, From 201503e6d24a91a9e7a6351fbcdbaafc43914cac Mon Sep 17 00:00:00 2001 From: richardg867 Date: Sat, 8 Apr 2023 01:19:05 -0300 Subject: [PATCH 17/53] Jenkins: Fix pkgconfig path missing a dependency for xkbcommon-x11 --- .ci/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/build.sh b/.ci/build.sh index 1d50e304c..a61cdc7f9 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -629,7 +629,7 @@ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) set(ENV{PKG_CONFIG_PATH} "") -set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/$libdir/pkgconfig:/usr/share/$libdir/pkgconfig") +set(ENV{PKG_CONFIG_LIBDIR} "/usr/lib/$libdir/pkgconfig:/usr/share/$libdir/pkgconfig:/usr/share/pkgconfig") include("$(realpath "$toolchain_file")") EOF From aea869b997a8303c0a56e53655e18193a71a6d8a Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 02:19:26 -0300 Subject: [PATCH 18/53] qt: Add missing XKB mapping for KPPLUSMINUS --- src/qt/xkbcommon_keyboard.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index 15833cd9b..490f95c82 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -164,8 +164,8 @@ std::unordered_map xkb_keycodes{ {"KPEQ", 0x59}, /* Num= */ {"FRNT", 0x101}, /* # Logitech Task Select */ {"I224", 0x105}, /* CHAT# => Messenger/Files */ - {"I190", 0x107}, /* REDO */ - {"UNDO", 0x108}, + {"I190", 0x107}, /* REDO# */ + {"UNDO", 0x108}, /* # */ {"PAST", 0x10a}, /* # Paste */ {"I185", 0x10b}, /* SCROLLUP# => normal speed */ {"I173", 0x110}, /* PREVIOUSSONG */ @@ -174,8 +174,8 @@ std::unordered_map xkb_keycodes{ {"I157", 0x114}, /* PROG2# => Excel */ {"I210", 0x115}, /* PROG3# => Calendar */ {"I182", 0x116}, /* EXIT# => Log Off */ - {"CUT", 0x117}, - {"COPY", 0x118}, + {"CUT", 0x117}, /* # */ + {"COPY", 0x118}, /* # */ {"I171", 0x119}, /* NEXTSONG */ {"I162", 0x11e}, /* CYCLEWINDOWS => Application Right (no left counterpart) */ {"MUTE", 0x120}, @@ -202,6 +202,7 @@ std::unordered_map xkb_keycodes{ {"I159", 0x144}, /* MSDOS# */ {"I120", 0x14c}, /* MACRO */ {"I187", 0x14c}, /* KPLEFTPAREN# */ + {"I126", 0x14e}, /* KPPLUSMINUS */ {"I243", 0x155}, /* DOCUMENTS# => Logitech */ {"I242", 0x157}, /* SAVE# */ {"I218", 0x158}, /* PRINT# */ From 6e1f3de04414a47ad23330bef7b19f97d0c387d2 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 14:32:05 -0300 Subject: [PATCH 19/53] qt: Get XCB connection for xkbcommon keyboard from Qt itself --- src/qt/xkbcommon_wl_keyboard.cpp | 2 +- src/qt/xkbcommon_x11_keyboard.cpp | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/qt/xkbcommon_wl_keyboard.cpp b/src/qt/xkbcommon_wl_keyboard.cpp index 2dda6368a..c6736f2d4 100644 --- a/src/qt/xkbcommon_wl_keyboard.cpp +++ b/src/qt/xkbcommon_wl_keyboard.cpp @@ -55,7 +55,7 @@ xkbcommon_wl_set_keymap() return; } } - xkbcommon_close(); + xkbcommon_close(); /* none found */ } static void diff --git a/src/qt/xkbcommon_x11_keyboard.cpp b/src/qt/xkbcommon_x11_keyboard.cpp index 8cba2c4d1..8e0167518 100644 --- a/src/qt/xkbcommon_x11_keyboard.cpp +++ b/src/qt/xkbcommon_x11_keyboard.cpp @@ -33,7 +33,9 @@ extern "C" { }; #include "xkbcommon_keyboard.hpp" +#include #include +#include void xkbcommon_x11_init() @@ -43,9 +45,9 @@ xkbcommon_x11_init() int32_t core_kbd_device_id; struct xkb_keymap *keymap; - conn = xcb_connect(NULL, NULL); - if (!conn || xcb_connection_has_error(conn)) { - qWarning() << "XKB Keyboard: X server connection failed with error" << (conn ? xcb_connection_has_error(conn) : -1); + conn = (xcb_connection_t *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("connection"); + if (!conn) { + qWarning() << "XKB Keyboard: X server connection failed"; return; } @@ -55,13 +57,13 @@ xkbcommon_x11_init() NULL, NULL, NULL, NULL); if (!ret) { qWarning() << "XKB Keyboard: XKB extension setup failed"; - goto err_conn; + return; } ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!ctx) { qWarning() << "XKB Keyboard: XKB context creation failed"; - goto err_conn; + return; } core_kbd_device_id = xkb_x11_get_core_keyboard_device_id(conn); @@ -77,10 +79,8 @@ xkbcommon_x11_init() } xkbcommon_init(keymap); - goto err_conn; + return; err_ctx: xkb_context_unref(ctx); -err_conn: - xcb_disconnect(conn); } From 1fb13b605e7b27f70a83ab576f96106b7110500a Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 15:39:42 -0300 Subject: [PATCH 20/53] qt: Add more XKB mappings, mostly multimedia on extended evdev codes (apparently not usable in X but will be useful later) --- src/qt/xkbcommon_keyboard.cpp | 58 ++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index 490f95c82..e0560117b 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -53,6 +53,7 @@ std::unordered_map xkb_keycodes{ {"AD11", 0x1a}, {"AD12", 0x1b}, {"RTRN", 0x1c}, + {"LNFD", 0x1c}, /* linefeed => Enter */ {"LCTL", 0x1d}, {"AC01", 0x1e}, @@ -99,7 +100,7 @@ std::unordered_map xkb_keycodes{ {"NMLK", 0x45}, {"SCLK", 0x46}, - {"FK14", 0x46}, /* F14 as Scroll Lock */ + {"FK14", 0x46}, /* F14 => Scroll Lock */ {"KP7", 0x47}, {"KP8", 0x48}, {"KP9", 0x49}, @@ -119,6 +120,7 @@ std::unordered_map xkb_keycodes{ {"FK12", 0x58}, /* Japanese keys. */ + {"HZTG", 0x29}, /* hankaku-zenkaku toggle => ~ */ {"HKTG", 0x70}, /* hiragana-katakana toggle... */ {"HIRA", 0x70}, /* ...and individual keys */ {"KATA", 0x70}, @@ -128,7 +130,7 @@ std::unordered_map xkb_keycodes{ {"AE13", 0x7d}, /* \| */ {"KPPT", 0x7e}, /* Brazilian Num. */ {"I06", 0x7e}, /* alias of KPPT on keycodes/xfree86 (i.e. X11 forwarding) */ - {"I129", 0x7e}, /* another alias: KPCOMMA */ + {"I129", 0x7e}, /* another alias: evdev KPCOMMA */ /* Korean keys. */ {"HJCV", 0xf1}, /* hancha toggle */ @@ -139,10 +141,11 @@ std::unordered_map xkb_keycodes{ {"KPDV", 0x135}, {"PRSC", 0x137}, {"SYRQ", 0x137}, - {"FK13", 0x137}, /* F13 as SysRq */ + {"FK13", 0x137}, /* F13 => SysRq */ {"RALT", 0x138}, {"PAUS", 0x145}, - {"FK15", 0x145}, /* F15 as Pause */ + {"BRK", 0x145}, + {"FK15", 0x145}, /* F15 => Pause */ {"HOME", 0x147}, {"UP", 0x148}, {"PGUP", 0x149}, @@ -155,25 +158,36 @@ std::unordered_map xkb_keycodes{ {"DELE", 0x153}, {"LWIN", 0x15b}, + {"LMTA", 0x15b}, {"RWIN", 0x15c}, - {"COMP", 0x15d}, + {"RMTA", 0x15c}, + {"MENU", 0x15d}, + {"COMP", 0x15d}, /* Compose as Menu */ /* Multimedia keys, using Linux evdev-specific keycodes where required. Guideline is to try and follow the Microsoft standard, then fill in some OEM-specific keys for redundancy sake. Keys marked with # are not translated into evdev codes by the standard atkbd driver. */ {"KPEQ", 0x59}, /* Num= */ + {"I426", 0x6a}, /* ZOOMIN# => Logitech */ + {"I428", 0x6b}, /* ZOOMRESET# => Logitech */ + {"I231", 0x6d}, /* CANCEL# => Logitech */ {"FRNT", 0x101}, /* # Logitech Task Select */ + {"I156", 0x102}, /* PROG1# => Samsung */ + {"I157", 0x103}, /* PROG2# => Samsung */ + {"I427", 0x104}, /* ZOOMOUT# => Logitech */ + {"I152", 0x105}, /* FILE# => Messenger/Files */ {"I224", 0x105}, /* CHAT# => Messenger/Files */ + {"I438", 0x105}, /* MESSENGER# */ {"I190", 0x107}, /* REDO# */ {"UNDO", 0x108}, /* # */ {"PAST", 0x10a}, /* # Paste */ {"I185", 0x10b}, /* SCROLLUP# => normal speed */ {"I173", 0x110}, /* PREVIOUSSONG */ {"FIND", 0x112}, /* # Logitech */ - {"I156", 0x113}, /* PROG1# => Word */ - {"I157", 0x114}, /* PROG2# => Excel */ - {"I210", 0x115}, /* PROG3# => Calendar */ - {"I182", 0x116}, /* EXIT# => Log Off */ + {"I429", 0x113}, /* WORDPROCESSOR# => Word */ + {"I431", 0x114}, /* SPREADSHEET# => Excel */ + {"I405", 0x115}, /* CALENDAR# */ + {"I441", 0x116}, /* LOGOFF# */ {"CUT", 0x117}, /* # */ {"COPY", 0x118}, /* # */ {"I171", 0x119}, /* NEXTSONG */ @@ -181,7 +195,7 @@ std::unordered_map xkb_keycodes{ {"MUTE", 0x120}, {"I148", 0x121}, /* CALC */ {"I172", 0x122}, /* PLAYPAUSE */ - {"I158", 0x123}, /* WWW# => Compaq online start */ + {"I440", 0x123}, /* SPELLCHECK# */ {"I174", 0x124}, /* STOPCD */ {"I147", 0x126}, /* MENU# => Shortcut/Menu/Help for a few OEMs */ {"VOL-", 0x12e}, @@ -189,9 +203,12 @@ std::unordered_map xkb_keycodes{ {"I169", 0x12f}, /* EJECTCD# => Logitech */ {"I170", 0x12f}, /* EJECTCLOSECD# => Logitech */ {"VOL+", 0x130}, + {"I158", 0x132}, /* WWW# */ {"I180", 0x132}, /* HOMEPAGE */ + {"I642", 0x137}, /* SELECTIVE_SCREENSHOT# => SysRq */ {"HELP", 0x13b}, /* # */ - {"I221", 0x13c}, /* SOUND# => My Music */ + {"I221", 0x13c}, /* SOUND# => My Music/Office Home */ + {"I368", 0x13c}, /* VENDOR# => My Music/Office Home */ {"I212", 0x13d}, /* DASHBOARD# => Task Pane */ {"I189", 0x13e}, /* NEW# */ {"OPEN", 0x13f}, /* # */ @@ -213,6 +230,7 @@ std::unordered_map xkb_keycodes{ {"I220", 0x164}, /* CAMERA# => My Pictures */ {"I225", 0x165}, /* SEARCH */ {"I164", 0x166}, /* BOOKMARKS => Favorites */ + {"I372", 0x166}, /* FAVORITES# */ {"I181", 0x167}, /* REFRESH */ {"STOP", 0x168}, {"I167", 0x169}, /* FORWARD */ @@ -222,7 +240,7 @@ std::unordered_map xkb_keycodes{ {"I223", 0x16c}, /* EMAIL# */ {"I234", 0x16d}, /* MEDIA */ {"I175", 0x178}, /* RECORD# => Logitech */ - {"I160", 0x17a}, /* COFFEE# */ + {"I160", 0x17a}, /* COFFEE/SCREENLOCK# */ {"I186", 0x18b}, /* SCROLLDOWN# => normal speed */ }; struct xkb_keymap *xkbcommon_keymap = nullptr; @@ -244,23 +262,21 @@ uint16_t xkbcommon_translate(uint32_t keycode) { const char *key_name = xkb_keymap_key_get_name(xkbcommon_keymap, keycode); - if (!key_name) { - qWarning() << "XKB Keyboard: Unknown keycode" << Qt::hex << keycode; - return 0; - } - std::string key_name_s(key_name); - uint16_t ret = xkb_keycodes[key_name_s]; + /* If XKB doesn't know the key name for this keycode, assume an unnamed Ixxx key. + This is useful for older XKB versions with an incomplete evdev keycode map. */ + auto key_name_s = key_name ? std::string(key_name) : QString("I%1").arg(keycode).toStdString(); + auto ret = xkb_keycodes[key_name_s]; - /* Observed with multimedia keys on a Windows X11 client. */ + /* Observed with multimedia keys on Windows VcXsrv. */ if (!ret && (key_name_s.length() == 3) && (key_name_s[0] == 'I') && IS_HEX_DIGIT(key_name_s[1]) && IS_HEX_DIGIT(key_name_s[2])) ret = 0x100 | stoi(key_name_s.substr(1), nullptr, 16); if (!ret) - qWarning() << "XKB Keyboard: Unknown key" << Qt::hex << keycode << "/" << QString::fromStdString(key_name_s); + qWarning() << "XKB Keyboard: Unknown key" << Qt::hex << keycode << QString::fromStdString(key_name_s); #if 0 else - qInfo() << "XKB Keyboard: Key" << Qt::hex << keycode << "/" << QString::fromStdString(key_name_s) << "scancode" << Qt::hex << ret; + qInfo() << "XKB Keyboard: Key" << Qt::hex << keycode << QString::fromStdString(key_name_s) << "scancode" << Qt::hex << ret; #endif return ret; From a80e9501b831c1d275e6db6ce35895c69a0e86b8 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 17:58:55 -0300 Subject: [PATCH 21/53] qt: Add evdev keycode mapper --- src/qt/CMakeLists.txt | 2 +- src/qt/evdev_keyboard.cpp | 134 ++++++++++++++++++++++++++++++++++ src/qt/evdev_keyboard.hpp | 20 +++++ src/qt/qt_mainwindow.cpp | 53 ++++---------- src/qt/xkbcommon_keyboard.cpp | 95 +++++------------------- 5 files changed, 190 insertions(+), 114 deletions(-) create mode 100644 src/qt/evdev_keyboard.cpp create mode 100644 src/qt/evdev_keyboard.hpp diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index dd3bc6f79..614da7a00 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -365,7 +365,7 @@ endif() if (UNIX AND NOT APPLE AND NOT HAIKU) find_package(X11 REQUIRED) target_link_libraries(ui PRIVATE X11::X11 X11::Xi) - target_sources(ui PRIVATE xinput2_mouse.cpp) + target_sources(ui PRIVATE evdev_keyboard.cpp xinput2_mouse.cpp) find_package(PkgConfig REQUIRED) pkg_check_modules(LIBEVDEV IMPORTED_TARGET libevdev) if (LIBEVDEV_FOUND) diff --git a/src/qt/evdev_keyboard.cpp b/src/qt/evdev_keyboard.cpp new file mode 100644 index 000000000..4eba75e26 --- /dev/null +++ b/src/qt/evdev_keyboard.cpp @@ -0,0 +1,134 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * evdev keyboard input module. + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +#include +#include + +static std::unordered_map evdev_keycodes{ + {99, 0x54}, /* SYSRQ */ + {86, 0x56}, /* 102ND */ + {87, 0x57}, /* F11 */ + {88, 0x58}, /* F12 */ + {117, 0x59}, /* KPEQUAL */ + {95, 0x5c}, /* KPJPCOMMA */ + {183, 0x5d}, /* F13 */ + {184, 0x5e}, /* F14 */ + {185, 0x5f}, /* F15 */ + {93, 0x70}, /* KATAKANAHIRAGANA */ + {89, 0x73}, /* RO */ + {85, 0x76}, /* ZENKAKUHANKAKU */ + {91, 0x77}, /* HIRAGANA */ + {90, 0x78}, /* KATAKANA */ + {92, 0x79}, /* HENKAN */ + {94, 0x7b}, /* MUHENKAN */ + {124, 0x7d}, /* YEN */ + {121, 0x7e}, /* KPCOMMA */ + + /* Multimedia keys. Guideline is to try and follow the Microsoft standard, then + fill in remaining scancodes with OEM-specific keys for redundancy sake. Keys + marked with # are not translated into evdev codes by the standard atkbd driver. */ + {117, 0x59}, /* Num= */ + {418, 0x6a}, /* ZOOMIN# => Logitech */ + {420, 0x6b}, /* ZOOMRESET# => Logitech */ + {223, 0x6d}, /* CANCEL# => Logitech */ + {132, 0x101}, /* # Logitech Task Select */ + {148, 0x102}, /* PROG1# => Samsung */ + {149, 0x103}, /* PROG2# => Samsung */ + {419, 0x104}, /* ZOOMOUT# => Logitech */ + {144, 0x105}, /* FILE# => Messenger/Files */ + {216, 0x105}, /* CHAT# => Messenger/Files */ + {430, 0x105}, /* MESSENGER# */ + {182, 0x107}, /* REDO# */ + {131, 0x108}, /* UNDO# */ + {135, 0x10a}, /* PASTE# */ + {177, 0x10b}, /* SCROLLUP# => normal speed */ + {165, 0x110}, /* PREVIOUSSONG */ + {136, 0x112}, /* FIND# => Logitech */ + {421, 0x113}, /* WORDPROCESSOR# => Word */ + {423, 0x114}, /* SPREADSHEET# => Excel */ + {397, 0x115}, /* CALENDAR# */ + {433, 0x116}, /* LOGOFF# */ + {137, 0x117}, /* CUT# */ + {133, 0x118}, /* COPY# */ + {163, 0x119}, /* NEXTSONG */ + {154, 0x11e}, /* CYCLEWINDOWS => Application Right (no left counterpart) */ + {113, 0x120}, /* MUTE */ + {140, 0x121}, /* CALC */ + {164, 0x122}, /* PLAYPAUSE */ + {432, 0x123}, /* SPELLCHECK# */ + {166, 0x124}, /* STOPCD */ + {139, 0x126}, /* MENU# => Shortcut/Menu/Help for a few OEMs */ + {114, 0x12e}, /* VOL- */ + {160, 0x12f}, /* CLOSECD# => Logitech Eject */ + {161, 0x12f}, /* EJECTCD# => Logitech */ + {162, 0x12f}, /* EJECTCLOSECD# => Logitech */ + {115, 0x130}, /* VOL+ */ + {150, 0x132}, /* WWW# */ + {172, 0x132}, /* HOMEPAGE */ + {634, 0x137}, /* SELECTIVE_SCREENSHOT# => SysRq */ + {138, 0x13b}, /* HELP# */ + {213, 0x13c}, /* SOUND# => My Music/Office Home */ + {360, 0x13c}, /* VENDOR# => My Music/Office Home */ + {204, 0x13d}, /* DASHBOARD# => Task Pane */ + {181, 0x13e}, /* NEW# */ + {134, 0x13f}, /* OPEN# */ + {206, 0x140}, /* CLOSE# */ + {232, 0x141}, /* REPLY# */ + {233, 0x142}, /* FORWARDMAIL# */ + {231, 0x143}, /* SEND# */ + {151, 0x144}, /* MSDOS# */ + {112, 0x14c}, /* MACRO */ + {179, 0x14c}, /* KPLEFTPAREN# */ + {118, 0x14e}, /* KPPLUSMINUS */ + {235, 0x155}, /* DOCUMENTS# => Logitech */ + {234, 0x157}, /* SAVE# */ + {210, 0x158}, /* PRINT# */ + {116, 0x15e}, /* POWER */ + {142, 0x15f}, /* SLEEP */ + {143, 0x163}, /* WAKEUP */ + {180, 0x164}, /* KPRIGHTPAREN# */ + {212, 0x164}, /* CAMERA# => My Pictures */ + {217, 0x165}, /* SEARCH */ + {156, 0x166}, /* BOOKMARKS => Favorites */ + {364, 0x166}, /* FAVORITES# */ + {173, 0x167}, /* REFRESH */ + {128, 0x168}, /* STOP */ + {159, 0x169}, /* FORWARD */ + {158, 0x16a}, /* BACK */ + {157, 0x16b}, /* COMPUTER */ + {155, 0x16c}, /* MAIL */ + {215, 0x16c}, /* EMAIL# */ + {226, 0x16d}, /* MEDIA */ + {167, 0x178}, /* RECORD# => Logitech */ + {152, 0x17a}, /* COFFEE/SCREENLOCK# */ + {178, 0x18b}, /* SCROLLDOWN# => normal speed */ +}; + +uint16_t +evdev_translate(uint32_t keycode) +{ + /* "for 1-83 (0x01-0x53) scancode equals keycode" */ + auto ret = (keycode <= 0x53) ? keycode : evdev_keycodes[keycode]; + + if (!ret) + qWarning() << "Evdev Keyboard: Unknown key" << keycode; +#if 0 + else + qInfo() << "Evdev Keyboard: Key" << keycode << "scancode" << Qt::hex << ret; +#endif + + return ret; +} diff --git a/src/qt/evdev_keyboard.hpp b/src/qt/evdev_keyboard.hpp new file mode 100644 index 000000000..5efe5958d --- /dev/null +++ b/src/qt/evdev_keyboard.hpp @@ -0,0 +1,20 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for evdev keyboard input module. + * + * + * + * Authors: RichardG, + * + * Copyright 2023 RichardG. + */ +#ifndef EVDEV_KEYBOARD_HPP +#define EVDEV_KEYBOARD_HPP +uint16_t evdev_translate(uint32_t keycode); +#endif diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index a8957b476..8e8208dcc 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -96,6 +96,9 @@ extern int qt_nvr_save(void); #include "qt_util.hpp" #if defined __unix__ && !defined __HAIKU__ +# ifndef Q_OS_MACOS +# include "evdev_keyboard.hpp" +# endif # ifdef XKBCOMMON # include "xkbcommon_keyboard.hpp" # ifdef XKBCOMMON_X11 @@ -1378,27 +1381,6 @@ std::array darwin_to_xt { }; #endif -#if defined(__unix__) && !defined(__HAIKU__) -static std::unordered_map evdev_to_xt = { - {96, 0x11C}, - { 97, 0x11D}, - { 98, 0x135}, - { 99, 0x71 }, - { 100, 0x138}, - { 101, 0x1C }, - { 102, 0x147}, - { 103, 0x148}, - { 104, 0x149}, - { 105, 0x14B}, - { 106, 0x14D}, - { 107, 0x14F}, - { 108, 0x150}, - { 109, 0x151}, - { 110, 0x152}, - { 111, 0x153} -}; -#endif - #ifdef __HAIKU__ static std::unordered_map be_to_xt = { {0x01, 0x01 }, @@ -1528,28 +1510,25 @@ x11_keycode_to_keysym(uint32_t keycode) if (xkbcommon_keymap) { finalkeycode = xkbcommon_translate(keycode); } else +# endif +# ifdef EVDEV_KEYBOARD_HPP + if (QApplication::platformName().contains("eglfs")) { + finalkeycode = evdev_translate(keycode); + } else # endif { static Display *x11display = nullptr; - if (QApplication::platformName().contains("eglfs")) { - keycode -= 8; - if (keycode <= 88) - finalkeycode = keycode; - else - finalkeycode = evdev_to_xt[keycode]; - } else { - if (QApplication::platformName().contains("wayland")) { + if (QApplication::platformName().contains("wayland")) { + selected_keycode = x11_to_xt_2; + } else if (!x11display) { + x11display = XOpenDisplay(nullptr); + if (XKeysymToKeycode(x11display, XK_Home) == 110) { selected_keycode = x11_to_xt_2; - } else if (!x11display) { - x11display = XOpenDisplay(nullptr); - if (XKeysymToKeycode(x11display, XK_Home) == 110) { - selected_keycode = x11_to_xt_2; - } else if (XKeysymToKeycode(x11display, XK_Home) == 69) { - selected_keycode = x11_to_xt_vnc; - } + } else if (XKeysymToKeycode(x11display, XK_Home) == 69) { + selected_keycode = x11_to_xt_vnc; } - finalkeycode = selected_keycode[keycode]; } + finalkeycode = selected_keycode[keycode]; } #endif /* Special case for Ctrl+Pause. */ diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index e0560117b..953008453 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -20,10 +20,12 @@ extern "C" { #include #include +#include "evdev_keyboard.hpp" -#define IS_HEX_DIGIT(c) ((((c) >= '0') && ((c) <= '9')) || (((c) >= 'A') && ((c) <= 'F')) || (((c) >= 'a') && ((c) <= 'f'))) +#define IS_DEC_DIGIT(c) (((c) >= '0') && ((c) <= '9')) +#define IS_HEX_DIGIT(c) (IS_DEC_DIGIT(c) || (((c) >= 'A') && ((c) <= 'F')) || (((c) >= 'a') && ((c) <= 'f'))) -std::unordered_map xkb_keycodes{ +static std::unordered_map xkb_keycodes{ {"ESC", 0x01}, {"AE01", 0x02}, {"AE02", 0x03}, @@ -100,7 +102,6 @@ std::unordered_map xkb_keycodes{ {"NMLK", 0x45}, {"SCLK", 0x46}, - {"FK14", 0x46}, /* F14 => Scroll Lock */ {"KP7", 0x47}, {"KP8", 0x48}, {"KP9", 0x49}, @@ -118,19 +119,22 @@ std::unordered_map xkb_keycodes{ {"LSGT", 0x56}, {"FK11", 0x57}, {"FK12", 0x58}, + {"FK13", 0x5d}, + {"FK14", 0x5e}, + {"FK15", 0x5f}, /* Japanese keys. */ - {"HZTG", 0x29}, /* hankaku-zenkaku toggle => ~ */ - {"HKTG", 0x70}, /* hiragana-katakana toggle... */ - {"HIRA", 0x70}, /* ...and individual keys */ - {"KATA", 0x70}, + {"JPCM", 0x5c}, /* evdev KPJPCOMMA */ + {"HKTG", 0x70}, /* hiragana-katakana toggle */ {"AB11", 0x73}, /* \_ and Brazilian /? */ + {"HZTG", 0x76}, /* hankaku-zenkaku toggle */ + {"HIRA", 0x77}, + {"KATA", 0x78}, {"HENK", 0x79}, {"MUHE", 0x7b}, {"AE13", 0x7d}, /* \| */ {"KPPT", 0x7e}, /* Brazilian Num. */ {"I06", 0x7e}, /* alias of KPPT on keycodes/xfree86 (i.e. X11 forwarding) */ - {"I129", 0x7e}, /* another alias: evdev KPCOMMA */ /* Korean keys. */ {"HJCV", 0xf1}, /* hancha toggle */ @@ -141,11 +145,9 @@ std::unordered_map xkb_keycodes{ {"KPDV", 0x135}, {"PRSC", 0x137}, {"SYRQ", 0x137}, - {"FK13", 0x137}, /* F13 => SysRq */ {"RALT", 0x138}, {"PAUS", 0x145}, {"BRK", 0x145}, - {"FK15", 0x145}, /* F15 => Pause */ {"HOME", 0x147}, {"UP", 0x148}, {"PGUP", 0x149}, @@ -164,84 +166,21 @@ std::unordered_map xkb_keycodes{ {"MENU", 0x15d}, {"COMP", 0x15d}, /* Compose as Menu */ - /* Multimedia keys, using Linux evdev-specific keycodes where required. Guideline is to try - and follow the Microsoft standard, then fill in some OEM-specific keys for redundancy sake. - Keys marked with # are not translated into evdev codes by the standard atkbd driver. */ + /* Multimedia keys. Same notes as evdev_keyboard apply here. */ {"KPEQ", 0x59}, /* Num= */ - {"I426", 0x6a}, /* ZOOMIN# => Logitech */ - {"I428", 0x6b}, /* ZOOMRESET# => Logitech */ - {"I231", 0x6d}, /* CANCEL# => Logitech */ {"FRNT", 0x101}, /* # Logitech Task Select */ - {"I156", 0x102}, /* PROG1# => Samsung */ - {"I157", 0x103}, /* PROG2# => Samsung */ - {"I427", 0x104}, /* ZOOMOUT# => Logitech */ - {"I152", 0x105}, /* FILE# => Messenger/Files */ - {"I224", 0x105}, /* CHAT# => Messenger/Files */ - {"I438", 0x105}, /* MESSENGER# */ - {"I190", 0x107}, /* REDO# */ {"UNDO", 0x108}, /* # */ {"PAST", 0x10a}, /* # Paste */ - {"I185", 0x10b}, /* SCROLLUP# => normal speed */ - {"I173", 0x110}, /* PREVIOUSSONG */ {"FIND", 0x112}, /* # Logitech */ - {"I429", 0x113}, /* WORDPROCESSOR# => Word */ - {"I431", 0x114}, /* SPREADSHEET# => Excel */ - {"I405", 0x115}, /* CALENDAR# */ - {"I441", 0x116}, /* LOGOFF# */ {"CUT", 0x117}, /* # */ {"COPY", 0x118}, /* # */ - {"I171", 0x119}, /* NEXTSONG */ - {"I162", 0x11e}, /* CYCLEWINDOWS => Application Right (no left counterpart) */ {"MUTE", 0x120}, - {"I148", 0x121}, /* CALC */ - {"I172", 0x122}, /* PLAYPAUSE */ - {"I440", 0x123}, /* SPELLCHECK# */ - {"I174", 0x124}, /* STOPCD */ - {"I147", 0x126}, /* MENU# => Shortcut/Menu/Help for a few OEMs */ {"VOL-", 0x12e}, - {"I168", 0x12f}, /* CLOSECD# => Logitech Eject */ - {"I169", 0x12f}, /* EJECTCD# => Logitech */ - {"I170", 0x12f}, /* EJECTCLOSECD# => Logitech */ {"VOL+", 0x130}, - {"I158", 0x132}, /* WWW# */ - {"I180", 0x132}, /* HOMEPAGE */ - {"I642", 0x137}, /* SELECTIVE_SCREENSHOT# => SysRq */ - {"HELP", 0x13b}, /* # */ - {"I221", 0x13c}, /* SOUND# => My Music/Office Home */ - {"I368", 0x13c}, /* VENDOR# => My Music/Office Home */ - {"I212", 0x13d}, /* DASHBOARD# => Task Pane */ - {"I189", 0x13e}, /* NEW# */ - {"OPEN", 0x13f}, /* # */ - {"I214", 0x140}, /* CLOSE# */ - {"I240", 0x141}, /* REPLY# */ - {"I241", 0x142}, /* FORWARDMAIL# */ - {"I239", 0x143}, /* SEND# */ - {"I159", 0x144}, /* MSDOS# */ - {"I120", 0x14c}, /* MACRO */ - {"I187", 0x14c}, /* KPLEFTPAREN# */ - {"I126", 0x14e}, /* KPPLUSMINUS */ - {"I243", 0x155}, /* DOCUMENTS# => Logitech */ - {"I242", 0x157}, /* SAVE# */ - {"I218", 0x158}, /* PRINT# */ + {"HELP", 0x13b}, + {"OPEN", 0x13f}, {"POWR", 0x15e}, - {"I150", 0x15f}, /* SLEEP */ - {"I151", 0x163}, /* WAKEUP */ - {"I188", 0x164}, /* KPRIGHTPAREN# */ - {"I220", 0x164}, /* CAMERA# => My Pictures */ - {"I225", 0x165}, /* SEARCH */ - {"I164", 0x166}, /* BOOKMARKS => Favorites */ - {"I372", 0x166}, /* FAVORITES# */ - {"I181", 0x167}, /* REFRESH */ {"STOP", 0x168}, - {"I167", 0x169}, /* FORWARD */ - {"I166", 0x16a}, /* BACK */ - {"I165", 0x16b}, /* COMPUTER */ - {"I163", 0x16c}, /* MAIL */ - {"I223", 0x16c}, /* EMAIL# */ - {"I234", 0x16d}, /* MEDIA */ - {"I175", 0x178}, /* RECORD# => Logitech */ - {"I160", 0x17a}, /* COFFEE/SCREENLOCK# */ - {"I186", 0x18b}, /* SCROLLDOWN# => normal speed */ }; struct xkb_keymap *xkbcommon_keymap = nullptr; @@ -272,6 +211,10 @@ xkbcommon_translate(uint32_t keycode) if (!ret && (key_name_s.length() == 3) && (key_name_s[0] == 'I') && IS_HEX_DIGIT(key_name_s[1]) && IS_HEX_DIGIT(key_name_s[2])) ret = 0x100 | stoi(key_name_s.substr(1), nullptr, 16); + /* Translate unnamed evdev-specific keycodes. */ + if (!ret && (key_name_s.length() >= 2) && (key_name_s[0] == 'I') && IS_DEC_DIGIT(key_name_s[1])) + ret = evdev_translate(stoi(key_name_s.substr(1)) - 8); + if (!ret) qWarning() << "XKB Keyboard: Unknown key" << Qt::hex << keycode << QString::fromStdString(key_name_s); #if 0 From ae9202327980060f938a8e63e1fbb90ab6469e6e Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 18:45:10 -0300 Subject: [PATCH 22/53] qt: Add missing evdev mappings and fix offset in native evdev mode --- src/qt/evdev_keyboard.cpp | 32 ++++++++++++++++++++++++++++++-- src/qt/qt_mainwindow.cpp | 2 +- src/qt/xkbcommon_keyboard.cpp | 2 +- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/qt/evdev_keyboard.cpp b/src/qt/evdev_keyboard.cpp index 4eba75e26..3e66dc1ed 100644 --- a/src/qt/evdev_keyboard.cpp +++ b/src/qt/evdev_keyboard.cpp @@ -17,16 +17,18 @@ #include #include -static std::unordered_map evdev_keycodes{ +static std::unordered_map evdev_keycodes = { {99, 0x54}, /* SYSRQ */ {86, 0x56}, /* 102ND */ {87, 0x57}, /* F11 */ {88, 0x58}, /* F12 */ {117, 0x59}, /* KPEQUAL */ - {95, 0x5c}, /* KPJPCOMMA */ {183, 0x5d}, /* F13 */ {184, 0x5e}, /* F14 */ {185, 0x5f}, /* F15 */ + + /* Japanese keys. */ + {95, 0x5c}, /* KPJPCOMMA */ {93, 0x70}, /* KATAKANAHIRAGANA */ {89, 0x73}, /* RO */ {85, 0x76}, /* ZENKAKUHANKAKU */ @@ -37,6 +39,32 @@ static std::unordered_map evdev_keycodes{ {124, 0x7d}, /* YEN */ {121, 0x7e}, /* KPCOMMA */ + /* Korean keys. */ + {123, 0xf1}, /* HANJA */ + {122, 0xf2}, /* HANGUL */ + + {96, 0x11c}, /* KPENTER */ + {97, 0x11d}, /* RIGHTCTRL */ + {98, 0x135}, /* KPSLASH */ + {99, 0x137}, /* SYSRQ */ + {100, 0x138}, /* RIGHTALT */ + {119, 0x145}, /* PAUSE */ + {411, 0x145}, /* BREAK */ + {102, 0x147}, /* HOME */ + {103, 0x148}, /* UP */ + {104, 0x149}, /* PAGEUP */ + {105, 0x14b}, /* LEFT */ + {106, 0x14d}, /* RIGHT */ + {107, 0x14f}, /* END */ + {108, 0x150}, /* DOWN */ + {109, 0x151}, /* PAGEDOWN */ + {110, 0x152}, /* INSERT */ + {111, 0x153}, /* DELETE */ + + {125, 0x15b}, /* LEFTMETA */ + {126, 0x15c}, /* RIGHTMETA */ + {127, 0x15d}, /* COMPOSE => Menu */ + /* Multimedia keys. Guideline is to try and follow the Microsoft standard, then fill in remaining scancodes with OEM-specific keys for redundancy sake. Keys marked with # are not translated into evdev codes by the standard atkbd driver. */ diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 8e8208dcc..a52ee7245 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1513,7 +1513,7 @@ x11_keycode_to_keysym(uint32_t keycode) # endif # ifdef EVDEV_KEYBOARD_HPP if (QApplication::platformName().contains("eglfs")) { - finalkeycode = evdev_translate(keycode); + finalkeycode = evdev_translate(keycode - 8); } else # endif { diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index 953008453..1546b6faa 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -25,7 +25,7 @@ extern "C" { #define IS_DEC_DIGIT(c) (((c) >= '0') && ((c) <= '9')) #define IS_HEX_DIGIT(c) (IS_DEC_DIGIT(c) || (((c) >= 'A') && ((c) <= 'F')) || (((c) >= 'a') && ((c) <= 'f'))) -static std::unordered_map xkb_keycodes{ +static std::unordered_map xkb_keycodes = { {"ESC", 0x01}, {"AE01", 0x02}, {"AE02", 0x03}, From 4002b71da6d96c7664bfcf8a407bcfafd0a915d4 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 18:58:26 -0300 Subject: [PATCH 23/53] qt: Remove legacy X11 input translators --- src/qt/qt_mainwindow.cpp | 371 +-------------------------------------- 1 file changed, 5 insertions(+), 366 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index a52ee7245..95b881e64 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -905,349 +905,6 @@ MainWindow::on_actionSettings_triggered() plat_pause(currentPause); } -#if defined(__unix__) && !defined(__HAIKU__) -std::array x11_to_xt_base { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0x01, - 0x02, - 0x03, - 0x04, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0A, - 0x0B, - 0x0C, - 0x0D, - 0x0E, - 0x0F, - 0x10, - 0x11, - 0x12, - 0x13, - 0x14, - 0x15, - 0x16, - 0x17, - 0x18, - 0x19, - 0x1A, - 0x1B, - 0x1C, - 0x1D, - 0x1E, - 0x1F, - 0x20, - 0x21, - 0x22, - 0x23, - 0x24, - 0x25, - 0x26, - 0x27, - 0x28, - 0x29, - 0x2A, - 0x2B, - 0x2C, - 0x2D, - 0x2E, - 0x2F, - 0x30, - 0x31, - 0x32, - 0x33, - 0x34, - 0x35, - 0x36, - 0x37, - 0x38, - 0x39, - 0x3A, - 0x3B, - 0x3C, - 0x3D, - 0x3E, - 0x3F, - 0x40, - 0x41, - 0x42, - 0x43, - 0x44, - 0x45, - 0x46, - 0x47, - 0x48, - 0x49, - 0x4A, - 0x4B, - 0x4C, - 0x4D, - 0x4E, - 0x4F, - 0x50, - 0x51, - 0x52, - 0x53, - 0x54, - 0x55, - 0x56, - 0x57, - 0x58, - 0x147, - 0x148, - 0x149, - 0, - 0x14B, - 0, - 0x14D, - 0x14F, - 0x150, - 0x151, - 0x152, - 0x153, - 0x11C, - 0x11D, - 0, // Pause/Break key. - 0x137, - 0x135, - 0x138, - 0, // Ditto as above comment. - 0x15B, - 0x15C, - 0x15D, -}; - -std::array x11_to_xt_2 { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0x01, - 0x02, - 0x03, - 0x04, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0A, - 0x0B, - 0x0C, - 0x0D, - 0x0E, - 0x0F, - 0x10, - 0x11, - 0x12, - 0x13, - 0x14, - 0x15, - 0x16, - 0x17, - 0x18, - 0x19, - 0x1A, - 0x1B, - 0x1C, - 0x1D, - 0x1E, - 0x1F, - 0x20, - 0x21, - 0x22, - 0x23, - 0x24, - 0x25, - 0x26, - 0x27, - 0x28, - 0x29, - 0x2A, - 0x2B, - 0x2C, - 0x2D, - 0x2E, - 0x2F, - 0x30, - 0x31, - 0x32, - 0x33, - 0x34, - 0x35, - 0x36, - 0x37, - 0x38, - 0x39, - 0x3A, - 0x3B, - 0x3C, - 0x3D, - 0x3E, - 0x3F, - 0x40, - 0x41, - 0x42, - 0x43, - 0x44, - 0x45, - 0x46, - 0x47, - 0x48, - 0x49, - 0x4A, - 0x4B, - 0x4C, - 0x4D, - 0x4E, - 0x4F, - 0x50, - 0x51, - 0x52, - 0x53, - 0x138, - 0x55, - 0x56, - 0x57, - 0x58, - 0x56, - 0x70, - 0x7B, - 0x7D, - 0x2B, - 0x7E, - 0, - 0x11C, - 0x11D, - 0x135, - 0x137, - 0x138, - 0, - 0x147, - 0x148, - 0x149, - 0x14B, - 0x14D, - 0x14F, - 0x150, - 0x151, - 0x152, - 0x153, - 0, - 0, /* Mute */ - 0, /* Volume Down */ - 0, /* Volume Up */ - 0, /* Power Off */ - 0, - 0, - 0, - 0, - 0, - 0x70, - 0x7B, - 0x73, - 0x15B, - 0x15C, - 0x15D -}; - -std::array x11_to_xt_vnc { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0x1D, - 0x11D, - 0x2A, - 0x36, - 0, - 0, - 0x38, - 0x138, - 0x39, - 0x0B, - 0x02, - 0x03, - 0x04, - 0x05, - 0x06, - 0x07, - 0x08, - 0x09, - 0x0A, - 0x0C, - 0x0D, - 0x1A, - 0x1B, - 0x27, - 0x28, - 0x29, - 0x33, - 0x34, - 0x35, - 0x2B, - 0x1E, - 0x30, - 0x2E, - 0x20, - 0x12, - 0x21, - 0x22, - 0x23, - 0x17, - 0x24, - 0x25, - 0x26, - 0x32, - 0x31, - 0x18, - 0x19, - 0x10, - 0x13, - 0x1F, - 0x14, - 0x16, - 0x2F, - 0x11, - 0x2D, - 0x15, - 0x2C, - 0x0E, - 0x1C, - 0x0F, - 0x01, - 0x153, - 0x147, - 0x14F, - 0x149, - 0x151, - 0x148, - 0x150, - 0x14B, - 0x14D, -}; -#endif - #ifdef Q_OS_MACOS std::array darwin_to_xt { 0x1E, @@ -1491,14 +1148,10 @@ static std::unordered_map be_to_xt = { }; #endif -#if defined(__unix__) && !defined(__HAIKU__) -static std::array &selected_keycode = x11_to_xt_base; -#endif - uint16_t x11_keycode_to_keysym(uint32_t keycode) { - uint16_t finalkeycode = 0; + uint16_t finalkeycode; #if defined(Q_OS_WINDOWS) finalkeycode = (keycode & 0xFFFF); #elif defined(Q_OS_MACOS) @@ -1507,29 +1160,15 @@ x11_keycode_to_keysym(uint32_t keycode) finalkeycode = be_to_xt[keycode]; #else # ifdef XKBCOMMON - if (xkbcommon_keymap) { + if (xkbcommon_keymap) finalkeycode = xkbcommon_translate(keycode); - } else + else # endif # ifdef EVDEV_KEYBOARD_HPP - if (QApplication::platformName().contains("eglfs")) { finalkeycode = evdev_translate(keycode - 8); - } else +# else + finalkeycode = 0; # endif - { - static Display *x11display = nullptr; - if (QApplication::platformName().contains("wayland")) { - selected_keycode = x11_to_xt_2; - } else if (!x11display) { - x11display = XOpenDisplay(nullptr); - if (XKeysymToKeycode(x11display, XK_Home) == 110) { - selected_keycode = x11_to_xt_2; - } else if (XKeysymToKeycode(x11display, XK_Home) == 69) { - selected_keycode = x11_to_xt_vnc; - } - } - finalkeycode = selected_keycode[keycode]; - } #endif /* Special case for Ctrl+Pause. */ if ((finalkeycode == 0x145) && (keyboard_recv(0x1d) || keyboard_recv(0x11d))) From b16b454bf16ac1d307d8519bede5b2aae04117af Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 19:36:48 -0300 Subject: [PATCH 24/53] qt: Add another XKB alias for Japanese Num, --- src/qt/xkbcommon_keyboard.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index 1546b6faa..39f078820 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -124,7 +124,8 @@ static std::unordered_map xkb_keycodes = { {"FK15", 0x5f}, /* Japanese keys. */ - {"JPCM", 0x5c}, /* evdev KPJPCOMMA */ + {"JPCM", 0x5c}, /* Num, */ + {"KPDC", 0x5c}, {"HKTG", 0x70}, /* hiragana-katakana toggle */ {"AB11", 0x73}, /* \_ and Brazilian /? */ {"HZTG", 0x76}, /* hankaku-zenkaku toggle */ From 218f70baace279b8f6b88dd163e72e128afc328e Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 19:39:11 -0300 Subject: [PATCH 25/53] qt: Map F13/F14/F15 using Apple equivalency again for Apple keyboards on Linux --- src/qt/evdev_keyboard.cpp | 10 ++++++---- src/qt/xkbcommon_keyboard.cpp | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/qt/evdev_keyboard.cpp b/src/qt/evdev_keyboard.cpp index 3e66dc1ed..c227eba83 100644 --- a/src/qt/evdev_keyboard.cpp +++ b/src/qt/evdev_keyboard.cpp @@ -18,14 +18,14 @@ #include static std::unordered_map evdev_keycodes = { - {99, 0x54}, /* SYSRQ */ + {184, 0x46}, /* F14 => Scroll Lock (for Apple keyboards) */ {86, 0x56}, /* 102ND */ {87, 0x57}, /* F11 */ {88, 0x58}, /* F12 */ {117, 0x59}, /* KPEQUAL */ - {183, 0x5d}, /* F13 */ - {184, 0x5e}, /* F14 */ - {185, 0x5f}, /* F15 */ + {186, 0x5d}, /* F16 => F13 */ + {187, 0x5e}, /* F17 => F14 */ + {188, 0x5f}, /* F18 => F15 */ /* Japanese keys. */ {95, 0x5c}, /* KPJPCOMMA */ @@ -47,9 +47,11 @@ static std::unordered_map evdev_keycodes = { {97, 0x11d}, /* RIGHTCTRL */ {98, 0x135}, /* KPSLASH */ {99, 0x137}, /* SYSRQ */ + {183, 0x137}, /* F13 => SysRq (for Apple keyboards) */ {100, 0x138}, /* RIGHTALT */ {119, 0x145}, /* PAUSE */ {411, 0x145}, /* BREAK */ + {185, 0x145}, /* F15 => Pause (for Apple keyboards) */ {102, 0x147}, /* HOME */ {103, 0x148}, /* UP */ {104, 0x149}, /* PAGEUP */ diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index 39f078820..f2e39298d 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -102,6 +102,7 @@ static std::unordered_map xkb_keycodes = { {"NMLK", 0x45}, {"SCLK", 0x46}, + {"FK14", 0x46}, /* F14 => Scroll Lock (for Apple keyboards) */ {"KP7", 0x47}, {"KP8", 0x48}, {"KP9", 0x49}, @@ -119,9 +120,9 @@ static std::unordered_map xkb_keycodes = { {"LSGT", 0x56}, {"FK11", 0x57}, {"FK12", 0x58}, - {"FK13", 0x5d}, - {"FK14", 0x5e}, - {"FK15", 0x5f}, + {"FK16", 0x5d}, /* F16 => F13 */ + {"FK17", 0x5e}, /* F17 => F14 */ + {"FK18", 0x5f}, /* F18 => F15 */ /* Japanese keys. */ {"JPCM", 0x5c}, /* Num, */ @@ -146,8 +147,10 @@ static std::unordered_map xkb_keycodes = { {"KPDV", 0x135}, {"PRSC", 0x137}, {"SYRQ", 0x137}, + {"FK13", 0x137}, /* F13 => SysRq (for Apple keyboards) */ {"RALT", 0x138}, {"PAUS", 0x145}, + {"FK15", 0x145}, /* F15 => Pause (for Apple keyboards) */ {"BRK", 0x145}, {"HOME", 0x147}, {"UP", 0x148}, From 85330cd6dc7bf90c32f16c1ec3f4eb665d025a57 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 19:41:09 -0300 Subject: [PATCH 26/53] qt: Remove a duplicate evdev mapping --- src/qt/evdev_keyboard.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/qt/evdev_keyboard.cpp b/src/qt/evdev_keyboard.cpp index c227eba83..4aad4e377 100644 --- a/src/qt/evdev_keyboard.cpp +++ b/src/qt/evdev_keyboard.cpp @@ -22,7 +22,6 @@ static std::unordered_map evdev_keycodes = { {86, 0x56}, /* 102ND */ {87, 0x57}, /* F11 */ {88, 0x58}, /* F12 */ - {117, 0x59}, /* KPEQUAL */ {186, 0x5d}, /* F16 => F13 */ {187, 0x5e}, /* F17 => F14 */ {188, 0x5f}, /* F18 => F15 */ From 4471849891061afd3765affeeed41637c1e0f3e6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Apr 2023 00:59:10 +0200 Subject: [PATCH 27/53] The keyboard now is now also a state machine. --- src/device/keyboard_at.c | 239 +++++++++++++++++++++++++++------------ 1 file changed, 169 insertions(+), 70 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index e440b3b07..b94343250 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -93,7 +93,10 @@ enum { KBC_STATE_RESET = 0, - KBC_STATE_NORMAL, + KBC_STATE_MAIN_IBF, + KBC_STATE_MAIN_KBD, + KBC_STATE_MAIN_MOUSE, + KBC_STATE_MAIN_BOTH, KBC_STATE_KBC_OUT, KBC_STATE_KBC_PARAM, KBC_STATE_KBD, @@ -102,6 +105,18 @@ enum { #define KBC_STATE_SCAN_KBD KBC_STATE_KBD #define KBC_STATE_SCAN_MOUSE KBC_STATE_MOUSE +enum { + DEV_STATE_RESET = 0, + DEV_STATE_MAIN_1, + DEV_STATE_MAIN_2, + DEV_STATE_MAIN_CMD, + DEV_STATE_MAIN_OUT, + DEV_STATE_MAIN_WANT_IN, + DEV_STATE_MAIN_IN, + DEV_STATE_MAIN_WANT_RESET, + DEV_STATE_RESET_OUT +}; + typedef struct { uint8_t command, status, ib, out, old_out, secr_phase, mem_addr, input_port, @@ -702,7 +717,7 @@ kbc_irq(atkbd_t *dev, uint16_t irq, int raise) { picint_common(irq, (dev->flags & KBC_TYPE_MASK) > KBC_TYPE_PS2_NOREF, raise); if (raise) - dev->irq_levels |= irq; + dev->irq_levels = irq; else dev->irq_levels &= ~irq; } @@ -814,7 +829,7 @@ kbc_ibf_process(atkbd_t *dev) { /* IBF set, process both commands and data. */ dev->status &= ~STAT_IFULL; - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; if (dev->status & STAT_CD) kbc_process_cmd(dev); else { @@ -836,7 +851,7 @@ kbc_scan_kbd_at(atkbd_t *dev) if (dev->out_new != -1) { add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); dev->out_new = -1; - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; } else if (dev->status & STAT_IFULL) kbc_ibf_process(dev); /* AT mode. */ @@ -858,9 +873,8 @@ kbc_scan_kbd_at(atkbd_t *dev) } else add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); dev->out_new = -1; - dev->kbc_state = KBC_STATE_NORMAL; - } else if (dev->status & STAT_IFULL) - kbc_ibf_process(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } } } } @@ -876,7 +890,9 @@ kbc_poll_at(atkbd_t *dev) kbc_process_cmd(dev); } break; - case KBC_STATE_NORMAL: + case KBC_STATE_MAIN_IBF: + case KBC_STATE_MAIN_MOUSE: + case KBC_STATE_SCAN_MOUSE: if (dev->status & STAT_OFULL) { /* OBF set, wait until it is cleared but still process commands. */ if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD)) { @@ -885,23 +901,28 @@ kbc_poll_at(atkbd_t *dev) } } else if (dev->status & STAT_IFULL) kbc_ibf_process(dev); - else - kbc_scan_kbd_at(dev); + else if (!(dev->mem[0x20] & 0x10)) + dev->kbc_state = KBC_STATE_MAIN_KBD; + break; + case KBC_STATE_MAIN_KBD: + case KBC_STATE_MAIN_BOTH: + (void) kbc_scan_kbd_at(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; break; case KBC_STATE_KBC_OUT: /* Keyboard controller command want to output multiple bytes. */ if (dev->status & STAT_IFULL) { /* Data from host aborts dumping. */ - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; kbc_ibf_process(dev); } /* Do not continue dumping until OBF is clear. */ if (!(dev->status & STAT_OFULL)) { - kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); + kbd_log("ATkbc: %02X coming from channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; if (key_ctrl_queue_start == key_ctrl_queue_end) - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; } break; case KBC_STATE_KBC_PARAM: @@ -909,7 +930,7 @@ kbc_poll_at(atkbd_t *dev) if (dev->status & STAT_IFULL) { /* Command written, abort current command. */ if (dev->status & STAT_CD) - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; dev->status &= ~STAT_IFULL; kbc_process_cmd(dev); @@ -921,13 +942,23 @@ kbc_poll_at(atkbd_t *dev) } } +/* + Correct Procedure: + 1. Controller asks the device (keyboard or mouse) for a byte. + 2. The device, unless it's in the reset or command states, sees if there's anything to give it, + and if yes, begins the transfer. + 3. The controller checks if there is a transfer, if yes, transfers the byte and sends it to the host, + otherwise, checks the next device, or if there is no device left to check, checks if IBF is full + and if yes, processes it. + */ static int kbc_scan_kbd_ps2(atkbd_t *dev) { if (dev->out_new != -1) { + kbd_log("ATkbc: %02X coming from channel 1\n", dev->out_new & 0xff); add_to_kbc_queue_front(dev, dev->out_new, 1, 0x00); dev->out_new = -1; - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; return 1; } @@ -938,9 +969,10 @@ static int kbc_scan_aux_ps2(atkbd_t *dev) { if (dev->out_new_mouse != -1) { + kbd_log("ATkbc: %02X coming from channel 2\n", dev->out_new_mouse & 0xff); add_to_kbc_queue_front(dev, dev->out_new_mouse, 2, 0x00); dev->out_new_mouse = -1; - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; return 1; } @@ -952,50 +984,57 @@ kbc_poll_ps2(atkbd_t *dev) { switch (dev->kbc_state) { case KBC_STATE_RESET: + // pclog("KBC_STATE_RESET\n"); if (dev->status & STAT_IFULL) { dev->status = ((dev->status & 0x0f) | 0x10) & ~STAT_IFULL; if ((dev->status & STAT_CD) && (dev->ib == 0xaa)) kbc_process_cmd(dev); } break; - case KBC_STATE_NORMAL: + case KBC_STATE_MAIN_IBF: + // pclog("KBC_STATE_MAIN_IBF\n"); if (dev->status & STAT_IFULL) kbc_ibf_process(dev); else if (!(dev->status & STAT_OFULL)) { if (dev->mem[0x20] & 0x20) { if (!(dev->mem[0x20] & 0x10)) { dev->output_port &= 0xbf; - - if (kbc_scan_kbd_ps2(dev) == 0) { - if (dev->status & STAT_IFULL) - kbc_ibf_process(dev); - } + dev->kbc_state = KBC_STATE_MAIN_KBD; } } else { dev->output_port &= 0xf7; - if (dev->mem[0x20] & 0x10) { - if (kbc_scan_aux_ps2(dev) == 0) { - if (dev->status & STAT_IFULL) - kbc_ibf_process(dev); - } - } else { + if (dev->mem[0x20] & 0x10) + dev->kbc_state = KBC_STATE_MAIN_MOUSE; + else { dev->output_port &= 0xbf; - - if (kbc_scan_kbd_ps2(dev) == 0) { - if (kbc_scan_aux_ps2(dev) == 0) { - if (dev->status & STAT_IFULL) - kbc_ibf_process(dev); - } - } + dev->kbc_state = KBC_STATE_MAIN_BOTH; } } } break; + case KBC_STATE_MAIN_KBD: + // pclog("KBC_STATE_MAIN_KBD\n"); + (void) kbc_scan_kbd_ps2(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + break; + case KBC_STATE_MAIN_MOUSE: + // pclog("KBC_STATE_MAIN_MOUSE\n"); + (void) kbc_scan_aux_ps2(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + break; + case KBC_STATE_MAIN_BOTH: + // pclog("KBC_STATE_MAIN_BOTH\n"); + if (kbc_scan_kbd_ps2(dev)) + dev->kbc_state = KBC_STATE_MAIN_IBF; + else + dev->kbc_state = KBC_STATE_MAIN_MOUSE; + break; case KBC_STATE_KBC_OUT: + // pclog("KBC_STATE_KBC_OUT\n"); /* Keyboard controller command want to output multiple bytes. */ if (dev->status & STAT_IFULL) { /* Data from host aborts dumping. */ - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; kbc_ibf_process(dev); } /* Do not continue dumping until OBF is clear. */ @@ -1004,29 +1043,104 @@ kbc_poll_ps2(atkbd_t *dev) add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; if (key_ctrl_queue_start == key_ctrl_queue_end) - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; } break; case KBC_STATE_KBC_PARAM: + // pclog("KBC_STATE_KBC_PARAM\n"); /* Keyboard controller command wants data, wait for said data. */ if (dev->status & STAT_IFULL) { /* Command written, abort current command. */ if (dev->status & STAT_CD) - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; dev->status &= ~STAT_IFULL; kbc_process_cmd(dev); } break; case KBC_STATE_SCAN_KBD: + // pclog("KBC_STATE_SCAN_KBD\n"); (void) kbc_scan_kbd_ps2(dev); break; case KBC_STATE_SCAN_MOUSE: + // pclog("KBC_STATE_SCAN_MOUSE\n"); (void) kbc_scan_aux_ps2(dev); break; } } +static void +kbc_poll_kbd(atkbd_t *dev) +{ + switch (dev->kbd_state) { + case DEV_STATE_RESET: + /* Reset state. */ + if (dev->reset_delay) { + dev->reset_delay--; + if (!dev->reset_delay) { + kbd_log("ATkbc: Sending AA on keyboard reset...\n"); + add_data_kbd_front(dev, 0xaa); + dev->kbd_state = DEV_STATE_RESET_OUT; + } + } + break; + case DEV_STATE_MAIN_1: + /* Process the command if needed and then return to main loop #2. */ + if (dev->key_wantcmd) { + kbd_log("ATkbc: Processing keyboard command...\n"); + kbd_process_cmd(dev); + dev->key_wantcmd = 0; + } else + dev->kbd_state = DEV_STATE_MAIN_2; + break; + case DEV_STATE_MAIN_2: + /* Output from scan queue if needed and then return to main loop #1. */ + if (keyboard_scan && (key_queue_start != key_queue_end)) { + kbd_log("ATkbc: %02X (DATA) on channel 1\n", key_queue[key_queue_start]); + dev->out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } + dev->kbd_state = DEV_STATE_MAIN_1; + break; + case DEV_STATE_MAIN_OUT: + case DEV_STATE_RESET_OUT: + /* Output command resposne and then return to main loop #2. */ + if (key_cmd_queue_start != key_cmd_queue_end) { + kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); + dev->out_new = key_cmd_queue[key_cmd_queue_start]; + key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; + } + dev->kbd_state = (dev->kbd_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; + break; + case DEV_STATE_MAIN_WANT_IN: + /* Output command response and then wait for host data. */ + if (key_cmd_queue_start != key_cmd_queue_end) { + kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); + dev->out_new = key_cmd_queue[key_cmd_queue_start]; + key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; + } + dev->kbd_state = DEV_STATE_MAIN_IN; + break; + case DEV_STATE_MAIN_IN: + /* Wait for host data. */ + if (dev->key_wantcmd) { + kbd_log("ATkbc: Processing keyboard command...\n"); + kbd_process_cmd(dev); + dev->key_wantcmd = 0; + } + break; + case DEV_STATE_MAIN_WANT_RESET: + /* Output command response and then go to the reset state. */ + if (key_cmd_queue_start != key_cmd_queue_end) { + kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); + dev->out_new = key_cmd_queue[key_cmd_queue_start]; + key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; + } + dev->kbd_state = DEV_STATE_RESET; + break; + } +} + /* TODO: State machines for controller, keyboard, and mouse. */ static void kbd_poll(void *priv) @@ -1042,31 +1156,7 @@ kbd_poll(void *priv) else kbc_poll_ps2(dev); - if (dev->reset_delay) { - dev->reset_delay--; - if (!dev->reset_delay) { - kbd_log("ATkbc: Sending AA on keyboard reset...\n"); - add_data_kbd_front(dev, 0xaa); - } - } else if (dev->key_wantcmd) { - if ((key_cmd_queue_start == key_cmd_queue_end) && (dev->out_new == -1) && (dev->reset_delay == 0)) { - kbd_log("ATkbc: Processing keyboard command...\n"); - kbd_process_cmd(dev); - dev->key_wantcmd = 0; - } - return; - } - if (dev->out_new == -1) { - if (key_cmd_queue_start != key_cmd_queue_end) { - kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); - dev->out_new = key_cmd_queue[key_cmd_queue_start]; - key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; - } else if (key_queue_start != key_queue_end) { - kbd_log("ATkbc: %02X (DATA) on channel 1\n", key_queue[key_queue_start]); - dev->out_new = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - } - } + kbc_poll_kbd(dev); if (dev->mouse_reset_delay) { dev->mouse_reset_delay--; @@ -1082,8 +1172,7 @@ kbd_poll(void *priv) // dev->mouse_reset_delay = RESET_DELAY_TIME; dev->mouse_wantcmd = 0; } - } - if (dev->out_new_mouse == -1) { + } else if (dev->out_new_mouse == -1) { if (mouse_cmd_queue_start != mouse_cmd_queue_end) { kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; @@ -2085,6 +2174,11 @@ kbd_key_reset(atkbd_t *dev, int do_fa) keyboard_scan = 1; dev->reset_delay = RESET_DELAY_TIME; + + if (do_fa) + dev->kbd_state = DEV_STATE_MAIN_WANT_RESET; + else + dev->kbd_state = DEV_STATE_RESET; } static void @@ -2095,6 +2189,8 @@ kbd_process_cmd(void *priv) /* Write data to keyboard. */ dev->mem[0x20] &= ~0x10; + dev->kbd_state = DEV_STATE_MAIN_OUT; + if (dev->key_wantdata) { dev->key_wantdata = 0; @@ -2159,6 +2255,7 @@ kbd_process_cmd(void *priv) add_data_kbd_raw(dev, 0xfa); dev->key_wantdata = 1; + dev->kbd_state = DEV_STATE_MAIN_WANT_IN; break; case 0xee: /* diagnostic echo */ @@ -2174,6 +2271,7 @@ kbd_process_cmd(void *priv) kbd_log("ATkbd: scan code set\n"); add_data_kbd_raw(dev, 0xfa); dev->key_wantdata = 1; + dev->kbd_state = DEV_STATE_MAIN_WANT_IN; break; case 0xf2: /* read ID */ @@ -2190,6 +2288,7 @@ kbd_process_cmd(void *priv) kbd_log("ATkbd: set typematic rate/delay\n"); add_data_kbd_raw(dev, 0xfa); dev->key_wantdata = 1; + dev->kbd_state = DEV_STATE_MAIN_WANT_IN; break; case 0xf4: /* enable keyboard */ @@ -2270,7 +2369,7 @@ kbc_process_cmd(void *priv) if (dev->status & STAT_CD) { /* Controller command. */ dev->want60 = 0; - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; /* Clear the keyboard controller queue. */ kbc_queue_reset(0); @@ -2328,7 +2427,7 @@ kbc_process_cmd(void *priv) } kbc_queue_reset(0); - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; add_to_kbc_queue_front(dev, 0x55, 0, 0x00); break; @@ -2433,7 +2532,7 @@ kbc_process_cmd(void *priv) } else if (dev->want60) { /* Write data to controller. */ dev->want60 = 0; - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; switch (dev->command) { case 0x60 ... 0x7f: @@ -2529,7 +2628,7 @@ kbd_write(uint16_t port, uint8_t val, void *priv) } write_output(dev, val | 0x01); dev->want60 = 0; - dev->kbc_state = KBC_STATE_NORMAL; + dev->kbc_state = KBC_STATE_MAIN_IBF; return; } break; @@ -2644,7 +2743,7 @@ kbd_reset(void *priv) dev->kbc_state = KBC_STATE_RESET; /* Reset the keyboard. */ - // kbd_key_reset(dev, 0); + kbd_key_reset(dev, 0); } /* Reset the AT keyboard - this is needed for the PCI TRC and is done From 68e49b75bcf8c7d21961a16bc74e64501aa3cc45 Mon Sep 17 00:00:00 2001 From: richardg867 Date: Sat, 8 Apr 2023 20:30:07 -0300 Subject: [PATCH 28/53] Jenkins: Clean pacman cache after update --- .ci/build.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.ci/build.sh b/.ci/build.sh index a61cdc7f9..fc7290f4a 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -316,6 +316,9 @@ then pacman -S --needed --noconfirm "$pkg" done fi + + # Clean pacman cache when running under Jenkins to save disk space. + [ "$CI" = "true" ] && rm -rf /var/cache/pacman/pkg # Generate a new freetype DLL for this architecture. rm -f "$freetype_dll" From 897f6a44e86a84aa3fb9ffb6feede87abc01a4ca Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 21:42:06 -0300 Subject: [PATCH 29/53] qt: Attempt fix for Pause key with the new mappers --- src/qt/qt_mainwindow.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 95b881e64..b51a8a360 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1394,12 +1394,19 @@ MainWindow::keyPressEvent(QKeyEvent *event) keyboard_input(1, 0x1D); keyboard_input(1, 0x45); } - } else + } else { #ifdef Q_OS_MACOS processMacKeyboardInput(true, event); #else - keyboard_input(1, x11_keycode_to_keysym(event->nativeScanCode())); + auto scan = x11_keycode_to_keysym(event->nativeVirtualKey()); + if (scan == 0x145) { + /* Special case for Pause. */ + keyboard_input(1, scan & 0xff00); + scan &= 0x00ff; + } + keyboard_input(1, scan); #endif + } } if ((video_fullscreen > 0) && keyboard_isfsexit()) { @@ -1446,7 +1453,13 @@ MainWindow::keyReleaseEvent(QKeyEvent *event) #ifdef Q_OS_MACOS processMacKeyboardInput(false, event); #else - keyboard_input(0, x11_keycode_to_keysym(event->nativeScanCode())); + auto scan = x11_keycode_to_keysym(event->nativeVirtualKey()); + if (scan == 0x145) { + /* Special case for Pause. */ + keyboard_input(0, scan & 0xff00); + scan &= 0x00ff; + } + keyboard_input(0, scan); #endif } From b447cc85c91b3dd5b782c06d59e176803ab89840 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 21:48:01 -0300 Subject: [PATCH 30/53] qt: Add AltGr XKB alias --- src/qt/xkbcommon_keyboard.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index f2e39298d..e3a058ed2 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -149,6 +149,7 @@ static std::unordered_map xkb_keycodes = { {"SYRQ", 0x137}, {"FK13", 0x137}, /* F13 => SysRq (for Apple keyboards) */ {"RALT", 0x138}, + {"ALGR", 0x138}, {"PAUS", 0x145}, {"FK15", 0x145}, /* F15 => Pause (for Apple keyboards) */ {"BRK", 0x145}, From 5b6965402abcebcbfb538f91771b6e68a0ed06fc Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sat, 8 Apr 2023 21:49:04 -0300 Subject: [PATCH 31/53] qt: Fix key translation screw-up --- src/qt/qt_mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index b51a8a360..89e010702 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1398,7 +1398,7 @@ MainWindow::keyPressEvent(QKeyEvent *event) #ifdef Q_OS_MACOS processMacKeyboardInput(true, event); #else - auto scan = x11_keycode_to_keysym(event->nativeVirtualKey()); + auto scan = x11_keycode_to_keysym(event->nativeScanCode()); if (scan == 0x145) { /* Special case for Pause. */ keyboard_input(1, scan & 0xff00); @@ -1453,7 +1453,7 @@ MainWindow::keyReleaseEvent(QKeyEvent *event) #ifdef Q_OS_MACOS processMacKeyboardInput(false, event); #else - auto scan = x11_keycode_to_keysym(event->nativeVirtualKey()); + auto scan = x11_keycode_to_keysym(event->nativeScanCode()); if (scan == 0x145) { /* Special case for Pause. */ keyboard_input(0, scan & 0xff00); From 7b76b2af27abe74e8010a880e3a64a54ff192382 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Apr 2023 04:36:28 +0200 Subject: [PATCH 32/53] The PS/2 mouse poll is now also a state machine and fixed output port writes on AMI PS/2 keyboard controllers - fixes PS/2 mouse in Windows 3.1 on some machines. --- src/device/keyboard_at.c | 189 ++++++++++++++++++++++++++++----------- src/device/mouse_ps2.c | 41 +++++---- 2 files changed, 161 insertions(+), 69 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index b94343250..b0308529d 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -834,7 +834,6 @@ kbc_ibf_process(atkbd_t *dev) kbc_process_cmd(dev); else { set_enable_kbd(dev, 1); - kbc_queue_reset(4); dev->key_wantcmd = 1; dev->key_dat = dev->ib; dev->kbc_state = KBC_STATE_SCAN_KBD; @@ -1088,6 +1087,8 @@ kbc_poll_kbd(atkbd_t *dev) /* Process the command if needed and then return to main loop #2. */ if (dev->key_wantcmd) { kbd_log("ATkbc: Processing keyboard command...\n"); + kbc_queue_reset(4); + // dev->out_new = -1; kbd_process_cmd(dev); dev->key_wantcmd = 0; } else @@ -1095,48 +1096,141 @@ kbc_poll_kbd(atkbd_t *dev) break; case DEV_STATE_MAIN_2: /* Output from scan queue if needed and then return to main loop #1. */ - if (keyboard_scan && (key_queue_start != key_queue_end)) { + if (keyboard_scan && (dev->out_new == -1) && (key_queue_start != key_queue_end)) { kbd_log("ATkbc: %02X (DATA) on channel 1\n", key_queue[key_queue_start]); dev->out_new = key_queue[key_queue_start]; key_queue_start = (key_queue_start + 1) & 0xf; } - dev->kbd_state = DEV_STATE_MAIN_1; + if (!keyboard_scan || (key_cmd_queue_start == key_cmd_queue_end)) + dev->kbd_state = DEV_STATE_MAIN_1; break; case DEV_STATE_MAIN_OUT: case DEV_STATE_RESET_OUT: - /* Output command resposne and then return to main loop #2. */ - if (key_cmd_queue_start != key_cmd_queue_end) { + /* Output command response and then return to main loop #2. */ + if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); dev->out_new = key_cmd_queue[key_cmd_queue_start]; key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; } - dev->kbd_state = (dev->kbd_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; + if (key_cmd_queue_start == key_cmd_queue_end) + dev->kbd_state = (dev->kbd_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; break; case DEV_STATE_MAIN_WANT_IN: /* Output command response and then wait for host data. */ - if (key_cmd_queue_start != key_cmd_queue_end) { + if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); dev->out_new = key_cmd_queue[key_cmd_queue_start]; key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; } - dev->kbd_state = DEV_STATE_MAIN_IN; + if (key_cmd_queue_start == key_cmd_queue_end) + dev->kbd_state = DEV_STATE_MAIN_IN; break; case DEV_STATE_MAIN_IN: /* Wait for host data. */ if (dev->key_wantcmd) { kbd_log("ATkbc: Processing keyboard command...\n"); + kbc_queue_reset(4); + // dev->out_new = -1; kbd_process_cmd(dev); dev->key_wantcmd = 0; } break; case DEV_STATE_MAIN_WANT_RESET: /* Output command response and then go to the reset state. */ - if (key_cmd_queue_start != key_cmd_queue_end) { + if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); dev->out_new = key_cmd_queue[key_cmd_queue_start]; key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; } - dev->kbd_state = DEV_STATE_RESET; + if (key_cmd_queue_start == key_cmd_queue_end) + dev->kbd_state = DEV_STATE_RESET; + break; + } +} + +static void +kbc_poll_aux(atkbd_t *dev) +{ + switch (dev->mouse_state) { +#if 0 + case DEV_STATE_RESET: + /* Reset state. */ + if (dev->mouse_reset_delay) { + dev->mouse_reset_delay--; + if (!dev->mouse_reset_delay) { + kbd_log("ATkbc: Sending AA 00 on mouse reset...\n"); + keyboard_at_adddata_mouse_cmd(0xaa); + keyboard_at_adddata_mouse_cmd(0x00); + dev->mouse_state = DEV_STATE_RESET_OUT; + } + } + break; +#endif + case DEV_STATE_MAIN_1: + /* Process the command if needed and then return to main loop #2. */ + if (dev->mouse_wantcmd) { + kbd_log("ATkbc: Processing mouse command...\n"); + kbc_queue_reset(3); + // dev->out_new_mouse = -1; + dev->mouse_state = DEV_STATE_MAIN_OUT; + mouse_write(dev->mouse_dat, mouse_p); + if ((dev->mouse_dat == 0xe8) || (dev->mouse_dat == 0xf3)) + dev->mouse_state = DEV_STATE_MAIN_WANT_IN; + dev->mouse_wantcmd = 0; + } else + dev->mouse_state = DEV_STATE_MAIN_2; + break; + case DEV_STATE_MAIN_2: + /* Output from scan queue if needed and then return to main loop #1. */ + if (mouse_scan && (dev->out_new_mouse == -1) && (mouse_queue_start != mouse_queue_end)) { + kbd_log("ATkbc: %02X (DATA) on channel 2\n", mouse_queue[mouse_queue_start]); + dev->out_new_mouse = mouse_queue[mouse_queue_start]; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } + if (!mouse_scan || (mouse_cmd_queue_start == mouse_cmd_queue_end)) + dev->mouse_state = DEV_STATE_MAIN_1; + break; + case DEV_STATE_MAIN_OUT: + case DEV_STATE_RESET_OUT: + /* Output command response and then return to main loop #2. */ + if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); + dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; + mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + } + if (mouse_cmd_queue_start == mouse_cmd_queue_end) + dev->mouse_state = (dev->mouse_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; + break; + case DEV_STATE_MAIN_WANT_IN: + /* Output command response and then wait for host data. */ + if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); + dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; + mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + } + if (mouse_cmd_queue_start == mouse_cmd_queue_end) + dev->mouse_state = DEV_STATE_MAIN_IN; + break; + case DEV_STATE_MAIN_IN: + /* Wait for host data. */ + if (dev->mouse_wantcmd) { + kbd_log("ATkbc: Processing mouse command...\n"); + kbc_queue_reset(3); + // dev->out_new_mouse = -1; + dev->mouse_state = DEV_STATE_MAIN_OUT; + mouse_write(dev->mouse_dat, mouse_p); + dev->mouse_wantcmd = 0; + } + break; + case DEV_STATE_MAIN_WANT_RESET: + /* Output command response and then go to the reset state. */ + if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); + dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; + mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + } + if (mouse_cmd_queue_start == mouse_cmd_queue_end) + dev->mouse_state = DEV_STATE_RESET; break; } } @@ -1151,38 +1245,15 @@ kbd_poll(void *priv) /* TODO: Use a fuction pointer for this (also needed to the AMI KBC mode switching) and implement the password security state. */ - if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) - kbc_poll_at(dev); - else + if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) kbc_poll_ps2(dev); + else + kbc_poll_at(dev); kbc_poll_kbd(dev); - if (dev->mouse_reset_delay) { - dev->mouse_reset_delay--; - if (!dev->mouse_reset_delay) { - kbd_log("ATkbc: Sending AA 00 on mouse reset...\n"); - // keyboard_at_adddata_mouse_cmd(0xaa); - // keyboard_at_adddata_mouse_cmd(0x00); - } - } else if (dev->mouse_wantcmd) { - if ((mouse_cmd_queue_start == mouse_cmd_queue_end) && (dev->out_new == -1) && (dev->mouse_reset_delay == 0)) { - mouse_write(dev->mouse_dat, mouse_p); - // if (dev->mouse_dat == 0xff) - // dev->mouse_reset_delay = RESET_DELAY_TIME; - dev->mouse_wantcmd = 0; - } - } else if (dev->out_new_mouse == -1) { - if (mouse_cmd_queue_start != mouse_cmd_queue_end) { - kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); - dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; - mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; - } else if (mouse_queue_start != mouse_queue_end) { - kbd_log("ATkbc: %02X (DATA) on channel 2\n", mouse_queue[mouse_queue_start]); - dev->out_new_mouse = mouse_queue[mouse_queue_start]; - mouse_queue_start = (mouse_queue_start + 1) & 0xf; - } - } + if (((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) && mouse_write) + kbc_poll_aux(dev); } static void @@ -1549,8 +1620,7 @@ write_cmd(atkbd_t *dev, uint8_t val) kbd_log("ATkbc: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); } - if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) || - (kbc_ven == KBC_VEN_TG_GREEN) || ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF)) { + if ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF) { /* Update the output port to mirror the IBF and OBF bits, if active. */ write_output(dev, (dev->output_port & 0x0f) | ((val & 0x03) << 4) | ((val & 0x20) ? 0xc0 : 0x00)); } @@ -1685,8 +1755,6 @@ write64_generic(void *priv, uint8_t val) case 0xd4: /* write to mouse */ kbd_log("ATkbc: write to mouse\n"); - set_enable_mouse(dev, 1); - kbc_queue_reset(3); dev->want60 = 1; dev->kbc_state = KBC_STATE_KBC_PARAM; return 0; @@ -2169,10 +2237,11 @@ kbd_key_reset(atkbd_t *dev, int do_fa) keyboard_mode = (keyboard_mode & 0xfc) | 0x02; set_scancode_map(dev); + keyboard_scan = 1; + if (do_fa) add_data_kbd_raw(dev, 0xfa); - keyboard_scan = 1; dev->reset_delay = RESET_DELAY_TIME; if (do_fa) @@ -2181,14 +2250,30 @@ kbd_key_reset(atkbd_t *dev, int do_fa) dev->kbd_state = DEV_STATE_RESET; } +static void +kbd_aux_reset(atkbd_t *dev, int do_fa) +{ + kbc_queue_reset(2); + + mouse_scan = 1; + + if (!do_fa) + dev->mouse_state = DEV_STATE_MAIN_1; +} + +void +keyboard_at_mouse_reset(void) +{ + atkbd_t *dev = SavedKbd; + + kbd_aux_reset(dev, 1); +} + static void kbd_process_cmd(void *priv) { atkbd_t *dev = (atkbd_t *) priv; - /* Write data to keyboard. */ - dev->mem[0x20] &= ~0x10; - dev->kbd_state = DEV_STATE_MAIN_OUT; if (dev->key_wantdata) { @@ -2579,10 +2664,9 @@ kbc_process_cmd(void *priv) if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { set_enable_mouse(dev, 1); if (mouse_write) { - kbc_queue_reset(3); dev->mouse_wantcmd = 1; dev->mouse_dat = dev->ib; - dev->kbc_state = KBC_STATE_MOUSE; + dev->kbc_state = KBC_STATE_SCAN_MOUSE; } else add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); } @@ -2744,6 +2828,9 @@ kbd_reset(void *priv) /* Reset the keyboard. */ kbd_key_reset(dev, 0); + + /* Reset the mouse. */ + kbd_aux_reset(dev, 0); } /* Reset the AT keyboard - this is needed for the PCI TRC and is done @@ -3173,12 +3260,6 @@ keyboard_at_adddata_mouse_cmd(uint8_t val) kbc_queue_add(dev, val, 3); } -void -keyboard_at_mouse_reset(void) -{ - kbc_queue_reset(2); -} - uint8_t keyboard_at_mouse_pos(void) { diff --git a/src/device/mouse_ps2.c b/src/device/mouse_ps2.c index 1fb2442ac..1c8e0334d 100644 --- a/src/device/mouse_ps2.c +++ b/src/device/mouse_ps2.c @@ -85,15 +85,24 @@ static void ps2_report_coordinates(mouse_t *dev, int cmd) { uint8_t buff[3] = { 0x08, 0x00, 0x00 }; + int temp_z; - if (dev->x > 255) + if (dev->x > 255) { dev->x = 255; - if (dev->x < -256) + buff[0] |= 0x40; + } + if (dev->x < -256) { dev->x = -256; - if (dev->y > 255) + buff[0] |= 0x40; + } + if (dev->y > 255) { dev->y = 255; - if (dev->y < -256) + buff[0] |= 0x80; + } + if (dev->y < -256) { dev->y = -256; + buff[0] |= 0x80; + } if (dev->z < -8) dev->z = -8; if (dev->z > 7) @@ -124,13 +133,16 @@ ps2_report_coordinates(mouse_t *dev, int cmd) keyboard_at_adddata_mouse(buff[2]); } if (dev->flags & FLAG_INTMODE) { - int temp_z = dev->z; + temp_z = dev->z & 0x0f; if ((dev->flags & FLAG_5BTN)) { - temp_z &= 0xF; if (mouse_buttons & 8) temp_z |= 0x10; if (mouse_buttons & 16) temp_z |= 0x20; + } else { + /* The wheel coordinate is sign-extended. */ + if (temp_z & 0x08) + temp_z |= 0xf0; } if (cmd) keyboard_at_adddata_mouse_cmd(temp_z); @@ -262,16 +274,15 @@ mouse_reset: dev->last_data[5] = val; - if (dev->last_data[0] == 0xf3 && dev->last_data[1] == 0xc8 - && dev->last_data[2] == 0xf3 && dev->last_data[3] == 0xc8 - && dev->last_data[4] == 0xf3 && dev->last_data[5] == 0x50 - && mouse_get_buttons() == 5) { - dev->flags |= FLAG_INTMODE | FLAG_5BTN; - } else if (dev->last_data[0] == 0xf3 && dev->last_data[1] == 0xc8 - && dev->last_data[2] == 0xf3 && dev->last_data[3] == 0x64 - && dev->last_data[4] == 0xf3 && dev->last_data[5] == 0x50) { + if ((dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) && + (dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0x64) && + (dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50)) dev->flags |= FLAG_INTMODE; - } + + if ((dev->flags & FLAG_INTMODE) && (dev->last_data[0] == 0xf3) && (dev->last_data[1] == 0xc8) && + (dev->last_data[2] == 0xf3) && (dev->last_data[3] == 0xc8) && + (dev->last_data[4] == 0xf3) && (dev->last_data[5] == 0x50)) + dev->flags |= FLAG_5BTN; } } From af8575b47b4413f2bc39fa782a616e65ede6f1dc Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Apr 2023 04:57:48 +0200 Subject: [PATCH 33/53] Made keyboard_input() correctly translate 0xe11d into the 0x0100 special case. --- src/device/keyboard.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 74bf3f67e..38d65b408 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -125,9 +125,13 @@ key_process(uint16_t scan, int down) void keyboard_input(int down, uint16_t scan) { + /* Special case for E1 1D, translate it to 0100 - special case. */ + if ((scan >> 8) == 0xe1) { + if ((scan & 0xff) == 0x1d) + scan = 0x0100; /* Translate E0 xx scan codes to 01xx because we use 512-byte arrays for states and scan code sets. */ - if ((scan >> 8) == 0xe0) { + } else if ((scan >> 8) == 0xe0) { scan &= 0x00ff; scan |= 0x0100; /* extended key code */ } else if ((scan >> 8) != 0x01) From 4eb902d85384ba9b3541cd9f37c64b569ebfb86b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Apr 2023 19:44:15 +0200 Subject: [PATCH 34/53] More keyboard controller fixes. --- src/cpu/x86.c | 14 ++++++-- src/device/keyboard_at.c | 64 ++++++++++++++++++++++++++++++------ src/include/86box/keyboard.h | 1 + src/mem/mem.c | 5 +-- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/cpu/x86.c b/src/cpu/x86.c index eb1dc463f..47250045f 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -29,6 +29,7 @@ #include <86box/device.h> #include <86box/dma.h> #include <86box/io.h> +#include <86box/keyboard.h> #include <86box/mem.h> #include <86box/rom.h> #include <86box/nmi.h> @@ -265,9 +266,12 @@ reset_common(int hard) if (is286) { loadcs(0xF000); cpu_state.pc = 0xFFF0; - rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; - if (is6117) - rammask |= 0x03000000; + if (hard) { + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + if (is6117) + rammask |= 0x03000000; + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + } } idt.base = 0; cpu_state.flags = 2; @@ -315,6 +319,10 @@ reset_common(int hard) cache_index = 0; memset(_tr, 0x00, sizeof(_tr)); memset(_cache, 0x00, sizeof(_cache)); + + /* If we have an AT or PS/2 keyboard controller, make sure the A20 state + is correct. */ + kbc_at_a20_reset(); } if (!is286) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index b0308529d..bfa6fa0be 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -878,6 +878,8 @@ kbc_scan_kbd_at(atkbd_t *dev) } } +static void write_output(atkbd_t *dev, uint8_t val); + static void kbc_poll_at(atkbd_t *dev) { @@ -905,8 +907,12 @@ kbc_poll_at(atkbd_t *dev) break; case KBC_STATE_MAIN_KBD: case KBC_STATE_MAIN_BOTH: - (void) kbc_scan_kbd_at(dev); - dev->kbc_state = KBC_STATE_MAIN_IBF; + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_kbd_at(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } break; case KBC_STATE_KBC_OUT: /* Keyboard controller command want to output multiple bytes. */ @@ -1013,13 +1019,21 @@ kbc_poll_ps2(atkbd_t *dev) break; case KBC_STATE_MAIN_KBD: // pclog("KBC_STATE_MAIN_KBD\n"); - (void) kbc_scan_kbd_ps2(dev); - dev->kbc_state = KBC_STATE_MAIN_IBF; + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_kbd_ps2(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } break; case KBC_STATE_MAIN_MOUSE: // pclog("KBC_STATE_MAIN_MOUSE\n"); - (void) kbc_scan_aux_ps2(dev); - dev->kbc_state = KBC_STATE_MAIN_IBF; + if (dev->status & STAT_IFULL) + kbc_ibf_process(dev); + else { + (void) kbc_scan_aux_ps2(dev); + dev->kbc_state = KBC_STATE_MAIN_IBF; + } break; case KBC_STATE_MAIN_BOTH: // pclog("KBC_STATE_MAIN_BOTH\n"); @@ -2230,7 +2244,9 @@ write64_toshiba(void *priv, uint8_t val) static void kbd_key_reset(atkbd_t *dev, int do_fa) { + dev->out_new = -1; kbc_queue_reset(1); + kbd_last_scan_code = 0x00; /* Set scan code set to 2. */ @@ -2253,6 +2269,7 @@ kbd_key_reset(atkbd_t *dev, int do_fa) static void kbd_aux_reset(atkbd_t *dev, int do_fa) { + dev->out_new_mouse = -1; kbc_queue_reset(2); mouse_scan = 1; @@ -2475,7 +2492,15 @@ kbc_process_cmd(void *priv) kbd_log("ATkbc: self-test\n"); if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { - dev->status = 0x60; + if (dev->kbc_state != KBC_STATE_RESET) { + kbd_log("ATkbc: self-test reinitialization\n"); + /* Yes, the firmware has an OR, but we need to make sure to keep any forcibly lowered bytes lowered. */ + /* TODO: Proper P1 implementation, with OR and AND flags in the machine table. */ + dev->input_port = dev->input_port & 0xff; + write_output(dev, 0x4b); + } + + dev->status = (dev->status & 0x0f) | 0x60; dev->mem[0x20] = 0x30; dev->mem[0x21] = 0x01; @@ -2497,7 +2522,7 @@ kbc_process_cmd(void *priv) write_output(dev, 0xcf); } - dev->status = 0x60; + dev->status = (dev->status & 0x0f) | 0x60; dev->mem[0x20] = 0x10; dev->mem[0x21] = 0x01; @@ -2511,10 +2536,14 @@ kbc_process_cmd(void *priv) dev->mem[0x2c] = 0x15; } + dev->out_new = dev->out_new_mouse = -1; kbc_queue_reset(0); - dev->kbc_state = KBC_STATE_MAIN_IBF; - add_to_kbc_queue_front(dev, 0x55, 0, 0x00); + // dev->kbc_state = KBC_STATE_MAIN_IBF; + dev->kbc_state = KBC_STATE_KBC_OUT; + + // add_to_kbc_queue_front(dev, 0x55, 0, 0x00); + kbc_queue_add(dev, 0x55, 0); break; case 0xab: /* interface test */ @@ -2814,6 +2843,7 @@ kbd_reset(void *priv) dev->ami_flags = ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) ? 0x01 : 0x00; dev->ami_stat |= 0x02; + dev->output_port = 0xcd; if ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { write_output(dev, 0x4b); } else { @@ -2841,6 +2871,20 @@ keyboard_at_reset(void) kbd_reset(SavedKbd); } +void +kbc_at_a20_reset(void) +{ + if (SavedKbd) { + SavedKbd->output_port = 0xcd; + if ((SavedKbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF) { + write_output(SavedKbd, 0x4b); + } else { + /* The real thing writes CF and then AND's it with BF. */ + write_output(SavedKbd, 0x8f); + } + } +} + static void kbd_close(void *priv) { diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index 767ffdca7..0fd25dbd0 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -210,6 +210,7 @@ extern void keyboard_at_set_mode(int ps2); extern uint8_t keyboard_at_get_mouse_scan(void); extern void keyboard_at_set_mouse_scan(uint8_t val); extern void keyboard_at_reset(void); +extern void kbc_at_a20_reset(void); #ifdef __cplusplus } diff --git a/src/mem/mem.c b/src/mem/mem.c index 1af83c844..9de4a670f 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -2530,11 +2530,12 @@ void mem_a20_init(void) { if (is286) { - rammask = cpu_16bitbus ? 0xefffff : 0xffefffff; + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + rammask = cpu_16bitbus ? 0xffffff : 0xffffffff; if (is6117) rammask |= 0x03000000; flushmmucache(); - mem_a20_state = mem_a20_key | mem_a20_alt; + // mem_a20_state = mem_a20_key | mem_a20_alt; } else { rammask = 0xfffff; flushmmucache(); From 579e5ce8ff35161b64493ac561f8897f47e95079 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 16:36:36 -0300 Subject: [PATCH 35/53] qt: Fix Pause key on Linux --- src/qt/qt_mainwindow.cpp | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 89e010702..1801f6160 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1382,31 +1382,17 @@ void MainWindow::keyPressEvent(QKeyEvent *event) { if (send_keyboard_input && !(kbd_req_capture && !mouse_capture)) { - // Windows keys in Qt have one-to-one mapping. - if (event->key() == Qt::Key_Pause && !keyboard_recv(0x38) && !keyboard_recv(0x138)) { - if ((keyboard_recv(0x1D) || keyboard_recv(0x11D))) { - keyboard_input(1, 0x46); - } else { - keyboard_input(0, 0xE1); - keyboard_input(0, 0x1D); - keyboard_input(0, 0x45); - keyboard_input(0, 0xE1); - keyboard_input(1, 0x1D); - keyboard_input(1, 0x45); - } - } else { #ifdef Q_OS_MACOS - processMacKeyboardInput(true, event); + processMacKeyboardInput(true, event); #else - auto scan = x11_keycode_to_keysym(event->nativeScanCode()); - if (scan == 0x145) { - /* Special case for Pause. */ - keyboard_input(1, scan & 0xff00); - scan &= 0x00ff; - } - keyboard_input(1, scan); -#endif + auto scan = x11_keycode_to_keysym(event->nativeScanCode()); + if (scan == 0x145) { + /* Special case for Pause. */ + keyboard_input(1, 0xe11d); + scan &= 0x00ff; } + keyboard_input(1, scan); +#endif } if ((video_fullscreen > 0) && keyboard_isfsexit()) { @@ -1456,7 +1442,7 @@ MainWindow::keyReleaseEvent(QKeyEvent *event) auto scan = x11_keycode_to_keysym(event->nativeScanCode()); if (scan == 0x145) { /* Special case for Pause. */ - keyboard_input(0, scan & 0xff00); + keyboard_input(0, 0xe11d); scan &= 0x00ff; } keyboard_input(0, scan); From 95f94bf57f6621578aed183aeb7b654859f20867 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 16:36:47 -0300 Subject: [PATCH 36/53] qt: Clarify a specific evdev mapping --- src/qt/evdev_keyboard.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/evdev_keyboard.cpp b/src/qt/evdev_keyboard.cpp index 4aad4e377..505618ef7 100644 --- a/src/qt/evdev_keyboard.cpp +++ b/src/qt/evdev_keyboard.cpp @@ -69,7 +69,7 @@ static std::unordered_map evdev_keycodes = { /* Multimedia keys. Guideline is to try and follow the Microsoft standard, then fill in remaining scancodes with OEM-specific keys for redundancy sake. Keys marked with # are not translated into evdev codes by the standard atkbd driver. */ - {117, 0x59}, /* Num= */ + {117, 0x59}, /* KPEQUAL */ {418, 0x6a}, /* ZOOMIN# => Logitech */ {420, 0x6b}, /* ZOOMRESET# => Logitech */ {223, 0x6d}, /* CANCEL# => Logitech */ From 9c49b53c0800c4ad93874121a0af6edc504cc165 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 17:04:57 -0300 Subject: [PATCH 37/53] qt: Fix Print Screen key on Linux --- src/qt/qt_mainwindow.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 1801f6160..03db77721 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1170,8 +1170,10 @@ x11_keycode_to_keysym(uint32_t keycode) finalkeycode = 0; # endif #endif - /* Special case for Ctrl+Pause. */ - if ((finalkeycode == 0x145) && (keyboard_recv(0x1d) || keyboard_recv(0x11d))) + /* Special case for Alt+Print Screen and Ctrl+Pause. */ + if ((finalkeycode == 0x137) && (keyboard_recv(0x38) || keyboard_recv(0x138))) + finalkeycode = 0x54; + else if ((finalkeycode == 0x145) && (keyboard_recv(0x1d) || keyboard_recv(0x11d))) finalkeycode = 0x146; if (rctrl_is_lalt && finalkeycode == 0x11D) @@ -1386,7 +1388,10 @@ MainWindow::keyPressEvent(QKeyEvent *event) processMacKeyboardInput(true, event); #else auto scan = x11_keycode_to_keysym(event->nativeScanCode()); - if (scan == 0x145) { + if (scan == 0x137) { + /* Special case for Print Screen. */ + keyboard_input(1, 0x12a); + } else if (scan == 0x145) { /* Special case for Pause. */ keyboard_input(1, 0xe11d); scan &= 0x00ff; @@ -1440,7 +1445,11 @@ MainWindow::keyReleaseEvent(QKeyEvent *event) processMacKeyboardInput(false, event); #else auto scan = x11_keycode_to_keysym(event->nativeScanCode()); - if (scan == 0x145) { + if (scan == 0x137) { + /* Special case for Print Screen. */ + keyboard_input(0, scan); + scan = 0x12a; + } else if (scan == 0x145) { /* Special case for Pause. */ keyboard_input(0, 0xe11d); scan &= 0x00ff; From b904636fe172edf2359f629205f3981bfbd8cb4f Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 17:48:13 -0300 Subject: [PATCH 38/53] qt: Fix some macOS keycodes, move them to a header and add key name comments --- src/qt/cocoa_keyboard.hpp | 129 ++++++++++++++++++++++++++++++++++++ src/qt/qt_mainwindow.cpp | 136 +------------------------------------- 2 files changed, 131 insertions(+), 134 deletions(-) create mode 100644 src/qt/cocoa_keyboard.hpp diff --git a/src/qt/cocoa_keyboard.hpp b/src/qt/cocoa_keyboard.hpp new file mode 100644 index 000000000..b4359c7d9 --- /dev/null +++ b/src/qt/cocoa_keyboard.hpp @@ -0,0 +1,129 @@ +std::array cocoa_keycodes = { /* key names in parentheses are not declared by Apple headers */ + 0x1e, /* ANSI_A */ + 0x1f, /* ANSI_S */ + 0x20, /* ANSI_D */ + 0x21, /* ANSI_F */ + 0x23, /* ANSI_H */ + 0x22, /* ANSI_G */ + 0x2c, /* ANSI_Z */ + 0x2d, /* ANSI_X */ + 0x2e, /* ANSI_C */ + 0x2f, /* ANSI_V */ + 0x56, /* ISO_Section */ + 0x30, /* ANSI_B */ + 0x10, /* ANSI_Q */ + 0x11, /* ANSI_W */ + 0x12, /* ANSI_E */ + 0x13, /* ANSI_R */ + 0x15, /* ANSI_Y */ + 0x14, /* ANSI_T */ + 0x02, /* ANSI_1 */ + 0x03, /* ANSI_2 */ + 0x04, /* ANSI_3 */ + 0x05, /* ANSI_4 */ + 0x07, /* ANSI_6 */ + 0x06, /* ANSI_5 */ + 0x0d, /* ANSI_Equal */ + 0x0a, /* ANSI_9 */ + 0x08, /* ANSI_7 */ + 0x0c, /* ANSI_Minus */ + 0x09, /* ANSI_8 */ + 0x0b, /* ANSI_0 */ + 0x1b, /* ANSI_RightBracket */ + 0x18, /* ANSI_O */ + 0x16, /* ANSI_U */ + 0x1a, /* ANSI_LeftBracket */ + 0x17, /* ANSI_I */ + 0x19, /* ANSI_P */ + 0x1c, /* Return */ + 0x26, /* ANSI_L */ + 0x24, /* ANSI_J */ + 0x28, /* ANSI_Quote */ + 0x25, /* ANSI_K */ + 0x27, /* ANSI_Semicolon */ + 0x2b, /* ANSI_Backslash */ + 0x33, /* ANSI_Comma */ + 0x35, /* ANSI_Slash */ + 0x31, /* ANSI_N */ + 0x32, /* ANSI_M */ + 0x34, /* ANSI_Period */ + 0x0f, /* Tab */ + 0x39, /* Space */ + 0x29, /* ANSI_Grave */ + 0x0e, /* Delete => Backspace */ + 0x11c, /* (ANSI_KeypadEnter) */ + 0x01, /* Escape */ + 0x15c, /* (RightCommand) => Right Windows */ + 0x15b, /* (Left)Command => Left Windows */ + 0x2a, /* Shift */ + 0x3a, /* CapsLock */ + 0x38, /* Option */ + 0x1d, /* Control */ + 0x36, /* RightShift */ + 0x138, /* RightOption */ + 0x11d, /* RightControl */ + 0x15c, /* Function */ + 0x5e, /* F17 => F14 */ + 0x53, /* ANSI_KeypadDecimal */ + 0, + 0x37, /* ANSI_KeypadMultiply */ + 0, + 0x4e, /* ANSI_KeypadPlus */ + 0, + 0x45, /* ANSI_KeypadClear => Num Lock (location equivalent) */ + 0x130, /* VolumeUp */ + 0x12e, /* VolumeDown */ + 0x120, /* Mute */ + 0x135, /* ANSI_KeypadDivide */ + 0x11c, /* ANSI_KeypadEnter */ + 0, + 0x4a, /* ANSI_KeypadMinus */ + 0x5f, /* F18 => F15 */ + 0, /* F19 */ + 0x59, /* ANSI_KeypadEquals */ + 0x52, /* ANSI_Keypad0 */ + 0x4f, /* ANSI_Keypad1 */ + 0x50, /* ANSI_Keypad2 */ + 0x51, /* ANSI_Keypad3 */ + 0x4b, /* ANSI_Keypad4 */ + 0x4c, /* ANSI_Keypad5 */ + 0x4d, /* ANSI_Keypad6 */ + 0x47, /* ANSI_Keypad7 */ + 0, /* F20 */ + 0x48, /* ANSI_Keypad8 */ + 0x49, /* ANSI_Keypad9 */ + 0x7d, /* JIS_Yen */ + 0x73, /* JIS_Underscore */ + 0x5c, /* JIS_KeypadComma */ + 0x3f, /* F5 */ + 0x40, /* F6 */ + 0x41, /* F7 */ + 0x3d, /* F3 */ + 0x42, /* F8 */ + 0x43, /* F9 */ + 0x7b, /* JIS_Eisu => muhenkan (location equivalent) */ + 0x57, /* F11 */ + 0x79, /* JIS_Kana => henkan (location equivalent) */ + 0x137, /* F13 => SysRq (location equivalent) */ + 0x5d, /* F16 => F13 */ + 0x46, /* F14 => Scroll Lock (location equivalent) */ + 0, + 0x44, /* F10 */ + 0x15d, /* (Menu) */ + 0x58, /* F12 */ + 0, + 0x145, /* F15 => Pause (location equivalent) */ + 0x152, /* Help => Insert (location equivalent) */ + 0x147, /* Home */ + 0x149, /* PageUp */ + 0x153, /* ForwardDelete */ + 0x3e, /* F4 */ + 0x14f, /* End */ + 0x3c, /* F2 */ + 0x151, /* PageDown */ + 0x3b, /* F1 */ + 0x14b, /* LeftArrow */ + 0x14d, /* RightArrow */ + 0x150, /* DownArrow */ + 0x148, /* UpArrow */ +}; diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 03db77721..2a1268a7f 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -115,6 +115,7 @@ extern int qt_nvr_save(void); #endif #ifdef Q_OS_MACOS +# include "cocoa_keyboard.hpp" // The namespace is required to avoid clashing typedefs; we only use this // header for its #defines anyway. namespace IOKit { @@ -905,139 +906,6 @@ MainWindow::on_actionSettings_triggered() plat_pause(currentPause); } -#ifdef Q_OS_MACOS -std::array darwin_to_xt { - 0x1E, - 0x1F, - 0x20, - 0x21, - 0x23, - 0x22, - 0x2C, - 0x2D, - 0x2E, - 0x2F, - 0x2B, - 0x30, - 0x10, - 0x11, - 0x12, - 0x13, - 0x15, - 0x14, - 0x02, - 0x03, - 0x04, - 0x05, - 0x07, - 0x06, - 0x0D, - 0x0A, - 0x08, - 0x0C, - 0x09, - 0x0B, - 0x1B, - 0x18, - 0x16, - 0x1A, - 0x17, - 0x19, - 0x1C, - 0x26, - 0x24, - 0x28, - 0x25, - 0x27, - 0x2B, - 0x33, - 0x35, - 0x31, - 0x32, - 0x34, - 0x0F, - 0x39, - 0x29, - 0x0E, - 0x11C, - 0x01, - 0x15C, - 0x15B, - 0x2A, - 0x3A, - 0x38, - 0x1D, - 0x36, - 0x138, - 0x11D, - 0x15C, - 0, - 0x53, - 0, - 0x37, - 0, - 0x4E, - 0, - 0x45, - 0x130, - 0x12E, - 0x120, - 0x135, - 0x11C, - 0, - 0x4A, - 0, - 0, - 0, - 0x52, - 0x4F, - 0x50, - 0x51, - 0x4B, - 0x4C, - 0x4D, - 0x47, - 0, - 0x48, - 0x49, - 0, - 0, - 0, - 0x3F, - 0x40, - 0x41, - 0x3D, - 0x42, - 0x43, - 0, - 0x57, - 0, - 0x137, - 0, - 0x46, - 0, - 0x44, - 0x15D, - 0x58, - 0, - 0, // Pause/Break key. - 0x152, - 0x147, - 0x149, - 0x153, - 0x3E, - 0x14F, - 0x3C, - 0x151, - 0x3B, - 0x14B, - 0x14D, - 0x150, - 0x148, - 0, -}; -#endif - #ifdef __HAIKU__ static std::unordered_map be_to_xt = { {0x01, 0x01 }, @@ -1155,7 +1023,7 @@ x11_keycode_to_keysym(uint32_t keycode) #if defined(Q_OS_WINDOWS) finalkeycode = (keycode & 0xFFFF); #elif defined(Q_OS_MACOS) - finalkeycode = darwin_to_xt[keycode]; + finalkeycode = (keycode < 127) ? cocoa_keycodes[keycode] : 0; #elif defined(__HAIKU__) finalkeycode = be_to_xt[keycode]; #else From 660856d6ec9f4a77c217c45652868583a4507a49 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 18:08:03 -0300 Subject: [PATCH 39/53] qt: Fix some Haiku keycodes, move them to a header and add key name comments --- src/qt/be_keyboard.hpp | 112 +++++++++++++++++++++++++++++++++++++ src/qt/cocoa_keyboard.hpp | 2 +- src/qt/qt_mainwindow.cpp | 113 +------------------------------------- 3 files changed, 115 insertions(+), 112 deletions(-) create mode 100644 src/qt/be_keyboard.hpp diff --git a/src/qt/be_keyboard.hpp b/src/qt/be_keyboard.hpp new file mode 100644 index 000000000..cc2bbabac --- /dev/null +++ b/src/qt/be_keyboard.hpp @@ -0,0 +1,112 @@ +static std::unordered_map be_keycodes = { + {B_F1_KEY, 0x3b}, + {B_F2_KEY, 0x3c}, + {B_F3_KEY, 0x3d}, + {B_F4_KEY, 0x3e}, + {B_F5_KEY, 0x3f}, + {B_F6_KEY, 0x40}, + {B_F7_KEY, 0x41}, + {B_F8_KEY, 0x42}, + {B_F9_KEY, 0x43}, + {B_F10_KEY, 0x44}, + {B_F11_KEY, 0x57}, + {B_F12_KEY, 0x58}, + {B_PRINT_KEY, 0x137}, + {B_SCROLL_KEY, 0x46}, + {B_PAUSE_KEY, 0x145}, + {B_KATAKANA_HIRAGANA, 0x70}, + {B_HANKAKU_ZENKAKU, 0x76}, + + {0x01, 0x01}, /* Escape */ + {0x11, 0x29}, + {0x12, 0x02}, + {0x13, 0x03}, + {0x14, 0x04}, + {0x15, 0x05}, + {0x16, 0x06}, + {0x17, 0x07}, + {0x18, 0x08}, + {0x19, 0x09}, + {0x1a, 0x0a}, + {0x1b, 0x0b}, + {0x1c, 0x0c}, + {0x1d, 0x0d}, + {0x1e, 0x0e}, /* Backspace */ + {0x1f, 0x152}, /* Insert */ + {0x20, 0x147}, /* Home */ + {0x21, 0x149}, /* Page Up */ + {0x22, 0x45}, + {0x23, 0x135}, + {0x24, 0x37}, + {0x25, 0x4a}, + {0x26, 0x0f}, /* Tab */ + {0x27, 0x10}, + {0x28, 0x11}, + {0x29, 0x12}, + {0x2a, 0x13}, + {0x2b, 0x14}, + {0x2c, 0x15}, + {0x2d, 0x16}, + {0x2e, 0x17}, + {0x2f, 0x18}, + {0x30, 0x19}, + {0x31, 0x1a}, + {0x32, 0x1b}, + {0x33, 0x2b}, + {0x34, 0x153}, /* Delete */ + {0x35, 0x14f}, /* End */ + {0x36, 0x151}, /* Page Down */ + {0x37, 0x47}, + {0x38, 0x48}, + {0x39, 0x49}, + {0x3a, 0x4e}, + {0x3b, 0x3a}, + {0x3c, 0x1e}, + {0x3d, 0x1f}, + {0x3e, 0x20}, + {0x3f, 0x21}, + {0x40, 0x22}, + {0x41, 0x23}, + {0x42, 0x24}, + {0x43, 0x25}, + {0x44, 0x26}, + {0x45, 0x27}, + {0x46, 0x28}, + {0x47, 0x1c}, /* Enter */ + {0x48, 0x4b}, + {0x49, 0x4c}, + {0x4a, 0x4d}, + {0x4b, 0x2a}, + {0x4c, 0x2c}, + {0x4d, 0x2d}, + {0x4e, 0x2e}, + {0x4f, 0x2f}, + {0x50, 0x30}, + {0x51, 0x31}, + {0x52, 0x32}, + {0x53, 0x33}, + {0x54, 0x34}, + {0x55, 0x35}, + {0x56, 0x36}, + {0x57, 0x148}, /* up arrow */ + {0x58, 0x51}, + {0x59, 0x50}, + {0x5a, 0x4f}, + {0x5b, 0x11c}, + {0x5c, 0x1d}, + {0x5d, 0x38}, + {0x5e, 0x39}, /* space bar */ + {0x5f, 0x138}, + {0x60, 0x11d}, + {0x61, 0x14b}, /* left arrow */ + {0x62, 0x150}, /* down arrow */ + {0x63, 0x14d}, /* right arrow */ + {0x64, 0x52}, + {0x65, 0x53}, + {0x66, 0x15b}, + {0x67, 0x15c}, + {0x68, 0x15d}, + {0x69, 0x56}, + {0x7e, 0x137}, /* System Request */ + {0x7f, 0x145}, /* Break */ +}; diff --git a/src/qt/cocoa_keyboard.hpp b/src/qt/cocoa_keyboard.hpp index b4359c7d9..eaf0cdfe0 100644 --- a/src/qt/cocoa_keyboard.hpp +++ b/src/qt/cocoa_keyboard.hpp @@ -1,4 +1,4 @@ -std::array cocoa_keycodes = { /* key names in parentheses are not declared by Apple headers */ +static std::array cocoa_keycodes = { /* key names in parentheses are not declared by Apple headers */ 0x1e, /* ANSI_A */ 0x1f, /* ANSI_S */ 0x20, /* ANSI_D */ diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 2a1268a7f..c12daa112 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -126,6 +126,7 @@ namespace IOKit { #ifdef __HAIKU__ # include # include +# include "be_keyboard.hpp" extern MainWindow *main_window; @@ -906,116 +907,6 @@ MainWindow::on_actionSettings_triggered() plat_pause(currentPause); } -#ifdef __HAIKU__ -static std::unordered_map be_to_xt = { - {0x01, 0x01 }, - { B_F1_KEY, 0x3B }, - { B_F2_KEY, 0x3C }, - { B_F3_KEY, 0x3D }, - { B_F4_KEY, 0x3E }, - { B_F5_KEY, 0x3F }, - { B_F6_KEY, 0x40 }, - { B_F7_KEY, 0x41 }, - { B_F8_KEY, 0x42 }, - { B_F9_KEY, 0x43 }, - { B_F10_KEY, 0x44 }, - { B_F11_KEY, 0x57 }, - { B_F12_KEY, 0x58 }, - { 0x11, 0x29 }, - { 0x12, 0x02 }, - { 0x13, 0x03 }, - { 0x14, 0x04 }, - { 0x15, 0x05 }, - { 0x16, 0x06 }, - { 0x17, 0x07 }, - { 0x18, 0x08 }, - { 0x19, 0x09 }, - { 0x1A, 0x0A }, - { 0x1B, 0x0B }, - { 0x1C, 0x0C }, - { 0x1D, 0x0D }, - { 0x1E, 0x0E }, - { 0x1F, 0x152}, - { 0x20, 0x147}, - { 0x21, 0x149}, - { 0x22, 0x45 }, - { 0x23, 0x135}, - { 0x24, 0x37 }, - { 0x25, 0x4A }, - { 0x26, 0x0F }, - { 0x27, 0x10 }, - { 0x28, 0x11 }, - { 0x29, 0x12 }, - { 0x2A, 0x13 }, - { 0x2B, 0x14 }, - { 0x2C, 0x15 }, - { 0x2D, 0x16 }, - { 0x2E, 0x17 }, - { 0x2F, 0x18 }, - { 0x30, 0x19 }, - { 0x31, 0x1A }, - { 0x32, 0x1B }, - { 0x33, 0x2B }, - { 0x34, 0x153}, - { 0x35, 0x14F}, - { 0x36, 0x151}, - { 0x37, 0x47 }, - { 0x38, 0x48 }, - { 0x39, 0x49 }, - { 0x3A, 0x4E }, - { 0x3B, 0x3A }, - { 0x3C, 0x1E }, - { 0x3D, 0x1F }, - { 0x3E, 0x20 }, - { 0x3F, 0x21 }, - { 0x40, 0x22 }, - { 0x41, 0x23 }, - { 0x42, 0x24 }, - { 0x43, 0x25 }, - { 0x44, 0x26 }, - { 0x45, 0x27 }, - { 0x46, 0x28 }, - { 0x47, 0x1C }, - { 0x48, 0x4B }, - { 0x49, 0x4C }, - { 0x4A, 0x4D }, - { 0x4B, 0x2A }, - { 0x4C, 0x2C }, - { 0x4D, 0x2D }, - { 0x4E, 0x2E }, - { 0x4F, 0x2F }, - { 0x50, 0x30 }, - { 0x51, 0x31 }, - { 0x52, 0x32 }, - { 0x53, 0x33 }, - { 0x54, 0x34 }, - { 0x55, 0x35 }, - { 0x56, 0x36 }, - { 0x57, 0x148}, - { 0x58, 0x51 }, - { 0x59, 0x50 }, - { 0x5A, 0x4F }, - { 0x5B, 0x11C}, - { 0x5C, 0x1D }, - { 0x5D, 0x38 }, - { 0x5E, 0x39 }, - { 0x5F, 0x138}, - { 0x60, 0x11D}, - { 0x61, 0x14B}, - { 0x62, 0x150}, - { 0x63, 0x14D}, - { 0x64, 0x52 }, - { 0x65, 0x53 }, - - { 0x0e, 0x137}, - { 0x0f, 0x46 }, - { 0x66, 0x15B}, - { 0x67, 0x15C}, - { 0x68, 0x15D}, - { 0x69, 0x56 } -}; -#endif - uint16_t x11_keycode_to_keysym(uint32_t keycode) { @@ -1025,7 +916,7 @@ x11_keycode_to_keysym(uint32_t keycode) #elif defined(Q_OS_MACOS) finalkeycode = (keycode < 127) ? cocoa_keycodes[keycode] : 0; #elif defined(__HAIKU__) - finalkeycode = be_to_xt[keycode]; + finalkeycode = be_keycodes[keycode]; #else # ifdef XKBCOMMON if (xkbcommon_keymap) From 1c4afad095e5c452f151886cd09a2b73265b07f6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 9 Apr 2023 23:24:03 +0200 Subject: [PATCH 40/53] The keyboard controller now waits for the keyboard or mouse to process a command, hopefully fixes the remaining 301 errors on the IBM PS/2 models. --- src/device/keyboard_at.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index bfa6fa0be..86e87cc9b 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -99,7 +99,9 @@ enum { KBC_STATE_MAIN_BOTH, KBC_STATE_KBC_OUT, KBC_STATE_KBC_PARAM, + KBC_STATE_SEND_KBD, KBC_STATE_KBD, + KBC_STATE_SEND_MOUSE, KBC_STATE_MOUSE }; #define KBC_STATE_SCAN_KBD KBC_STATE_KBD @@ -836,7 +838,7 @@ kbc_ibf_process(atkbd_t *dev) set_enable_kbd(dev, 1); dev->key_wantcmd = 1; dev->key_dat = dev->ib; - dev->kbc_state = KBC_STATE_SCAN_KBD; + dev->kbc_state = KBC_STATE_SEND_KBD; } } @@ -892,8 +894,7 @@ kbc_poll_at(atkbd_t *dev) } break; case KBC_STATE_MAIN_IBF: - case KBC_STATE_MAIN_MOUSE: - case KBC_STATE_SCAN_MOUSE: + default: if (dev->status & STAT_OFULL) { /* OBF set, wait until it is cleared but still process commands. */ if ((dev->status & STAT_IFULL) && (dev->status & STAT_CD)) { @@ -941,6 +942,10 @@ kbc_poll_at(atkbd_t *dev) kbc_process_cmd(dev); } break; + case KBC_STATE_SEND_KBD: + if (!dev->key_wantcmd) + dev->kbc_state = KBC_STATE_SCAN_KBD; + break; case KBC_STATE_SCAN_KBD: kbc_scan_kbd_at(dev); break; @@ -997,6 +1002,7 @@ kbc_poll_ps2(atkbd_t *dev) } break; case KBC_STATE_MAIN_IBF: + default: // pclog("KBC_STATE_MAIN_IBF\n"); if (dev->status & STAT_IFULL) kbc_ibf_process(dev); @@ -1071,10 +1077,18 @@ kbc_poll_ps2(atkbd_t *dev) kbc_process_cmd(dev); } break; + case KBC_STATE_SEND_KBD: + if (!dev->key_wantcmd) + dev->kbc_state = KBC_STATE_SCAN_KBD; + break; case KBC_STATE_SCAN_KBD: // pclog("KBC_STATE_SCAN_KBD\n"); (void) kbc_scan_kbd_ps2(dev); break; + case KBC_STATE_SEND_MOUSE: + if (!dev->mouse_wantcmd) + dev->kbc_state = KBC_STATE_SCAN_MOUSE; + break; case KBC_STATE_SCAN_MOUSE: // pclog("KBC_STATE_SCAN_MOUSE\n"); (void) kbc_scan_aux_ps2(dev); @@ -2695,7 +2709,7 @@ kbc_process_cmd(void *priv) if (mouse_write) { dev->mouse_wantcmd = 1; dev->mouse_dat = dev->ib; - dev->kbc_state = KBC_STATE_SCAN_MOUSE; + dev->kbc_state = KBC_STATE_SEND_MOUSE; } else add_to_kbc_queue_front(dev, 0xfe, 2, 0x40); } From bd1832054e9a3d7a7f7e124c778f7f5c5c23a317 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 18:24:26 -0300 Subject: [PATCH 41/53] qt: Add a couple xkb mappings for Japanese Apple keyboards --- src/qt/xkbcommon_keyboard.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index e3a058ed2..181f9e057 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -133,7 +133,9 @@ static std::unordered_map xkb_keycodes = { {"HIRA", 0x77}, {"KATA", 0x78}, {"HENK", 0x79}, + {"KANA", 0x79}, /* kana => henkan (for Apple keyboards) */ {"MUHE", 0x7b}, + {"EISU", 0x7b}, /* eisu => muhenkan (for Apple keyboards) */ {"AE13", 0x7d}, /* \| */ {"KPPT", 0x7e}, /* Brazilian Num. */ {"I06", 0x7e}, /* alias of KPPT on keycodes/xfree86 (i.e. X11 forwarding) */ @@ -199,7 +201,7 @@ xkbcommon_init(struct xkb_keymap *keymap) void xkbcommon_close() { - xkbcommon_keymap = NULL; + xkbcommon_keymap = nullptr; } uint16_t From e492640d65611b0b587cfe638445649ed35129b2 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 19:26:56 -0300 Subject: [PATCH 42/53] qt: Unify keyboard input paths --- src/qt/qt_mainwindow.cpp | 85 ++++++++++++++++++++-------------------- src/qt/qt_mainwindow.hpp | 1 + 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index c12daa112..91bf76d67 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -907,37 +907,57 @@ MainWindow::on_actionSettings_triggered() plat_pause(currentPause); } -uint16_t -x11_keycode_to_keysym(uint32_t keycode) +void +MainWindow::processKeyboardInput(bool down, uint32_t keycode) { - uint16_t finalkeycode; -#if defined(Q_OS_WINDOWS) - finalkeycode = (keycode & 0xFFFF); +#if defined(Q_OS_WINDOWS) /* non-raw input */ + keycode &= 0xffff; #elif defined(Q_OS_MACOS) - finalkeycode = (keycode < 127) ? cocoa_keycodes[keycode] : 0; + keycode = (keycode < 127) ? cocoa_keycodes[keycode] : 0; #elif defined(__HAIKU__) - finalkeycode = be_keycodes[keycode]; + keycode = be_keycodes[keycode]; #else # ifdef XKBCOMMON if (xkbcommon_keymap) - finalkeycode = xkbcommon_translate(keycode); + keycode = xkbcommon_translate(keycode); else # endif # ifdef EVDEV_KEYBOARD_HPP - finalkeycode = evdev_translate(keycode - 8); + keycode = evdev_translate(keycode - 8); # else - finalkeycode = 0; + keycode = 0; # endif #endif - /* Special case for Alt+Print Screen and Ctrl+Pause. */ - if ((finalkeycode == 0x137) && (keyboard_recv(0x38) || keyboard_recv(0x138))) - finalkeycode = 0x54; - else if ((finalkeycode == 0x145) && (keyboard_recv(0x1d) || keyboard_recv(0x11d))) - finalkeycode = 0x146; - if (rctrl_is_lalt && finalkeycode == 0x11D) - finalkeycode = 0x38; - return finalkeycode; + /* Apply special cases. */ + switch (keycode) { + case 0x11d: /* Right Ctrl */ + if (rctrl_is_lalt) + keycode = 0x38; /* map to Left Alt */ + break; + + case 0x137: /* Print Screen */ + if (keyboard_recv(0x38) || keyboard_recv(0x138)) { /* Alt+ */ + keycode = 0x54; + } else if (down) { + keyboard_input(down, 0x12a); + } else { + keyboard_input(down, keycode); + keycode = 0x12a; + } + break; + + case 0x145: /* Pause */ + if (keyboard_recv(0x1d) || keyboard_recv(0x11d)) { /* Ctrl+ */ + keycode = 0x146; + } else { + keyboard_input(down, 0xe11d); + keycode &= 0x00ff; + } + break; + } + + keyboard_input(down, keycode); } #ifdef Q_OS_MACOS @@ -995,11 +1015,11 @@ MainWindow::processMacKeyboardInput(bool down, const QKeyEvent *event) // It's possible that other lock keys get delivered in this way, but // standard Apple keyboards don't have them, so this is untested. if (event->key() == Qt::Key_CapsLock) { - keyboard_input(1, 0x3A); - keyboard_input(0, 0x3A); + keyboard_input(1, 0x3a); + keyboard_input(0, 0x3a); } } else { - keyboard_input(down, x11_keycode_to_keysym(event->nativeVirtualKey())); + processKeyboardInput(down, event->nativeVirtualKey()); } } #endif @@ -1146,16 +1166,7 @@ MainWindow::keyPressEvent(QKeyEvent *event) #ifdef Q_OS_MACOS processMacKeyboardInput(true, event); #else - auto scan = x11_keycode_to_keysym(event->nativeScanCode()); - if (scan == 0x137) { - /* Special case for Print Screen. */ - keyboard_input(1, 0x12a); - } else if (scan == 0x145) { - /* Special case for Pause. */ - keyboard_input(1, 0xe11d); - scan &= 0x00ff; - } - keyboard_input(1, scan); + processKeyboardInput(true, event->nativeScanCode()); #endif } @@ -1203,17 +1214,7 @@ MainWindow::keyReleaseEvent(QKeyEvent *event) #ifdef Q_OS_MACOS processMacKeyboardInput(false, event); #else - auto scan = x11_keycode_to_keysym(event->nativeScanCode()); - if (scan == 0x137) { - /* Special case for Print Screen. */ - keyboard_input(0, scan); - scan = 0x12a; - } else if (scan == 0x145) { - /* Special case for Pause. */ - keyboard_input(0, 0xe11d); - scan &= 0x00ff; - } - keyboard_input(0, scan); + processKeyboardInput(false, event->nativeScanCode()); #endif } diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index bf4a30f1d..826f75475 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -155,6 +155,7 @@ private: std::unique_ptr status; std::shared_ptr mm; + void processKeyboardInput(bool down, uint32_t keycode); #ifdef Q_OS_MACOS uint32_t last_modifiers = 0; void processMacKeyboardInput(bool down, const QKeyEvent *event); From 6f8fffc275039025f02ade52f4a0fe5c9783cbdc Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 19:38:05 -0300 Subject: [PATCH 43/53] qt: Fix potential UAF and leak in Wayland xkbcommon keyboard --- src/qt/xkbcommon_wl_keyboard.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qt/xkbcommon_wl_keyboard.cpp b/src/qt/xkbcommon_wl_keyboard.cpp index c6736f2d4..4db4971ee 100644 --- a/src/qt/xkbcommon_wl_keyboard.cpp +++ b/src/qt/xkbcommon_wl_keyboard.cpp @@ -70,15 +70,20 @@ kbd_keymap(void *data, struct wl_keyboard *wl_kbd, uint32_t format, return; } + if (seat->keymap) { + static struct xkb_keymap *keymap = seat->keymap; + seat->keymap = NULL; + xkbcommon_wl_set_keymap(); + xkb_keymap_unref(keymap); + } + seat->keymap = xkb_keymap_new_from_buffer(ctx, buf, size - 1, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(buf, size); close(fd); - if (!seat->keymap) { + if (!seat->keymap) qWarning() << "XKB Keyboard: Keymap compilation failed"; - return; - } xkbcommon_wl_set_keymap(); } From fb00a89b890e01fe95052e3986da8804c8168f57 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 19:42:01 -0300 Subject: [PATCH 44/53] workflows: Add missing Linux keyboard input libraries --- .github/workflows/cmake.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index be42cbae6..d19a5dac7 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -253,6 +253,8 @@ jobs: packages: >- qtbase5-dev qttools5-dev + libevdev-dev + libxkbcommon-x11-dev steps: - name: Install dependencies From 8fc6027756102a3fd6945bdee6fcc15f3e8c9213 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 19:49:25 -0300 Subject: [PATCH 45/53] qt: Add Alt+PrtSc special case for one evdev key --- src/qt/evdev_keyboard.cpp | 2 +- src/qt/qt_mainwindow.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/qt/evdev_keyboard.cpp b/src/qt/evdev_keyboard.cpp index 505618ef7..9dbb4127a 100644 --- a/src/qt/evdev_keyboard.cpp +++ b/src/qt/evdev_keyboard.cpp @@ -69,6 +69,7 @@ static std::unordered_map evdev_keycodes = { /* Multimedia keys. Guideline is to try and follow the Microsoft standard, then fill in remaining scancodes with OEM-specific keys for redundancy sake. Keys marked with # are not translated into evdev codes by the standard atkbd driver. */ + {634, 0x54}, /* SELECTIVE_SCREENSHOT# => Alt+SysRq */ {117, 0x59}, /* KPEQUAL */ {418, 0x6a}, /* ZOOMIN# => Logitech */ {420, 0x6b}, /* ZOOMRESET# => Logitech */ @@ -107,7 +108,6 @@ static std::unordered_map evdev_keycodes = { {115, 0x130}, /* VOL+ */ {150, 0x132}, /* WWW# */ {172, 0x132}, /* HOMEPAGE */ - {634, 0x137}, /* SELECTIVE_SCREENSHOT# => SysRq */ {138, 0x13b}, /* HELP# */ {213, 0x13c}, /* SOUND# => My Music/Office Home */ {360, 0x13c}, /* VENDOR# => My Music/Office Home */ diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 91bf76d67..13a32723c 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -931,6 +931,16 @@ MainWindow::processKeyboardInput(bool down, uint32_t keycode) /* Apply special cases. */ switch (keycode) { + case 0x54: /* Alt + Print Screen (special case, i.e. evdev SELECTIVE_SCREENSHOT) */ + /* Send Alt as well. */ + if (down) { + keyboard_input(down, 0x38); + } else { + keyboard_input(down, keycode); + keycode = 0x38; + } + break; + case 0x11d: /* Right Ctrl */ if (rctrl_is_lalt) keycode = 0x38; /* map to Left Alt */ From be5b473436210be9049f9f7c994af410fbe5f301 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 20:18:51 -0300 Subject: [PATCH 46/53] qt: Add one more RAlt XKB keycode mapping --- src/qt/xkbcommon_keyboard.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/xkbcommon_keyboard.cpp b/src/qt/xkbcommon_keyboard.cpp index 181f9e057..788087998 100644 --- a/src/qt/xkbcommon_keyboard.cpp +++ b/src/qt/xkbcommon_keyboard.cpp @@ -152,6 +152,7 @@ static std::unordered_map xkb_keycodes = { {"FK13", 0x137}, /* F13 => SysRq (for Apple keyboards) */ {"RALT", 0x138}, {"ALGR", 0x138}, + {"LVL3", 0x138}, /* observed on TigerVNC with AltGr-enabled layout */ {"PAUS", 0x145}, {"FK15", 0x145}, /* F15 => Pause (for Apple keyboards) */ {"BRK", 0x145}, From 18ee7f70804d0b00c56588b6f3e7dac5fe5e8832 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Sun, 9 Apr 2023 20:23:34 -0300 Subject: [PATCH 47/53] workflows: Add missing qt5 package for a private header --- .github/workflows/cmake.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index d19a5dac7..27c7ea204 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -252,6 +252,7 @@ jobs: slug: -Qt packages: >- qtbase5-dev + qtbase5-private-dev qttools5-dev libevdev-dev libxkbcommon-x11-dev From c614efa075f2c3543cba7317b5f8917969cc48d8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Apr 2023 13:45:55 +0200 Subject: [PATCH 48/53] Fixed scan code translation skip checking (fixes missing break code on Alt+Print Screen / SysRq) and actually committed the Acer V10 fix. --- src/device/keyboard.c | 1 + src/device/keyboard_at.c | 7 +++++-- src/machine/m_at_386dx_486.c | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/device/keyboard.c b/src/device/keyboard.c index 38d65b408..197281992 100644 --- a/src/device/keyboard.c +++ b/src/device/keyboard.c @@ -66,6 +66,7 @@ static uint8_t fake_shift_needed(uint16_t scan) { switch (scan) { + case 0x137: /* Yes, Print Screen requires the fake shifts. */ case 0x147: case 0x148: case 0x149: diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 86e87cc9b..103732f92 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -735,7 +735,7 @@ add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_ else stat_hi |= 0x10; - kbd_log("ATkbc: Adding %02X to front...\n", val); + kbd_log("ATkbc: Adding %02X to front on channel %i...\n", val, channel); dev->status = (dev->status & ~0xf0) | STAT_OFULL | stat_hi; /* WARNING: On PS/2, all IRQ's are level-triggered, but the IBM PS/2 KBC firmware is explicitly @@ -806,6 +806,9 @@ add_data_kbd_front(atkbd_t *dev, uint8_t val) static void add_data_kbd_raw(atkbd_t *dev, uint8_t val) { + if (dev->reset_delay) + return; + add_data_kbd_cmd_queue(dev, val); } @@ -1342,7 +1345,7 @@ add_data_kbd(uint16_t val) } /* Skip break code if translated make code has bit 7 set. */ - if (translate && (sc_or == 0x80) && (val & 0x80)) { + if (translate && (sc_or == 0x80) && (nont_to_t[val] & 0x80)) { kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); sc_or = 0; return; diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index ee54758e2..7768202da 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -404,7 +404,7 @@ machine_at_acerv10_init(const machine_t *model) machine_at_common_init(model); device_add(&sis_85c461_device); - device_add(&keyboard_ps2_ami_pci_device); + device_add(&keyboard_ps2_acer_pci_device); device_add(&ide_isa_2ch_device); if (fdc_type == FDC_INTERNAL) From d3bd8fb1aecf80fe8f4775376be0991aac185239 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Apr 2023 14:08:36 +0200 Subject: [PATCH 49/53] Moved scan code translation to the keyboard controller's side where it should be and removed an excessive keyboard command queue add function. --- src/device/keyboard_at.c | 273 ++++++++++++++++++--------------------- 1 file changed, 124 insertions(+), 149 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 103732f92..56e95a3ee 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -724,10 +724,110 @@ kbc_irq(atkbd_t *dev, uint16_t irq, int raise) dev->irq_levels &= ~irq; } +static int +kbc_translate(uint8_t val) +{ + atkbd_t *dev = SavedKbd; + int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); + int translate = (keyboard_mode & 0x40); + uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + int ret = - 1; + + translate = translate || (keyboard_mode & 0x40) || xt_mode; + translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); + + /* Allow for scan code translation. */ + if (translate && (val == 0xf0)) { + kbd_log("ATkbd: translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return ret; + } + + /* Skip break code if translated make code has bit 7 set. */ + if (translate && (sc_or == 0x80) && (nont_to_t[val] & 0x80)) { + kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return ret; + } + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && + (keyboard_recv(0x138) || keyboard_recv(0x11d))) switch (val) { + case 0x4f: + t3100e_notify_set(0x01); + break; /* End */ + case 0x50: + t3100e_notify_set(0x02); + break; /* Down */ + case 0x51: + t3100e_notify_set(0x03); + break; /* PgDn */ + case 0x52: + t3100e_notify_set(0x04); + break; /* Ins */ + case 0x53: + t3100e_notify_set(0x05); + break; /* Del */ + case 0x54: + t3100e_notify_set(0x06); + break; /* SysRQ */ + case 0x45: + t3100e_notify_set(0x07); + break; /* NumLock */ + case 0x46: + t3100e_notify_set(0x08); + break; /* ScrLock */ + case 0x47: + t3100e_notify_set(0x09); + break; /* Home */ + case 0x48: + t3100e_notify_set(0x0a); + break; /* Up */ + case 0x49: + t3100e_notify_set(0x0b); + break; /* PgUp */ + case 0x4a: + t3100e_notify_set(0x0c); + break; /* Keypad - */ + case 0x4b: + t3100e_notify_set(0x0d); + break; /* Left */ + case 0x4c: + t3100e_notify_set(0x0e); + break; /* KP 5 */ + case 0x4d: + t3100e_notify_set(0x0f); + break; /* Right */ + } + + kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); +#ifdef ENABLE_KEYBOARD_AT_LOG + kbd_log("scan code: "); + if (translate) { + kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); + if (sc_or == 0x80) + kbd_log("F0 "); + kbd_log("%02X)\n", val); + } else + kbd_log("%02X\n", val); +#endif + + ret = translate ? (nont_to_t[val] | sc_or) : val; + + if (sc_or == 0x80) + sc_or = 0; + + return ret; +} + static void add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_hi) { uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; + int temp = (channel == 1) ? kbc_translate(val) : val; + + if (temp == -1) + return; if ((kbc_ven == KBC_VEN_AMI) || (kbc_ven == KBC_VEN_TG) || (kbc_ven == KBC_VEN_TG_GREEN) || ((dev->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_NOREF)) @@ -735,7 +835,7 @@ add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_ else stat_hi |= 0x10; - kbd_log("ATkbc: Adding %02X to front on channel %i...\n", val, channel); + kbd_log("ATkbc: Adding %02X to front on channel %i...\n", temp, channel); dev->status = (dev->status & ~0xf0) | STAT_OFULL | stat_hi; /* WARNING: On PS/2, all IRQ's are level-triggered, but the IBM PS/2 KBC firmware is explicitly @@ -755,7 +855,7 @@ add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_ } else if (dev->mem[0x20] & 0x01) picintlevel(1 << 1); /* AT KBC: IRQ 1 is level-triggered because it is tied to OBF. */ - dev->out = val; + dev->out = temp; } static void @@ -784,27 +884,6 @@ add_data_kbd_queue(atkbd_t *dev, uint8_t val) static void add_data_kbd_front(atkbd_t *dev, uint8_t val) -{ - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); - uint8_t send; - - if (dev->reset_delay) - return; - - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - if (translate) - send = nont_to_t[val]; - else - send = val; - - add_data_kbd_cmd_queue(dev, send); -} - -static void -add_data_kbd_raw(atkbd_t *dev, uint8_t val) { if (dev->reset_delay) return; @@ -1290,118 +1369,28 @@ kbd_poll(void *priv) static void add_data_vals(atkbd_t *dev, uint8_t *val, uint8_t len) { - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); int i; - uint8_t or = 0; - uint8_t send; if (dev->reset_delay) return; - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - - for (i = 0; i < len; i++) { - if (translate) { - if (val[i] == 0xf0) { - or = 0x80; - continue; - } - send = nont_to_t[val[i]] | or ; - if (or == 0x80) - or = 0; - } else - send = val[i]; - - add_data_kbd_queue(dev, send); - } + for (i = 0; i < len; i++) + add_data_kbd_queue(dev, val[i]); } static void add_data_kbd(uint16_t val) { atkbd_t *dev = SavedKbd; - int xt_mode = (keyboard_mode & 0x20) && ((dev->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_NOREF); - int translate = (keyboard_mode & 0x40); uint8_t fake_shift[4]; uint8_t num_lock = 0, shift_states = 0; - uint8_t kbc_ven = dev->flags & KBC_VEN_MASK; if (dev->reset_delay) return; - translate = translate || (keyboard_mode & 0x40) || xt_mode; - translate = translate || ((dev->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2); - keyboard_get_states(NULL, &num_lock, NULL); shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; - /* Allow for scan code translation. */ - if (translate && (val == 0xf0)) { - kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; - return; - } - - /* Skip break code if translated make code has bit 7 set. */ - if (translate && (sc_or == 0x80) && (nont_to_t[val] & 0x80)) { - kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; - return; - } - - /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ - if ((dev != NULL) && (kbc_ven == KBC_VEN_TOSHIBA) && (keyboard_recv(0x138) || keyboard_recv(0x11d))) - switch (val) { - case 0x4f: - t3100e_notify_set(0x01); - break; /* End */ - case 0x50: - t3100e_notify_set(0x02); - break; /* Down */ - case 0x51: - t3100e_notify_set(0x03); - break; /* PgDn */ - case 0x52: - t3100e_notify_set(0x04); - break; /* Ins */ - case 0x53: - t3100e_notify_set(0x05); - break; /* Del */ - case 0x54: - t3100e_notify_set(0x06); - break; /* SysRQ */ - case 0x45: - t3100e_notify_set(0x07); - break; /* NumLock */ - case 0x46: - t3100e_notify_set(0x08); - break; /* ScrLock */ - case 0x47: - t3100e_notify_set(0x09); - break; /* Home */ - case 0x48: - t3100e_notify_set(0x0a); - break; /* Up */ - case 0x49: - t3100e_notify_set(0x0b); - break; /* PgUp */ - case 0x4A: - t3100e_notify_set(0x0c); - break; /* Keypad -*/ - case 0x4B: - t3100e_notify_set(0x0d); - break; /* Left */ - case 0x4C: - t3100e_notify_set(0x0e); - break; /* KP 5 */ - case 0x4D: - t3100e_notify_set(0x0f); - break; /* Right */ - } - - kbd_log("ATkbd: translate is %s, ", translate ? "on" : "off"); switch (val) { case FAKE_LSHIFT_ON: kbd_log("fake left shift on, scan code: "); @@ -1549,23 +1538,9 @@ add_data_kbd(uint16_t val) break; default: -#ifdef ENABLE_KEYBOARD_AT_LOG - kbd_log("scan code: "); - if (translate) { - kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); - if (sc_or == 0x80) - kbd_log("F0 "); - kbd_log("%02X)\n", val); - } else - kbd_log("%02X\n", val); -#endif - - add_data_kbd_queue(dev, translate ? (nont_to_t[val] | sc_or) : val); + add_data_kbd_queue(dev, val); break; } - - if (sc_or == 0x80) - sc_or = 0; } static void @@ -2273,7 +2248,7 @@ kbd_key_reset(atkbd_t *dev, int do_fa) keyboard_scan = 1; if (do_fa) - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); dev->reset_delay = RESET_DELAY_TIME; @@ -2320,19 +2295,19 @@ kbd_process_cmd(void *priv) */ if (dev->key_dat == dev->key_command) { /* Respond NAK and ignore it. */ - add_data_kbd_raw(dev, 0xfe); + add_data_kbd_front(dev, 0xfe); dev->key_command = 0x00; return; } switch (dev->key_command) { case 0xed: /* set/reset LEDs */ - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); kbd_log("ATkbd: set LEDs [%02x]\n", dev->key_dat); break; case 0xf0: /* get/set scancode set */ - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); if (dev->key_dat == 0) { kbd_log("Get scan code set: %02X\n", keyboard_mode & 3); add_data_kbd_front(dev, keyboard_mode & 3); @@ -2347,12 +2322,12 @@ kbd_process_cmd(void *priv) break; case 0xf3: /* set typematic rate/delay */ - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); break; default: kbd_log("ATkbd: bad keyboard 0060 write %02X command %02X\n", dev->key_dat, dev->key_command); - add_data_kbd_raw(dev, 0xfe); + add_data_kbd_front(dev, 0xfe); break; } @@ -2366,12 +2341,12 @@ kbd_process_cmd(void *priv) switch (dev->key_dat) { case 0x00 ... 0x7f: kbd_log("ATkbd: invalid command %02X\n", dev->key_dat); - add_data_kbd_raw(dev, 0xfe); + add_data_kbd_front(dev, 0xfe); break; case 0xed: /* set/reset LEDs */ kbd_log("ATkbd: set/reset leds\n"); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); dev->key_wantdata = 1; dev->kbd_state = DEV_STATE_MAIN_WANT_IN; @@ -2379,7 +2354,7 @@ kbd_process_cmd(void *priv) case 0xee: /* diagnostic echo */ kbd_log("ATkbd: ECHO\n"); - add_data_kbd_raw(dev, 0xee); + add_data_kbd_front(dev, 0xee); break; case 0xef: /* NOP (reserved for future use) */ @@ -2388,7 +2363,7 @@ kbd_process_cmd(void *priv) case 0xf0: /* get/set scan code set */ kbd_log("ATkbd: scan code set\n"); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); dev->key_wantdata = 1; dev->kbd_state = DEV_STATE_MAIN_WANT_IN; break; @@ -2398,21 +2373,21 @@ kbd_process_cmd(void *priv) kbd_log("ATkbd: read keyboard id\n"); /* TODO: After keyboard type selection is implemented, make this return the correct keyboard ID for the selected type. */ - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); add_data_kbd_front(dev, 0xab); add_data_kbd_front(dev, 0x83); break; case 0xf3: /* set typematic rate/delay */ kbd_log("ATkbd: set typematic rate/delay\n"); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); dev->key_wantdata = 1; dev->kbd_state = DEV_STATE_MAIN_WANT_IN; break; case 0xf4: /* enable keyboard */ kbd_log("ATkbd: enable keyboard\n"); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); keyboard_scan = 1; break; @@ -2422,7 +2397,7 @@ kbd_process_cmd(void *priv) keyboard_scan = (dev->key_dat == 0xf6); kbd_log("dev->key_dat = %02X, keyboard_scan = %i, dev->mem[0x20] = %02X\n", dev->key_dat, keyboard_scan, dev->mem[0]); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); keyboard_set3_all_break = 0; keyboard_set3_all_repeat = 0; @@ -2433,32 +2408,32 @@ kbd_process_cmd(void *priv) case 0xf7: /* set all keys to repeat */ kbd_log("ATkbd: set all keys to repeat\n"); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); keyboard_set3_all_break = 1; break; case 0xf8: /* set all keys to give make/break codes */ kbd_log("ATkbd: set all keys to give make/break codes\n"); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); keyboard_set3_all_break = 1; break; case 0xf9: /* set all keys to give make codes only */ kbd_log("ATkbd: set all keys to give make codes only\n"); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); keyboard_set3_all_break = 0; break; case 0xfa: /* set all keys to repeat and give make/break codes */ kbd_log("ATkbd: set all keys to repeat and give make/break codes\n"); - add_data_kbd_raw(dev, 0xfa); + add_data_kbd_front(dev, 0xfa); keyboard_set3_all_repeat = 1; keyboard_set3_all_break = 1; break; case 0xfe: /* resend last scan code */ kbd_log("ATkbd: reset last scan code\n"); - add_data_kbd_raw(dev, kbd_last_scan_code); + add_data_kbd_front(dev, kbd_last_scan_code); break; case 0xff: /* reset */ From 8786eebc8feea6c3d3de1de080bb1b0abaf76071 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 10 Apr 2023 12:57:42 -0300 Subject: [PATCH 50/53] qt: Add Apple ISO keyboard workaround + debug code for this case --- src/qt/qt_mainwindow.cpp | 55 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 13a32723c..ca0981ace 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -985,6 +985,7 @@ static std::unordered_map mac_modifiers_to_xt = { { NX_DEVICE_ALPHASHIFT_STATELESS_MASK, 0x3A }, { NX_DEVICERCTLKEYMASK, 0x11D}, }; +static bool mac_iso_swap = false; void MainWindow::processMacKeyboardInput(bool down, const QKeyEvent *event) @@ -1029,7 +1030,59 @@ MainWindow::processMacKeyboardInput(bool down, const QKeyEvent *event) keyboard_input(0, 0x3a); } } else { - processKeyboardInput(down, event->nativeVirtualKey()); + /* Apple ISO keyboards are notorious for swapping ISO_Section and ANSI_Grave + on *some* layouts and/or models. While macOS can sort this mess out at + keymap level, it still provides applications with unfiltered, ambiguous + keycodes, so we have to disambiguate them by making some bold assumptions + about the user's keyboard layout based on the OS-provided key mappings. */ + auto nvk = event->nativeVirtualKey(); + if ((nvk == 0x0a) || (nvk == 0x32)) { + /* Flaws: + - Layouts with `~ on ISO_Section are partially detected due to a conflict with ANSI + - Czech and Slovak are not detected as they have <> ANSI_Grave and \| ISO_Section (differing from PC actually) + - Italian is partially detected due to \| conflicting with Brazilian + - Romanian third level ANSI_Grave is unknown + - Russian clusters <>, plusminus and paragraph into a four-level ANSI_Grave, with the aforementioned `~ on ISO_Section */ + auto key = event->key(); + if ((nvk == 0x32) && ( /* system reports ANSI_Grave for ISO_Section keys: */ + (key == Qt::Key_Less) || (key == Qt::Key_Greater) || /* Croatian, French, German, Icelandic, Italian, Norwegian, Portuguese, Spanish, Spanish Latin America, Turkish Q */ + (key == Qt::Key_Ugrave) || /* French Canadian */ + (key == Qt::Key_Icircumflex) || /* Romanian */ + (key == Qt::Key_Iacute) || /* Hungarian */ + (key == Qt::Key_BracketLeft) || (key == Qt::Key_BracketRight) || /* Russian upper two levels */ + (key == Qt::Key_W) /* Turkish F */ + )) + mac_iso_swap = true; + else if ((nvk == 0x0a) && ( /* system reports ISO_Section for ANSI_Grave keys: */ + (key == Qt::Key_paragraph) || (key == Qt::Key_plusminus) || /* Arabic, British, Bulgarian, Danish shifted, Dutch, Greek, Hebrew, Hungarian shifted, International English, Norwegian shifted, Portuguese, Russian lower two levels, Swiss unshifted, Swedish unshifted, Turkish F */ + (key == Qt::Key_At) || (key == Qt::Key_NumberSign) || /* Belgian, French */ + (key == Qt::Key_Apostrophe) || /* Brazilian unshifted */ + (key == Qt::Key_QuoteDbl) || /* Brazilian shifted, Turkish Q unshifted */ + (key == Qt::Key_QuoteLeft) || /* Croatian (right quote unknown) */ + (key == Qt::Key_Dollar) || /* Danish unshifted */ + (key == Qt::Key_AsciiCircum) || /* German unshifted, Polish unshifted */ + (key == Qt::Key_degree) || /* German shifted, Icelandic unshifted, Spanish Latin America shifted, Swiss shifted, Swedish shifted */ + (key == Qt::Key_0) || /* Hungarian unshifted */ + (key == Qt::Key_diaeresis) || /* Icelandic shifted */ + (key == Qt::Key_acute) || /* Norwegian unshifted */ + (key == Qt::Key_Asterisk) || /* Polish shifted */ + (key == Qt::Key_masculine) || (key == Qt::Key_ordfeminine) || /* Spanish (masculine unconfirmed) */ + (key == Qt::Key_Eacute) || /* Turkish Q shifted */ + (key == Qt::Key_Slash) /* French Canadian unshifted, Ukrainian shifted */ + )) + mac_iso_swap = true; + + /* Temporary debug code. */ + if (down) { + QMessageBox questionbox(QMessageBox::Icon::Information, QString("Mac key swap test"), QString("nativeVirtualKey 0x%1\nnativeScanCode 0x%2\nkey 0x%3\nmac_iso_swap %4").arg(nvk, 0, 16).arg(event->nativeScanCode(), 0, 16).arg(key, 0, 16).arg(mac_iso_swap ? "yes" : "no"), QMessageBox::Ok, this); + questionbox.exec(); + } + + if (mac_iso_swap) + nvk = (nvk == 0x0a) ? 0x32 : 0x0a; + } + + processKeyboardInput(down, nvk); } } #endif From e33ae8a2af3321a7d6ea201654669386d1135f00 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Apr 2023 18:59:38 +0200 Subject: [PATCH 51/53] Preparations for splitting keyboard_at.c into multiple files. --- src/device/keyboard_at.c | 274 +++++++++++++++++++++------------------ 1 file changed, 151 insertions(+), 123 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index 56e95a3ee..bdd7b61c7 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -120,52 +120,74 @@ enum { }; typedef struct { - uint8_t command, status, ib, out, - old_out, secr_phase, mem_addr, input_port, - output_port, old_output_port, key_command, output_locked, - ami_stat, want60, key_wantdata, ami_flags, - key_wantcmd, key_dat, mouse_wantcmd, mouse_dat, - kbc_state, kbd_state, mouse_state, pci; + /* Controller. */ + uint8_t pci, kbc_state, command, want60, + status, ib, out, old_out, + secr_phase, mem_addr, input_port, output_port, + old_output_port, output_locked, ami_stat, ami_flags, + key_ctrl_queue_start, key_ctrl_queue_end; - uint16_t irq_levels, pad; + /* Keyboard. */ + uint8_t kbd_state, key_command, key_wantdata, key_wantcmd, + key_dat, kbd_last_scan_code, sc_or, + key_cmd_queue_start, key_cmd_queue_end, key_queue_start, key_queue_end; + /* Mouse. */ + uint8_t mouse_state, mouse_wantcmd, mouse_dat, mouse_cmd_queue_start, mouse_cmd_queue_end, + mouse_queue_start, mouse_queue_end; + + /* Controller. */ uint8_t mem[0x100]; - int out_new, out_new_mouse, - reset_delay, mouse_reset_delay; + /* Controller - internal FIFO for the purpose of commands with multi-byte output. */ + uint8_t key_ctrl_queue[64]; + /* Keyboard - command response FIFO. */ + uint8_t key_cmd_queue[16]; + + /* Keyboard - scan FIFO. */ + uint8_t key_queue[16]; + + /* Mouse - command response FIFO. */ + uint8_t mouse_cmd_queue[16]; + + /* Mouse - scan FIFO. */ + uint8_t mouse_queue[16]; + + /* Controller. */ + uint16_t irq_levels, pad1; + + /* Keyboard. */ + int out_new, reset_delay; + + /* Mouse. */ + int out_new_mouse, mouse_reset_delay; + + /* Controller. */ uint32_t flags; + /* Controller (main timer). */ + pc_timer_t send_delay_timer; + + /* Controller (P2 pulse callback timer). */ pc_timer_t pulse_cb; uint8_t (*write60_ven)(void *p, uint8_t val); uint8_t (*write64_ven)(void *p, uint8_t val); - - pc_timer_t send_delay_timer; } atkbd_t; -/* bit 0 = repeat, bit 1 = makes break code? */ +/* Global keyboard flags for scan code set 3: + bit 0 = repeat, bit 1 = makes break code? */ uint8_t keyboard_set3_flags[512]; uint8_t keyboard_set3_all_repeat; uint8_t keyboard_set3_all_break; -/* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ -uint8_t keyboard_mode = 0x42; +/* Global keyboard mode: + Bits 0 - 1 = scan code set, bit 6 = translate or not. */ +uint8_t keyboard_mode = 0x42; -static uint8_t key_ctrl_queue[64]; -static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; -static uint8_t key_queue[16]; -static int key_queue_start = 0, key_queue_end = 0; -static uint8_t key_cmd_queue[16]; -static int key_cmd_queue_start = 0, key_cmd_queue_end = 0; -uint8_t mouse_queue[16]; -int mouse_queue_start = 0, mouse_queue_end = 0; -uint8_t mouse_cmd_queue[16]; -int mouse_cmd_queue_start = 0, mouse_cmd_queue_end = 0; -static uint8_t kbd_last_scan_code; static void (*mouse_write)(uint8_t val, void *priv) = NULL; static void *mouse_p = NULL; -static uint8_t sc_or = 0; static atkbd_t *SavedKbd = NULL; // FIXME: remove!!! --FvK /* Non-translated to translated scan codes. */ @@ -655,29 +677,31 @@ set_scancode_map(atkbd_t *dev) static void kbc_queue_reset(uint8_t channel) { + atkbd_t *dev = SavedKbd; + switch (channel) { case 1: - key_queue_start = key_queue_end = 0; - memset(key_queue, 0x00, sizeof(key_queue)); + dev->key_queue_start = dev->key_queue_end = 0; + memset(dev->key_queue, 0x00, sizeof(dev->key_queue)); /* FALLTHROUGH */ case 4: - key_cmd_queue_start = key_cmd_queue_end = 0; - memset(key_cmd_queue, 0x00, sizeof(key_cmd_queue)); + dev->key_cmd_queue_start = dev->key_cmd_queue_end = 0; + memset(dev->key_cmd_queue, 0x00, sizeof(dev->key_cmd_queue)); break; case 2: - mouse_queue_start = mouse_queue_end = 0; - memset(mouse_queue, 0x00, sizeof(mouse_queue)); + dev->mouse_queue_start = dev->mouse_queue_end = 0; + memset(dev->mouse_queue, 0x00, sizeof(dev->mouse_queue)); /* FALLTHROUGH */ case 3: - mouse_cmd_queue_start = mouse_cmd_queue_end = 0; - memset(mouse_cmd_queue, 0x00, sizeof(mouse_cmd_queue)); + dev->mouse_cmd_queue_start = dev->mouse_cmd_queue_end = 0; + memset(dev->mouse_cmd_queue, 0x00, sizeof(dev->mouse_cmd_queue)); break; case 0: default: - key_ctrl_queue_start = key_ctrl_queue_end = 0; - memset(key_ctrl_queue, 0x00, sizeof(key_ctrl_queue)); + dev->key_ctrl_queue_start = dev->key_ctrl_queue_end = 0; + memset(dev->key_ctrl_queue, 0x00, sizeof(dev->key_ctrl_queue)); } } @@ -686,30 +710,30 @@ kbc_queue_add(atkbd_t *dev, uint8_t val, uint8_t channel) { switch (channel) { case 4: - kbd_log("ATkbc: key_cmd_queue[%02X] = %02X;\n", key_cmd_queue_end, val); - key_cmd_queue[key_cmd_queue_end] = val; - key_cmd_queue_end = (key_cmd_queue_end + 1) & 0xf; + kbd_log("ATkbc: dev->key_cmd_queue[%02X] = %02X;\n", dev->key_cmd_queue_end, val); + dev->key_cmd_queue[dev->key_cmd_queue_end] = val; + dev->key_cmd_queue_end = (dev->key_cmd_queue_end + 1) & 0xf; break; case 3: - kbd_log("ATkbc: mouse_cmd_queue[%02X] = %02X;\n", mouse_cmd_queue_end, val); - mouse_cmd_queue[mouse_cmd_queue_end] = val; - mouse_cmd_queue_end = (mouse_cmd_queue_end + 1) & 0xf; + kbd_log("ATkbc: dev->mouse_cmd_queue[%02X] = %02X;\n", dev->mouse_cmd_queue_end, val); + dev->mouse_cmd_queue[dev->mouse_cmd_queue_end] = val; + dev->mouse_cmd_queue_end = (dev->mouse_cmd_queue_end + 1) & 0xf; break; case 2: - kbd_log("ATkbc: mouse_queue[%02X] = %02X;\n", mouse_queue_end, val); - mouse_queue[mouse_queue_end] = val; - mouse_queue_end = (mouse_queue_end + 1) & 0xf; + kbd_log("ATkbc: dev->mouse_queue[%02X] = %02X;\n", dev->mouse_queue_end, val); + dev->mouse_queue[dev->mouse_queue_end] = val; + dev->mouse_queue_end = (dev->mouse_queue_end + 1) & 0xf; break; case 1: - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); - key_queue[key_queue_end] = val; - key_queue_end = (key_queue_end + 1) & 0xf; + kbd_log("ATkbc: dev->key_queue[%02X] = %02X;\n", dev->key_queue_end, val); + dev->key_queue[dev->key_queue_end] = val; + dev->key_queue_end = (dev->key_queue_end + 1) & 0xf; break; case 0: default: - kbd_log("ATkbc: key_ctrl_queue[%02X] = %02X;\n", key_ctrl_queue_end, val); - key_ctrl_queue[key_ctrl_queue_end] = val; - key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0x3f; + kbd_log("ATkbc: dev->key_ctrl_queue[%02X] = %02X;\n", dev->key_ctrl_queue_end, val); + dev->key_ctrl_queue[dev->key_ctrl_queue_end] = val; + dev->key_ctrl_queue_end = (dev->key_ctrl_queue_end + 1) & 0x3f; break; } } @@ -739,14 +763,14 @@ kbc_translate(uint8_t val) /* Allow for scan code translation. */ if (translate && (val == 0xf0)) { kbd_log("ATkbd: translate is on, F0 prefix detected\n"); - sc_or = 0x80; + dev->sc_or = 0x80; return ret; } /* Skip break code if translated make code has bit 7 set. */ - if (translate && (sc_or == 0x80) && (nont_to_t[val] & 0x80)) { + if (translate && (dev->sc_or == 0x80) && (nont_to_t[val] & 0x80)) { kbd_log("ATkbd: translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); - sc_or = 0; + dev->sc_or = 0; return ret; } @@ -804,18 +828,18 @@ kbc_translate(uint8_t val) #ifdef ENABLE_KEYBOARD_AT_LOG kbd_log("scan code: "); if (translate) { - kbd_log("%02X (original: ", (nont_to_t[val] | sc_or)); - if (sc_or == 0x80) + kbd_log("%02X (original: ", (nont_to_t[val] | dev->sc_or)); + if (dev->sc_or == 0x80) kbd_log("F0 "); kbd_log("%02X)\n", val); } else kbd_log("%02X\n", val); #endif - ret = translate ? (nont_to_t[val] | sc_or) : val; + ret = translate ? (nont_to_t[val] | dev->sc_or) : val; - if (sc_or == 0x80) - sc_or = 0; + if (dev->sc_or == 0x80) + dev->sc_or = 0; return ret; } @@ -861,25 +885,25 @@ add_to_kbc_queue_front(atkbd_t *dev, uint8_t val, uint8_t channel, uint8_t stat_ static void add_data_kbd_cmd_queue(atkbd_t *dev, uint8_t val) { - if ((dev->reset_delay > 0) || (key_cmd_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", (dev->reset_delay > 0), (key_cmd_queue_end >= 16)); + if ((dev->reset_delay > 0) || (dev->key_cmd_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", (dev->reset_delay > 0), (dev->key_cmd_queue_end >= 16)); return; } - kbd_log("ATkbc: key_cmd_queue[%02X] = %02X;\n", key_cmd_queue_end, val); + kbd_log("ATkbc: dev->key_cmd_queue[%02X] = %02X;\n", dev->key_cmd_queue_end, val); kbc_queue_add(dev, val, 4); - kbd_last_scan_code = val; + dev->kbd_last_scan_code = val; } static void add_data_kbd_queue(atkbd_t *dev, uint8_t val) { - if (!keyboard_scan || (dev->reset_delay > 0) || (key_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (key_queue_end >= 16)); + if (!keyboard_scan || (dev->reset_delay > 0) || (dev->key_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !keyboard_scan, (dev->reset_delay > 0), (dev->key_queue_end >= 16)); return; } - kbd_log("ATkbc: key_queue[%02X] = %02X;\n", key_queue_end, val); + kbd_log("ATkbc: key_queue[%02X] = %02X;\n", dev->key_queue_end, val); kbc_queue_add(dev, val, 1); - kbd_last_scan_code = val; + dev->kbd_last_scan_code = val; } static void @@ -1006,10 +1030,10 @@ kbc_poll_at(atkbd_t *dev) } /* Do not continue dumping until OBF is clear. */ if (!(dev->status & STAT_OFULL)) { - kbd_log("ATkbc: %02X coming from channel 0\n", key_ctrl_queue[key_ctrl_queue_start]); - add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; - if (key_ctrl_queue_start == key_ctrl_queue_end) + kbd_log("ATkbc: %02X coming from channel 0\n", dev->key_ctrl_queue[dev-.key_ctrl_queue_start]); + add_to_kbc_queue_front(dev, dev->key_ctrl_queue[dev->key_ctrl_queue_start], 0, 0x00); + dev->key_ctrl_queue_start = (dev->key_ctrl_queue_start + 1) & 0x3f; + if (dev->key_ctrl_queue_start == dev->key_ctrl_queue_end) dev->kbc_state = KBC_STATE_MAIN_IBF; } break; @@ -1141,9 +1165,9 @@ kbc_poll_ps2(atkbd_t *dev) /* Do not continue dumping until OBF is clear. */ if (!(dev->status & STAT_OFULL)) { kbd_log("ATkbc: %02X coming from channel 0\n", dev->out_new & 0xff); - add_to_kbc_queue_front(dev, key_ctrl_queue[key_ctrl_queue_start], 0, 0x00); - key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0x3f; - if (key_ctrl_queue_start == key_ctrl_queue_end) + add_to_kbc_queue_front(dev, dev->key_ctrl_queue[dev->key_ctrl_queue_start], 0, 0x00); + dev->key_ctrl_queue_start = (dev->key_ctrl_queue_start + 1) & 0x3f; + if (dev->key_ctrl_queue_start == dev->key_ctrl_queue_end) dev->kbc_state = KBC_STATE_MAIN_IBF; } break; @@ -1206,33 +1230,33 @@ kbc_poll_kbd(atkbd_t *dev) break; case DEV_STATE_MAIN_2: /* Output from scan queue if needed and then return to main loop #1. */ - if (keyboard_scan && (dev->out_new == -1) && (key_queue_start != key_queue_end)) { - kbd_log("ATkbc: %02X (DATA) on channel 1\n", key_queue[key_queue_start]); - dev->out_new = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; + if (keyboard_scan && (dev->out_new == -1) && (dev->key_queue_start != dev->key_queue_end)) { + kbd_log("ATkbc: %02X (DATA) on channel 1\n", dev->key_queue[key_queue_start]); + dev->out_new = dev->key_queue[dev->key_queue_start]; + dev->key_queue_start = (dev->key_queue_start + 1) & 0xf; } - if (!keyboard_scan || (key_cmd_queue_start == key_cmd_queue_end)) + if (!keyboard_scan || (dev->key_queue_start == dev->key_queue_end)) dev->kbd_state = DEV_STATE_MAIN_1; break; case DEV_STATE_MAIN_OUT: case DEV_STATE_RESET_OUT: /* Output command response and then return to main loop #2. */ - if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { + if ((dev->out_new == -1) && (dev->key_cmd_queue_start != dev->key_cmd_queue_end)) { kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); - dev->out_new = key_cmd_queue[key_cmd_queue_start]; - key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; + dev->out_new = dev->key_cmd_queue[dev->key_cmd_queue_start]; + dev->key_cmd_queue_start = (dev->key_cmd_queue_start + 1) & 0xf; } - if (key_cmd_queue_start == key_cmd_queue_end) + if (dev->key_cmd_queue_start == dev->key_cmd_queue_end) dev->kbd_state = (dev->kbd_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; break; case DEV_STATE_MAIN_WANT_IN: /* Output command response and then wait for host data. */ - if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { - kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); - dev->out_new = key_cmd_queue[key_cmd_queue_start]; - key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; + if ((dev->out_new == -1) && (dev->key_cmd_queue_start != dev->key_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 1\n", dev->key_cmd_queue[dev->key_cmd_queue_start]); + dev->out_new = dev->key_cmd_queue[dev->key_cmd_queue_start]; + dev->key_cmd_queue_start = (dev->key_cmd_queue_start + 1) & 0xf; } - if (key_cmd_queue_start == key_cmd_queue_end) + if (dev->key_cmd_queue_start == dev->key_cmd_queue_end) dev->kbd_state = DEV_STATE_MAIN_IN; break; case DEV_STATE_MAIN_IN: @@ -1247,12 +1271,12 @@ kbc_poll_kbd(atkbd_t *dev) break; case DEV_STATE_MAIN_WANT_RESET: /* Output command response and then go to the reset state. */ - if ((dev->out_new == -1) && (key_cmd_queue_start != key_cmd_queue_end)) { - kbd_log("ATkbc: %02X (CMD ) on channel 1\n", key_cmd_queue[key_cmd_queue_start]); - dev->out_new = key_cmd_queue[key_cmd_queue_start]; - key_cmd_queue_start = (key_cmd_queue_start + 1) & 0xf; + if ((dev->out_new == -1) && (dev->key_cmd_queue_start != dev->key_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 1\n", dev->key_cmd_queue[dev->key_cmd_queue_start]); + dev->out_new = dev->key_cmd_queue[dev->key_cmd_queue_start]; + dev->key_cmd_queue_start = (dev->key_cmd_queue_start + 1) & 0xf; } - if (key_cmd_queue_start == key_cmd_queue_end) + if (dev->key_cmd_queue_start == dev->key_cmd_queue_end) dev->kbd_state = DEV_STATE_RESET; break; } @@ -1292,33 +1316,33 @@ kbc_poll_aux(atkbd_t *dev) break; case DEV_STATE_MAIN_2: /* Output from scan queue if needed and then return to main loop #1. */ - if (mouse_scan && (dev->out_new_mouse == -1) && (mouse_queue_start != mouse_queue_end)) { - kbd_log("ATkbc: %02X (DATA) on channel 2\n", mouse_queue[mouse_queue_start]); - dev->out_new_mouse = mouse_queue[mouse_queue_start]; - mouse_queue_start = (mouse_queue_start + 1) & 0xf; + if (mouse_scan && (dev->out_new_mouse == -1) && (dev->mouse_queue_start != dev->mouse_queue_end)) { + kbd_log("ATkbc: %02X (DATA) on channel 2\n", dev->mouse_queue[dev->mouse_queue_start]); + dev->out_new_mouse = dev->mouse_queue[dev->mouse_queue_start]; + dev->mouse_queue_start = (dev->mouse_queue_start + 1) & 0xf; } - if (!mouse_scan || (mouse_cmd_queue_start == mouse_cmd_queue_end)) + if (!mouse_scan || (dev->mouse_queue_start == dev->mouse_queue_end)) dev->mouse_state = DEV_STATE_MAIN_1; break; case DEV_STATE_MAIN_OUT: case DEV_STATE_RESET_OUT: /* Output command response and then return to main loop #2. */ - if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { - kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); - dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; - mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + if ((dev->out_new_mouse == -1) && (dev->mouse_cmd_queue_start != dev->mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]); + dev->out_new_mouse = dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]; + dev->mouse_cmd_queue_start = (dev->mouse_cmd_queue_start + 1) & 0xf; } - if (mouse_cmd_queue_start == mouse_cmd_queue_end) + if (dev->mouse_cmd_queue_start == dev->mouse_cmd_queue_end) dev->mouse_state = (dev->mouse_state == DEV_STATE_RESET_OUT) ? DEV_STATE_MAIN_1 : DEV_STATE_MAIN_2; break; case DEV_STATE_MAIN_WANT_IN: /* Output command response and then wait for host data. */ - if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { - kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); - dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; - mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + if ((dev->out_new_mouse == -1) && (dev->mouse_cmd_queue_start != dev->mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]); + dev->out_new_mouse = dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]; + dev->mouse_cmd_queue_start = (dev->mouse_cmd_queue_start + 1) & 0xf; } - if (mouse_cmd_queue_start == mouse_cmd_queue_end) + if (dev->mouse_cmd_queue_start == dev->mouse_cmd_queue_end) dev->mouse_state = DEV_STATE_MAIN_IN; break; case DEV_STATE_MAIN_IN: @@ -1334,12 +1358,12 @@ kbc_poll_aux(atkbd_t *dev) break; case DEV_STATE_MAIN_WANT_RESET: /* Output command response and then go to the reset state. */ - if ((dev->out_new_mouse == -1) && (mouse_cmd_queue_start != mouse_cmd_queue_end)) { - kbd_log("ATkbc: %02X (CMD ) on channel 2\n", mouse_cmd_queue[mouse_cmd_queue_start]); - dev->out_new_mouse = mouse_cmd_queue[mouse_cmd_queue_start]; - mouse_cmd_queue_start = (mouse_cmd_queue_start + 1) & 0xf; + if ((dev->out_new_mouse == -1) && (dev->mouse_cmd_queue_start != dev->mouse_cmd_queue_end)) { + kbd_log("ATkbc: %02X (CMD ) on channel 2\n", dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]); + dev->out_new_mouse = dev->mouse_cmd_queue[dev->mouse_cmd_queue_start]; + dev->mouse_cmd_queue_start = (dev->mouse_cmd_queue_start + 1) & 0xf; } - if (mouse_cmd_queue_start == mouse_cmd_queue_end) + if (dev->mouse_cmd_queue_start == dev->mouse_cmd_queue_end) dev->mouse_state = DEV_STATE_RESET; break; } @@ -2239,7 +2263,7 @@ kbd_key_reset(atkbd_t *dev, int do_fa) dev->out_new = -1; kbc_queue_reset(1); - kbd_last_scan_code = 0x00; + dev->kbd_last_scan_code = 0x00; /* Set scan code set to 2. */ keyboard_mode = (keyboard_mode & 0xfc) | 0x02; @@ -2247,6 +2271,8 @@ kbd_key_reset(atkbd_t *dev, int do_fa) keyboard_scan = 1; + dev->sc_or = 0; + if (do_fa) add_data_kbd_front(dev, 0xfa); @@ -2432,8 +2458,8 @@ kbd_process_cmd(void *priv) break; case 0xfe: /* resend last scan code */ - kbd_log("ATkbd: reset last scan code\n"); - add_data_kbd_front(dev, kbd_last_scan_code); + kbd_log("ATkbd: resend last scan code\n"); + add_data_kbd_front(dev, dev->kbd_last_scan_code); break; case 0xff: /* reset */ @@ -2824,9 +2850,9 @@ kbd_reset(void *priv) dev->out_new = dev->out_new_mouse = -1; for (i = 0; i < 3; i++) kbc_queue_reset(i); - kbd_last_scan_code = 0; + dev->kbd_last_scan_code = 0; - sc_or = 0; + dev->sc_or = 0; memset(keyboard_set3_flags, 0, 512); @@ -3277,8 +3303,8 @@ keyboard_at_adddata_mouse(uint8_t val) { atkbd_t *dev = SavedKbd; - if (!mouse_scan || (dev->mouse_reset_delay > 0) || (mouse_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !mouse_scan, (dev->mouse_reset_delay > 0), (mouse_queue_end >= 16)); + if (!mouse_scan || (dev->mouse_reset_delay > 0) || (dev->mouse_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i, %i\n", !mouse_scan, (dev->mouse_reset_delay > 0), (dev->mouse_queue_end >= 16)); return; } kbc_queue_add(dev, val, 2); @@ -3289,8 +3315,8 @@ keyboard_at_adddata_mouse_cmd(uint8_t val) { atkbd_t *dev = SavedKbd; - if ((dev->mouse_reset_delay > 0) || (mouse_cmd_queue_end >= 16)) { - kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", (dev->mouse_reset_delay > 0), (mouse_cmd_queue_end >= 16)); + if ((dev->mouse_reset_delay > 0) || (dev->mouse_cmd_queue_end >= 16)) { + kbd_log("ATkbc: Unable to add to queue, conditions: %i, %i\n", (dev->mouse_reset_delay > 0), (dev->mouse_cmd_queue_end >= 16)); return; } kbc_queue_add(dev, val, 3); @@ -3299,7 +3325,9 @@ keyboard_at_adddata_mouse_cmd(uint8_t val) uint8_t keyboard_at_mouse_pos(void) { - return ((mouse_queue_end - mouse_queue_start) & 0xf); + atkbd_t *dev = SavedKbd; + + return ((dev->mouse_queue_end - dev->mouse_queue_start) & 0xf); } void From 5da3e78fc100159e2f43bc0c66dfa824b079d035 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 10 Apr 2023 19:18:39 +0200 Subject: [PATCH 52/53] Save SavedKbd before resetting the queues, fixes the segmentation fault. --- src/device/keyboard_at.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/device/keyboard_at.c b/src/device/keyboard_at.c index bdd7b61c7..194339c72 100644 --- a/src/device/keyboard_at.c +++ b/src/device/keyboard_at.c @@ -2934,6 +2934,9 @@ kbd_init(const device_t *info) dev->flags = info->local; dev->pci = !!(info->flags & DEVICE_PCI); + /* We need this, sadly. */ + SavedKbd = dev; + video_reset(gfxcard[0]); kbd_reset(dev); @@ -2983,9 +2986,6 @@ kbd_init(const device_t *info) break; } - /* We need this, sadly. */ - SavedKbd = dev; - return (dev); } From da36911c9a00556cd777703687dc395a625a73a3 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Mon, 10 Apr 2023 15:21:14 -0300 Subject: [PATCH 53/53] qt: Remove Mac keyboard debug code --- src/qt/qt_mainwindow.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index ca0981ace..0c5e204ce 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -1060,7 +1060,7 @@ MainWindow::processMacKeyboardInput(bool down, const QKeyEvent *event) (key == Qt::Key_QuoteDbl) || /* Brazilian shifted, Turkish Q unshifted */ (key == Qt::Key_QuoteLeft) || /* Croatian (right quote unknown) */ (key == Qt::Key_Dollar) || /* Danish unshifted */ - (key == Qt::Key_AsciiCircum) || /* German unshifted, Polish unshifted */ + (key == Qt::Key_AsciiCircum) || (key == 0x1ffffff) || /* German unshifted (0x1ffffff according to one tester), Polish unshifted */ (key == Qt::Key_degree) || /* German shifted, Icelandic unshifted, Spanish Latin America shifted, Swiss shifted, Swedish shifted */ (key == Qt::Key_0) || /* Hungarian unshifted */ (key == Qt::Key_diaeresis) || /* Icelandic shifted */ @@ -1071,13 +1071,12 @@ MainWindow::processMacKeyboardInput(bool down, const QKeyEvent *event) (key == Qt::Key_Slash) /* French Canadian unshifted, Ukrainian shifted */ )) mac_iso_swap = true; - - /* Temporary debug code. */ +#if 0 if (down) { QMessageBox questionbox(QMessageBox::Icon::Information, QString("Mac key swap test"), QString("nativeVirtualKey 0x%1\nnativeScanCode 0x%2\nkey 0x%3\nmac_iso_swap %4").arg(nvk, 0, 16).arg(event->nativeScanCode(), 0, 16).arg(key, 0, 16).arg(mac_iso_swap ? "yes" : "no"), QMessageBox::Ok, this); questionbox.exec(); } - +#endif if (mac_iso_swap) nvk = (nvk == 0x0a) ? 0x32 : 0x0a; }