Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 111 additions & 108 deletions src/keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "video.h"

#include <SDL2/SDL.h>
#include <SDL2/SDL_scancode.h>
#include <stdint.h>
#include <string.h>

Expand All @@ -17,10 +18,10 @@ typedef enum ceda_associator_type_t {
CEDA_ASSOCIATOR_FUNC,
} ceda_associator_type_t;

typedef void (*ceda_associator_func_t)(SDL_Keycode);
typedef void (*ceda_associator_func_t)(SDL_Scancode);

typedef struct ceda_associator_t {
SDL_Keycode sdl;
SDL_Scancode sdl;
ceda_associator_type_t type;
void *ptr;
} ceda_associator_t;
Expand All @@ -43,19 +44,19 @@ static uint8_t modifiers = KEYBOARD_MODIFIERS_DEFAULT;

static void keyboard_toggle_modifier(SDL_Keycode code) {
switch (code) {
case SDLK_LSHIFT:
case SDLK_RSHIFT:
case SDL_SCANCODE_LSHIFT:
case SDL_SCANCODE_RSHIFT:
modifiers ^= KEYBOARD_MODIFIER_SHIFT;
break;
case SDLK_CAPSLOCK:
case SDL_SCANCODE_CAPSLOCK:
modifiers ^= KEYBOARD_MODIFIER_CAPS_LOCK;
break;
case SDLK_LALT:
case SDLK_RALT:
case SDL_SCANCODE_LALT:
case SDL_SCANCODE_RALT:
modifiers ^= KEYBOARD_MODIFIER_ALT;
break;
case SDLK_LCTRL:
case SDLK_RCTRL:
case SDL_SCANCODE_LCTRL:
case SDL_SCANCODE_RCTRL:
modifiers ^= KEYBOARD_MODIFIER_CTRL;
break;
default:
Expand All @@ -65,120 +66,122 @@ static void keyboard_toggle_modifier(SDL_Keycode code) {

static const ceda_associator_t associators[] = {
// row 0
{SDLK_INSERT, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4D}},
{SDLK_F1, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4E}},
{SDLK_F2, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4F}},
{SDLK_F3, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x50}},
{SDLK_F4, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x51}},
{SDLK_F5, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x52}},
{SDLK_F6, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x53}},
{SDLK_F7, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x54}},
{SDLK_F8, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x55}},
{SDLK_F9, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x56}},
{SDLK_F10, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x57}},
{SDLK_F11, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x58}},
{SDLK_F12, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x59}},
{SDLK_F13, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x5A}},
{SDLK_F14, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x5B}},
{SDLK_F15, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x5C}},
{SDL_SCANCODE_INSERT, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4D}},
{SDL_SCANCODE_F1, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4E}},
{SDL_SCANCODE_F2, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4F}},
{SDL_SCANCODE_F3, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x50}},
{SDL_SCANCODE_F4, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x51}},
{SDL_SCANCODE_F5, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x52}},
{SDL_SCANCODE_F6, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x53}},
{SDL_SCANCODE_F7, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x54}},
{SDL_SCANCODE_F8, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x55}},
{SDL_SCANCODE_F9, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x56}},
{SDL_SCANCODE_F10, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x57}},
{SDL_SCANCODE_F11, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x58}},
{SDL_SCANCODE_F12, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x59}},
{SDL_SCANCODE_F13, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x5A}},
{SDL_SCANCODE_F14, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x5B}},
{SDL_SCANCODE_F15, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x5C}},

// row 1
{SDLK_ESCAPE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x01}},
{SDLK_LESS, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x02}},
{SDLK_1, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x03}},
{SDLK_2, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x04}},
{SDLK_3, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x05}},
{SDLK_4, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x06}},
{SDLK_5, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x07}},
{SDLK_6, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x08}},
{SDLK_7, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x09}},
{SDLK_8, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0a}},
{SDLK_9, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0b}},
{SDLK_0, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0C}},
{SDLK_HASH, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0D}},
{SDLK_AT, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0E}},
{SDLK_DELETE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0F}},
{SDLK_CARET, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x10}},
{SDL_SCANCODE_ESCAPE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x01}},
{SDL_SCANCODE_GRAVE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x02}},
{SDL_SCANCODE_1, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x03}},
{SDL_SCANCODE_2, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x04}},
{SDL_SCANCODE_3, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x05}},
{SDL_SCANCODE_4, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x06}},
{SDL_SCANCODE_5, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x07}},
{SDL_SCANCODE_6, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x08}},
{SDL_SCANCODE_7, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x09}},
{SDL_SCANCODE_8, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0a}},
{SDL_SCANCODE_9, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0b}},
{SDL_SCANCODE_0, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0C}},
{SDL_SCANCODE_MINUS, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0D}},
{SDL_SCANCODE_EQUALS, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0E}},
{SDL_SCANCODE_DELETE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x0F}},
// {} ex CARET (0x10)
// mapped to SDL_SCANCODE_NONUSBACKSLASH (additional key for ISO layout)

// row 2
// {} BREAK (0x11)
{SDLK_TAB, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x12}},
{SDLK_a, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x13}},
{SDLK_z, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x14}},
{SDLK_e, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x15}},
{SDLK_r, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x16}},
{SDLK_t, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x17}},
{SDLK_y, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x18}},
{SDLK_u, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x19}},
{SDLK_i, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1A}},
{SDLK_o, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1B}},
{SDLK_p, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1C}},
{SDLK_GREATER, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1D}},
// {} umlaut / dieresis (0x1E)
{SDLK_KP_RIGHTBRACE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1F}},
{SDL_SCANCODE_TAB, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x12}},
{SDL_SCANCODE_Q, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x13}},
{SDL_SCANCODE_W, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x14}},
{SDL_SCANCODE_E, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x15}},
{SDL_SCANCODE_R, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x16}},
{SDL_SCANCODE_T, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x17}},
{SDL_SCANCODE_Y, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x18}},
{SDL_SCANCODE_U, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x19}},
{SDL_SCANCODE_I, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1A}},
{SDL_SCANCODE_O, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1B}},
{SDL_SCANCODE_P, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1C}},
{SDL_SCANCODE_LEFTBRACKET, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1D}},
{SDL_SCANCODE_RIGHTBRACKET, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1E}},
{SDL_SCANCODE_BACKSLASH, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x1F}},

// row 3
{SDLK_CAPSLOCK, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
// {} SHIFT LOCK
{SDLK_q, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x20}},
{SDLK_s, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x21}},
{SDLK_d, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x22}},
{SDLK_f, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x23}},
{SDLK_g, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x24}},
{SDLK_h, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x25}},
{SDLK_j, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x26}},
{SDLK_k, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x27}},
{SDLK_l, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x28}},
{SDLK_m, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x29}},
{SDLK_PERCENT, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2A}},
{SDLK_RETURN, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2B}},
{SDLK_KP_LEFTBRACE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2C}},
{SDL_SCANCODE_CAPSLOCK, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
// {} SHIFT LOCK (0x65)
{SDL_SCANCODE_A, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x20}},
{SDL_SCANCODE_S, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x21}},
{SDL_SCANCODE_D, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x22}},
{SDL_SCANCODE_F, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x23}},
{SDL_SCANCODE_G, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x24}},
{SDL_SCANCODE_H, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x25}},
{SDL_SCANCODE_J, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x26}},
{SDL_SCANCODE_K, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x27}},
{SDL_SCANCODE_L, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x28}},
{SDL_SCANCODE_SEMICOLON, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x29}},
{SDL_SCANCODE_APOSTROPHE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2A}},
{SDL_SCANCODE_RETURN, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2B}},
// {} ex LEFT BRACKET (0x2C)

// row 4
// {} CAN (0x2D)
{SDLK_LSHIFT, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDLK_w, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2E}},
{SDLK_x, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2F}},
{SDLK_c, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x30}},
{SDLK_v, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x31}},
{SDLK_b, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x32}},
{SDLK_n, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x33}},
{SDLK_SLASH, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x34}},
{SDLK_PERIOD, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x35}},
{SDLK_MINUS, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x36}},
{SDLK_PLUS, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x37}},
{SDLK_RSHIFT, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDL_SCANCODE_LSHIFT, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDL_SCANCODE_Z, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2E}},
{SDL_SCANCODE_X, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x2F}},
{SDL_SCANCODE_C, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x30}},
{SDL_SCANCODE_V, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x31}},
{SDL_SCANCODE_B, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x32}},
{SDL_SCANCODE_N, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x33}},
{SDL_SCANCODE_M, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x34}},
{SDL_SCANCODE_COMMA, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x35}},
{SDL_SCANCODE_PERIOD, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x36}},
{SDL_SCANCODE_SLASH, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x37}},
{SDL_SCANCODE_RSHIFT, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
// {} LINE FEED (0x38)

// row 5
{SDLK_LCTRL, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDLK_SPACE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x39}},
{SDLK_RALT, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDL_SCANCODE_LCTRL, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDL_SCANCODE_SPACE, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x39}},
{SDL_SCANCODE_RALT, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},

// useful keys on modern IBM keyboards
{SDLK_RCTRL, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDLK_LALT, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDL_SCANCODE_RCTRL, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDL_SCANCODE_LALT, CEDA_ASSOCIATOR_FUNC, keyboard_toggle_modifier},
{SDL_SCANCODE_NONUSBACKSLASH, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x10}},

// number pad
{SDLK_UP, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3A}},
{SDLK_DOWN, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3B}},
{SDLK_LEFT, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3C}},
{SDLK_RIGHT, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3D}},
{SDLK_KP_7, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3E}},
{SDLK_KP_8, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3F}},
{SDLK_KP_9, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x40}},
{SDLK_KP_CLEAR, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x41}},
{SDLK_KP_4, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x42}},
{SDLK_KP_5, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x43}},
{SDLK_KP_6, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x44}},
{SDLK_KP_MINUS, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x45}},
{SDLK_KP_1, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x46}},
{SDLK_KP_2, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x47}},
{SDLK_KP_3, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x48}},
{SDLK_KP_ENTER, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4C}},
{SDLK_KP_PERIOD, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x49}},
{SDLK_KP_0, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4A}},
{SDLK_KP_00, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4B}},
{SDL_SCANCODE_UP, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3A}},
{SDL_SCANCODE_DOWN, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3B}},
{SDL_SCANCODE_LEFT, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3C}},
{SDL_SCANCODE_RIGHT, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3D}},
{SDL_SCANCODE_KP_7, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3E}},
{SDL_SCANCODE_KP_8, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x3F}},
{SDL_SCANCODE_KP_9, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x40}},
{SDL_SCANCODE_KP_CLEAR, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x41}},
{SDL_SCANCODE_KP_4, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x42}},
{SDL_SCANCODE_KP_5, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x43}},
{SDL_SCANCODE_KP_6, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x44}},
{SDL_SCANCODE_KP_MINUS, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x45}},
{SDL_SCANCODE_KP_1, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x46}},
{SDL_SCANCODE_KP_2, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x47}},
{SDL_SCANCODE_KP_3, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x48}},
{SDL_SCANCODE_KP_ENTER, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4C}},
{SDL_SCANCODE_KP_PERIOD, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x49}},
{SDL_SCANCODE_KP_0, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4A}},
{SDL_SCANCODE_KP_00, CEDA_ASSOCIATOR_KEY, &(uint8_t){0x4B}},
};

void keyboard_init(void) {
Expand All @@ -192,12 +195,12 @@ void keyboard_init(void) {
}

void keyboard_handleEvent(const SDL_KeyboardEvent *event) {
LOG_DEBUG("keycode = %" PRId32 ", repeat = %d\n", event->keysym.sym,
LOG_DEBUG("scancode = %" PRId32 ", repeat = %d\n", event->keysym.scancode,
(int)event->repeat);

for (size_t i = 0; i < ARRAY_SIZE(associators); ++i) {
const ceda_associator_t *const associator = &associators[i];
if (associator->sdl != event->keysym.sym)
if (associator->sdl != event->keysym.scancode)
continue;

switch (associator->type) {
Expand Down
Loading