diff --git a/zephr/os_linux.odin b/zephr/os_linux.odin index 8b98d03..ab5488e 100644 --- a/zephr/os_linux.odin +++ b/zephr/os_linux.odin @@ -7,6 +7,8 @@ import x11 "vendor:x11/xlib" import "../glx" import "../xcursor" +OsEvent :: x11.Cursor + @(private="file") PropModeReplace :: 0 @(private="file") @@ -32,8 +34,7 @@ x11_go_fullscreen :: proc() { // and properly fullscreen the window size_hints := x11.XAllocSizeHints() - zephr_ctx.window.pre_fullscreen_size.x = zephr_ctx.window.size.x - zephr_ctx.window.pre_fullscreen_size.y = zephr_ctx.window.size.y + zephr_ctx.window.pre_fullscreen_size = zephr_ctx.window.size if (size_hints != nil) { size_hints.flags = {.PPosition, .PSize} size_hints.width = cast(i32)zephr_ctx.window.size.x @@ -299,94 +300,6 @@ backend_shutdown :: proc() { x11.XCloseDisplay(x11_display) } -@(private="file") -x11_mods_to_zephr_mods :: proc(scancode: Scancode, is_press: bool) -> KeyMod { - mods := zephr_ctx.keyboard.mods - - if (is_press) { - if (scancode == .LEFT_SHIFT) { - mods |= {.LEFT_SHIFT, .SHIFT} - } - if (scancode == .RIGHT_SHIFT) { - mods |= {.RIGHT_SHIFT, .SHIFT} - } - if (scancode == .LEFT_CTRL) { - mods |= {.LEFT_CTRL, .CTRL} - } - if (scancode == .RIGHT_CTRL) { - mods |= {.RIGHT_CTRL, .CTRL} - } - if (scancode == .LEFT_ALT) { - mods |= {.LEFT_ALT, .ALT} - } - if (scancode == .RIGHT_ALT) { - mods |= {.RIGHT_ALT, .ALT} - } - if (scancode == .LEFT_META) { - mods |= {.LEFT_META, .META} - } - if (scancode == .RIGHT_META) { - mods |= {.RIGHT_META, .META} - } - if (scancode == .CAPS_LOCK) { - mods |= {.CAPS_LOCK} - } - if (scancode == .NUM_LOCK_OR_CLEAR) { - mods |= {.NUM_LOCK} - } - } else { - if (scancode == .LEFT_SHIFT) { - mods &= ~{.LEFT_SHIFT} - } - if (scancode == .RIGHT_SHIFT) { - mods &= ~{.RIGHT_SHIFT} - } - if (!(.RIGHT_SHIFT in mods) && !(.LEFT_SHIFT in mods)) { - mods &= ~{.SHIFT} - } - - if (scancode == .LEFT_CTRL) { - mods &= ~{.LEFT_CTRL} - } - if (scancode == .RIGHT_CTRL) { - mods &= ~{.RIGHT_CTRL} - } - if (!(.RIGHT_CTRL in mods) && !(.LEFT_CTRL in mods)) { - mods &= ~{.CTRL} - } - - if (scancode == .LEFT_ALT) { - mods &= ~{.LEFT_ALT} - } - if (scancode == .RIGHT_ALT) { - mods &= ~{.RIGHT_ALT} - } - if (!(.RIGHT_ALT in mods) && !(.LEFT_ALT in mods)) { - mods &= ~{.ALT} - } - - if (scancode == .LEFT_META) { - mods &= ~{.LEFT_META} - } - if (scancode == .RIGHT_META) { - mods &= ~{.RIGHT_META} - } - if (!(.RIGHT_META in mods) && !(.LEFT_META in mods)) { - mods &= ~{.META} - } - - if (scancode == .CAPS_LOCK) { - mods &= ~{.CAPS_LOCK} - } - if (scancode == .NUM_LOCK_OR_CLEAR) { - mods &= ~{.NUM_LOCK} - } - } - - zephr_ctx.keyboard.mods = mods - return mods -} - backend_swapbuffers :: proc() { glx.SwapBuffers(x11_display, x11_window) } @@ -435,7 +348,7 @@ backend_get_os_events :: proc(e_out: ^Event) -> bool { e_out.type = .KEY_PRESSED e_out.key.scancode = scancode //e_out.key.code = keycode; - e_out.key.mods = x11_mods_to_zephr_mods(scancode, true) + e_out.key.mods = set_zephr_mods(scancode, true) return true } else if xev.type == .KeyRelease { @@ -447,7 +360,7 @@ backend_get_os_events :: proc(e_out: ^Event) -> bool { e_out.type = .KEY_RELEASED e_out.key.scancode = scancode //e_out.key.code = keycode; - e_out.key.mods = x11_mods_to_zephr_mods(scancode, false) + e_out.key.mods = set_zephr_mods(scancode, false) return true } else if xev.type == .ButtonPress { @@ -530,4 +443,20 @@ backend_get_os_events :: proc(e_out: ^Event) -> bool { } return false +} + +backend_set_cursor :: proc() { + x11.XDefineCursor(x11_display, x11_window, zephr_ctx.cursors[zephr_ctx.cursor]) +} + +backend_init_cursors :: proc() { + zephr_ctx.cursors[.ARROW] = x11.XCreateFontCursor(x11_display, .XC_left_ptr) + zephr_ctx.cursors[.IBEAM] = x11.XCreateFontCursor(x11_display, .XC_xterm) + zephr_ctx.cursors[.CROSSHAIR] = x11.XCreateFontCursor(x11_display, .XC_crosshair) + zephr_ctx.cursors[.HAND] = x11.XCreateFontCursor(x11_display, .XC_hand1) + zephr_ctx.cursors[.HRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_h_double_arrow) + zephr_ctx.cursors[.VRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_v_double_arrow) + + non-standard cursors + zephr_ctx.cursors[.DISABLED] = xcursor.LibraryLoadCursor(x11_display, "crossed_circle") } \ No newline at end of file diff --git a/zephr/os_windows.odin b/zephr/os_windows.odin index 051ba12..c1208e9 100644 --- a/zephr/os_windows.odin +++ b/zephr/os_windows.odin @@ -3,7 +3,6 @@ package zephr import "core:log" -import "core:fmt" import "core:strings" import "core:strconv" import "core:os" @@ -12,6 +11,15 @@ import win32 "core:sys/windows" import gl "vendor:OpenGL" +// BUG: setting the cursor every frame messes with the cursor for resizing when on the edge of the window +// TODO: handle start window in fullscreen +// currently the way to "start" a window in fullscreen is to just create a regular window +// and immediately fullscreen it. This works fine but there's a moment where you can see the regular-sized window. +// Not a priority right now. +// TODO: only log debug when ODIN_DEBUG is true + +OsCursor :: win32.HCURSOR + OsEvent :: struct { type: win32.UINT, lparam: win32.LPARAM, @@ -41,7 +49,33 @@ backend_get_screen_size :: proc() -> Vec2 { } backend_toggle_fullscreen :: proc(fullscreen: bool) { - // TODO: + context.logger = logger + // TODO: handle multiple monitors + + if fullscreen { + w := cast(i32)zephr_ctx.window.pre_fullscreen_size.x + h := cast(i32)zephr_ctx.window.pre_fullscreen_size.y + + win_style := (win32.WS_OVERLAPPEDWINDOW if !zephr_ctx.window.non_resizable else win32.WS_OVERLAPPEDWINDOW & ~win32.WS_MAXIMIZEBOX & ~win32.WS_THICKFRAME) | win32.WS_VISIBLE + + // Adjust the rect to account for the window titlebar and frame sizes + rect := win32.RECT{0, 0, w, h} + win32.AdjustWindowRect(&rect, win_style, false) + + w = rect.right - rect.left + h = rect.bottom - rect.top + x := cast(i32)(zephr_ctx.screen_size.x / 2 - cast(f32)w / 2) + y := cast(i32)(zephr_ctx.screen_size.y / 2 - cast(f32)h / 2) + + win32.SetWindowLongPtrW(hwnd, win32.GWL_STYLE, cast(win32.LONG_PTR)(win_style)) + win32.SetWindowPos(hwnd, nil, x, y, w, h, win32.SWP_FRAMECHANGED) + } else { + zephr_ctx.window.pre_fullscreen_size = zephr_ctx.window.size + w := cast(i32)zephr_ctx.screen_size.x + h := cast(i32)zephr_ctx.screen_size.y + result := win32.SetWindowLongPtrW(hwnd, win32.GWL_STYLE, cast(win32.LONG_PTR)(win32.WS_VISIBLE | win32.WS_POPUPWINDOW)) + win32.SetWindowPos(hwnd, win32.HWND_TOP, 0, 0, w, h, win32.SWP_FRAMECHANGED) + } } @(private="file") @@ -116,7 +150,7 @@ init_legacy_gl :: proc(class_name: win32.wstring, hInstance: win32.HINSTANCE) { } @(private="file") -init_gl :: proc(class_name: win32.wstring, window_title: win32.wstring, window_size: Vec2, hInstance: win32.HINSTANCE) { +init_gl :: proc(class_name: win32.wstring, window_title: win32.wstring, window_size: Vec2, window_non_resizable: bool, hInstance: win32.HINSTANCE) { screen_size := Vec2{ cast(f32)win32.GetSystemMetrics(win32.SM_CXSCREEN), cast(f32)win32.GetSystemMetrics(win32.SM_CYSCREEN), @@ -131,11 +165,13 @@ init_gl :: proc(class_name: win32.wstring, window_title: win32.wstring, window_s win_width := rect.right - rect.left win_height := rect.bottom - rect.top - hwnd := win32.CreateWindowExW( + win_style := win32.WS_OVERLAPPEDWINDOW if !window_non_resizable else (win32.WS_OVERLAPPEDWINDOW & ~win32.WS_THICKFRAME & ~win32.WS_MAXIMIZEBOX) + + hwnd = win32.CreateWindowExW( 0, class_name, window_title, - win32.WS_OVERLAPPEDWINDOW, + win_style, cast(i32)win_x, cast(i32)win_y, win_width, win_height, @@ -165,9 +201,7 @@ init_gl :: proc(class_name: win32.wstring, window_title: win32.wstring, window_s win32.WGL_DRAW_TO_WINDOW_ARB, 1, win32.WGL_SUPPORT_OPENGL_ARB, 1, win32.WGL_DOUBLE_BUFFER_ARB, 1, - // TODO: test to see if EXCHANGE actually causes problems in fullscreen - /* WGL_SWAP_EXCHANGE_ARB causes problems with window menu in fullscreen */ - win32.WGL_SWAP_METHOD_ARB, win32.WGL_SWAP_COPY_ARB, + win32.WGL_SWAP_METHOD_ARB, win32.WGL_SWAP_EXCHANGE_ARB, win32.WGL_PIXEL_TYPE_ARB, win32.WGL_TYPE_RGBA_ARB, win32.WGL_ACCELERATION_ARB, win32.WGL_FULL_ACCELERATION_ARB, win32.WGL_COLOR_BITS_ARB, 32, @@ -318,7 +352,7 @@ backend_init :: proc(window_title: cstring, window_size: Vec2, icon_path: cstrin win32.SetProcessDpiAwarenessContext(win32.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) init_legacy_gl(class_name, hInstance) - init_gl(class_name, window_title, window_size, hInstance) + init_gl(class_name, window_title, window_size, window_non_resizable, hInstance) } backend_get_os_events :: proc(e_out: ^Event) -> bool { @@ -441,20 +475,26 @@ backend_get_os_events :: proc(e_out: ^Event) -> bool { return true case win32.WM_SYSKEYDOWN: fallthrough case win32.WM_KEYDOWN: - log.debug(event.lparam) // Bits 16-23 hold the scancode system_scancode := (event.lparam & 0xFF0000) >> 16 + is_extended := event.lparam & (1 << 24) != 0 - scancode := scan1_scancode_to_zephr_scancode_map[system_scancode] + scancode := scan1_scancode_to_zephr_scancode_map(auto_cast system_scancode, is_extended) - log.debug(system_scancode) - log.debug(scancode) - // TODO: + e_out.key.scancode = scancode + e_out.key.mods = set_zephr_mods(scancode, true) + return true case win32.WM_SYSKEYUP: fallthrough case win32.WM_KEYUP: - // TODO: - // 0101 0010 - //log.debug("released key") + // Bits 16-23 hold the scancode + system_scancode := (event.lparam & 0xFF0000) >> 16 + is_extended := event.lparam & (1 << 24) != 0 + + scancode := scan1_scancode_to_zephr_scancode_map(auto_cast system_scancode, is_extended) + + e_out.key.scancode = scancode + e_out.key.mods = set_zephr_mods(scancode, false) + return true } } @@ -476,6 +516,8 @@ backend_swapbuffers :: proc() { // https://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/translate.pdf @(private="file") scan1_scancode_to_zephr_scancode_map :: proc(scancode: u8, is_extended: bool) -> Scancode { + context.logger = logger + switch scancode { case 0: return .NULL @@ -517,7 +559,7 @@ scan1_scancode_to_zephr_scancode_map :: proc(scancode: u8, is_extended: bool) -> case 0x0A: return .KEY_9 case 0x0B: return .KEY_0 - case 0x1C: return .ENTER + case 0x1C: return .KP_ENTER if is_extended else .ENTER case 0x01: return .ESCAPE case 0x0E: return .BACKSPACE // Says "Keyboard Delete" on microsoft.com but it's actually backspace case 0x0F: return .TAB @@ -534,7 +576,7 @@ scan1_scancode_to_zephr_scancode_map :: proc(scancode: u8, is_extended: bool) -> case 0x29: return .GRAVE case 0x33: return .COMMA case 0x34: return .PERIOD - case 0x35: return .SLASH + case 0x35: return .KP_DIVIDE if is_extended else .SLASH case 0x3A: return .CAPS_LOCK @@ -551,97 +593,95 @@ scan1_scancode_to_zephr_scancode_map :: proc(scancode: u8, is_extended: bool) -> case 0x57: return .F11 case 0x58: return .F12 - case 0x54: return .PRINT_SCREEN - //case 0xE037 = .PRINT_SCREEN, // SysRq ??? - case 0x46: return .SCROLL_LOCK - case 0x45: return .PAUSE - //case 0xE046 = .PAUSE, // Break ?? + case 0x54: return .PRINT_SCREEN // Only emitted on KeyRelease + case 0x46: return .PAUSE if is_extended else .SCROLL_LOCK + case 0x45: return .NUM_LOCK_OR_CLEAR if is_extended else .PAUSE //case 0xE11D45 = .PAUSE, // Some legacy stuff ??? - case 0x52: - // INSERT - // KP_0 - case 0x47: - // HOME - // KP_7 - case 0x49: - // PAGE_UP - // KP_9 - case 0x53: - // DELETE - // KP_PERIOD - case 0x4F: - // END - // KP_1 - case 0x51: - // PAGE_DOWN - // KP_3 - case 0x4D: - // RIGHT - // KP_6 - case 0x4B: - // LEFT - // KP_4 - case 0x50: - // DOWN - // KP_2 - case 0xE048: - // UP - // KP_8 + case 0x52: return .INSERT if is_extended else .KP_0 + case 0x47: return .HOME if is_extended else .KP_7 + case 0x49: return .PAGE_UP if is_extended else .KP_9 + case 0x53: return .DELETE if is_extended else .KP_PERIOD + case 0x4F: return .END if is_extended else .KP_1 + case 0x51: return .PAGE_DOWN if is_extended else .KP_3 + case 0x4D: return .RIGHT if is_extended else .KP_6 + case 0x4B: return .LEFT if is_extended else .KP_4 + case 0x50: return .DOWN if is_extended else .KP_2 + case 0x48: return .UP if is_extended else .KP_8 + case 0x37: return .PRINT_SCREEN if is_extended else .KP_MULTIPLY + case 0x4A: return .KP_MINUS + case 0x4E: return .KP_PLUS + case 0x4C: return .KP_5 + + case 0x56: return .NON_US_BACKSLASH + case 0x5D: + if is_extended { + return .APPLICATION + } else { + log.warnf("Pressed unmapped key: %d. Extended key: %s", scancode, is_extended) + } + case 0x5E: + if is_extended { + return .POWER + } else { + log.warnf("Pressed unmapped key: %d. Extended key: %s", scancode, is_extended) + } + case 0x59: return .KP_EQUALS + case 0x64: return .F13 + case 0x65: return .F14 + case 0x66: return .F15 + case 0x67: return .F16 + case 0x68: return .F17 + case 0x69: return .F18 + case 0x6A: return .F19 + case 0x6B: return .F20 + case 0x6C: return .F21 + case 0x6D: return .F22 + case 0x6E: return .F23 + case 0x76: return .F24 + + case 0x7E: return .KP_COMMA + case 0x73: return .INTERNATIONAL1 + case 0x70: return .INTERNATIONAL2 + case 0x7D: return .INTERNATIONAL3 + case 0x79: return .INTERNATIONAL4 + case 0x7B: return .INTERNATIONAL5 + case 0x5C: return .RIGHT_META if is_extended else .INTERNATIONAL6 + case 0x72: return .LANG1 // Only emitted on Key Release + case 0xF2: return .LANG1 // Legacy, Only emitted on Key Release + case 0x71: return .LANG2 // Only emitted on Key Release + case 0xF1: return .LANG2 // Legacy, Only emitted on Key Release + case 0x78: return .LANG3 + case 0x77: return .LANG4 + //case 0x76: return .LANG5 // Conflicts with F24 + + case 0x1D: return .RIGHT_CTRL if is_extended else .LEFT_CTRL + case 0x2A: return .LEFT_SHIFT + case 0x36: return .RIGHT_SHIFT + case 0x38: return .RIGHT_ALT if is_extended else .LEFT_ALT + case 0x5B: + if is_extended { + return .LEFT_META + } else { + log.warnf("Pressed unmapped key: %d. Extended key: %s", scancode, is_extended) + } + // End of Keyboard/Keypad section on microsoft.com + // We currently don't map or care about the Consumer section } + return .NULL +} + +backend_set_cursor :: proc() { + win32.SetCursor(zephr_ctx.cursors[zephr_ctx.cursor]) +} - - - //0x45 = .NUM_LOCK_OR_CLEAR, // conflicts with Pause, Pause doesn't have the extended bit set. don't know about this - //0xE045 = .NUM_LOCK_OR_CLEAR, // Legacy stuff - 0xE035 = .KP_DIVIDE, - 0x37 = .KP_MULTIPLY, - 0x4A = .KP_MINUS, - 0x4E = .KP_PLUS, - 0xE01C = .KP_ENTER, - 0x4C = .KP_5, - - 0x56 = .NON_US_BACKSLASH, - 0xE05D = .APPLICATION, - 0xE05E = .POWER, - 0x59 = .KP_EQUALS, - 0x64 = .F13, - 0x65 = .F14, - 0x66 = .F15, - 0x67 = .F16, - 0x68 = .F17, - 0x69 = .F18, - 0x6A = .F19, - 0x6B = .F20, - 0x6C = .F21, - 0x6D = .F22, - 0x6E = .F23, - 0x76 = .F24, - - 0x7E = .KP_COMMA, - 0x73 = .INTERNATIONAL1, - 0x70 = .INTERNATIONAL2, - 0x7D = .INTERNATIONAL3, - 0x79 = .INTERNATIONAL4, - 0x7B = .INTERNATIONAL5, - 0x5C = .INTERNATIONAL6, - 0x72 = .LANG1, // Only emitted on Key Release - 0xF2 = .LANG1, // Legacy, Only emitted on Key Release - 0x71 = .LANG2, // Only emitted on Key Release - 0xF1 = .LANG2, // Legacy, Only emitted on Key Release - 0x78 = .LANG3, - 0x77 = .LANG4, - //0x76 = .LANG5, // Conflicts with F24 - - 0x1D = .LEFT_CTRL, - 0x2A = .LEFT_SHIFT, - 0x38 = .LEFT_ALT, - 0xE05B = .LEFT_META, - 0xE01D = .RIGHT_CTRL, - 0x36 = .RIGHT_SHIFT, - 0xE038 = .RIGHT_ALT, - 0xE05C = .RIGHT_META, - // End of Keyboard/Keypad section on microsoft.com - // We currently don't map or care about the Consumer section +backend_init_cursors :: proc() { + zephr_ctx.cursors[.ARROW] = auto_cast win32.LoadImageW(nil, auto_cast win32._IDC_ARROW, win32.IMAGE_CURSOR, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_SHARED) + zephr_ctx.cursors[.IBEAM] = auto_cast win32.LoadImageW(nil, auto_cast win32._IDC_IBEAM, win32.IMAGE_CURSOR, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_SHARED) + zephr_ctx.cursors[.CROSSHAIR] = auto_cast win32.LoadImageW(nil, auto_cast win32._IDC_CROSS, win32.IMAGE_CURSOR, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_SHARED) + zephr_ctx.cursors[.HAND] = auto_cast win32.LoadImageW(nil, auto_cast win32._IDC_HAND, win32.IMAGE_CURSOR, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_SHARED) + zephr_ctx.cursors[.HRESIZE] = auto_cast win32.LoadImageW(nil, auto_cast win32._IDC_SIZEWE, win32.IMAGE_CURSOR, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_SHARED) + zephr_ctx.cursors[.VRESIZE] = auto_cast win32.LoadImageW(nil, auto_cast win32._IDC_SIZENS, win32.IMAGE_CURSOR, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_SHARED) + zephr_ctx.cursors[.DISABLED] = auto_cast win32.LoadImageW(nil, auto_cast win32._IDC_NO, win32.IMAGE_CURSOR, 0, 0, win32.LR_DEFAULTSIZE | win32.LR_SHARED) } \ No newline at end of file diff --git a/zephr/zephr.odin b/zephr/zephr.odin index 8acb856..f16f7ba 100644 --- a/zephr/zephr.odin +++ b/zephr/zephr.odin @@ -356,7 +356,7 @@ Context :: struct { keyboard: Keyboard, cursor: Cursor, event_queue: queue.Queue(OsEvent), - //cursors: [Cursor]x11.Cursor, + cursors: [Cursor]OsCursor, ui: Ui, /* ZephrKeyboard keyboard; */ @@ -666,15 +666,7 @@ init :: proc(font_path: cstring, icon_path: cstring, window_title: cstring, wind zephr_ctx.window.non_resizable = window_non_resizable zephr_ctx.projection = orthographic_projection_2d(0, window_size.x, window_size.y, 0) - // zephr_ctx.cursors[.ARROW] = x11.XCreateFontCursor(x11_display, .XC_left_ptr) - // zephr_ctx.cursors[.IBEAM] = x11.XCreateFontCursor(x11_display, .XC_xterm) - // zephr_ctx.cursors[.CROSSHAIR] = x11.XCreateFontCursor(x11_display, .XC_crosshair) - // zephr_ctx.cursors[.HAND] = x11.XCreateFontCursor(x11_display, .XC_hand1) - // zephr_ctx.cursors[.HRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_h_double_arrow) - // zephr_ctx.cursors[.VRESIZE] = x11.XCreateFontCursor(x11_display, .XC_sb_v_double_arrow) - - // non-standard cursors - // zephr_ctx.cursors[.DISABLED] = xcursor.LibraryLoadCursor(x11_display, "crossed_circle") + backend_init_cursors() zephr_ctx.screen_size = backend_get_screen_size() start_internal_timer() @@ -727,150 +719,13 @@ swap_buffers :: proc() { } backend_swapbuffers() - //x11.XDefineCursor(x11_display, x11_window, zephr_ctx.cursors[zephr_ctx.cursor]) + backend_set_cursor() } iter_events :: proc(e_out: ^Event) -> bool { return backend_get_os_events(e_out) } -// iter_events :: proc(e_out: ^Event) -> bool { -// context.logger = logger -// xev: x11.XEvent - -// for (cast(bool)x11.XPending(x11_display)) { -// x11.XNextEvent(x11_display, &xev) - -// if xev.type == .ConfigureNotify { -// xce := xev.xconfigure - -// if (xce.width != cast(i32)zephr_ctx.window.size.x || xce.height != cast(i32)zephr_ctx.window.size.y) { -// zephr_ctx.window.size = Vec2{cast(f32)xce.width, cast(f32)xce.height} -// zephr_ctx.projection = orthographic_projection_2d(0, zephr_ctx.window.size.x, zephr_ctx.window.size.y, 0) -// x11_resize_window() - -// e_out.type = .WINDOW_RESIZED -// e_out.window.width = cast(u32)xce.width -// e_out.window.height = cast(u32)xce.height - -// return true -// } -// } else if xev.type == .DestroyNotify { -// // window destroy event -// e_out.type = .WINDOW_CLOSED - -// return true -// } else if xev.type == .ClientMessage { -// // window close event -// if (cast(x11.Atom)xev.xclient.data.l[0] == zephr_ctx.window_delete_atom) { -// e_out.type = .WINDOW_CLOSED - -// return true -// } -// } else if xev.type == .KeyPress { -// xke := xev.xkey - -// evdev_keycode := xke.keycode - 8 -// scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode] - -// e_out.type = .KEY_PRESSED -// e_out.key.scancode = scancode -// //e_out.key.code = keycode; -// e_out.key.mods = x11_mods_to_zephr_mods(scancode, true) - -// return true -// } else if xev.type == .KeyRelease { -// xke := xev.xkey - -// evdev_keycode := xke.keycode - 8 -// scancode := evdev_scancode_to_zephr_scancode_map[evdev_keycode] - -// e_out.type = .KEY_RELEASED -// e_out.key.scancode = scancode -// //e_out.key.code = keycode; -// e_out.key.mods = x11_mods_to_zephr_mods(scancode, false) - -// return true -// } else if xev.type == .ButtonPress { -// e_out.type = .MOUSE_BUTTON_PRESSED -// e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y} -// zephr_ctx.mouse.pressed = true - -// switch (xev.xbutton.button) { -// case .Button1: -// e_out.mouse.button = .BUTTON_LEFT -// zephr_ctx.mouse.button = .BUTTON_LEFT -// case .Button2: -// e_out.mouse.button = .BUTTON_MIDDLE -// zephr_ctx.mouse.button = .BUTTON_MIDDLE -// case .Button3: -// e_out.mouse.button = .BUTTON_RIGHT -// zephr_ctx.mouse.button = .BUTTON_RIGHT -// case .Button4: -// e_out.type = .MOUSE_SCROLL -// e_out.mouse.scroll_direction = .UP -// case .Button5: -// e_out.type = .MOUSE_SCROLL -// e_out.mouse.scroll_direction = .DOWN -// case cast(x11.MouseButton)8: // Back -// e_out.mouse.button = .BUTTON_BACK -// zephr_ctx.mouse.button = .BUTTON_BACK -// case cast(x11.MouseButton)9: // Forward -// e_out.mouse.button = .BUTTON_FORWARD -// zephr_ctx.mouse.button = .BUTTON_FORWARD -// case: -// log.warnf("Unknown mouse button pressed: %d", xev.xbutton.button) -// } - -// return true -// } else if xev.type == .ButtonRelease { -// e_out.type = .MOUSE_BUTTON_RELEASED -// e_out.mouse.pos = Vec2{cast(f32)xev.xbutton.x, cast(f32)xev.xbutton.y} -// zephr_ctx.mouse.released = true -// zephr_ctx.mouse.pressed = false - -// switch (xev.xbutton.button) { -// case .Button1: -// e_out.mouse.button = .BUTTON_LEFT -// case .Button2: -// e_out.mouse.button = .BUTTON_MIDDLE -// case .Button3: -// e_out.mouse.button = .BUTTON_RIGHT -// case .Button4: -// e_out.type = .MOUSE_SCROLL -// e_out.mouse.scroll_direction = .UP -// case .Button5: -// e_out.type = .MOUSE_SCROLL -// e_out.mouse.scroll_direction = .DOWN -// case cast(x11.MouseButton)8: // Back -// e_out.mouse.button = .BUTTON_BACK -// zephr_ctx.mouse.button = .BUTTON_BACK -// case cast(x11.MouseButton)9: // Forward -// e_out.mouse.button = .BUTTON_FORWARD -// zephr_ctx.mouse.button = .BUTTON_FORWARD -// } - -// return true -// } else if xev.type == .MappingNotify { -// // input device mapping changed -// if (xev.xmapping.request != .MappingKeyboard) { -// break -// } -// x11.XRefreshKeyboardMapping(&xev.xmapping) -// /* x11_keyboard_map_update(); */ -// break -// } else if xev.type == .MotionNotify { -// e_out.type = .MOUSE_MOVED -// e_out.mouse.pos = Vec2{cast(f32)xev.xmotion.x, cast(f32)xev.xmotion.y} -// zephr_ctx.mouse.pos = e_out.mouse.pos - -// return true -// } -// } - -// return false -// } - get_window_size :: proc() -> Vec2 { return zephr_ctx.window.size } @@ -923,4 +778,93 @@ logger_init :: proc() { term_logger := log.create_console_logger(opt = TerminalLoggerOpts) logger = log.create_multi_logger(file_logger, term_logger) +} + +@private +set_zephr_mods :: proc(scancode: Scancode, is_press: bool) -> KeyMod { + mods := zephr_ctx.keyboard.mods + + if (is_press) { + if (scancode == .LEFT_SHIFT) { + mods |= {.LEFT_SHIFT, .SHIFT} + } + if (scancode == .RIGHT_SHIFT) { + mods |= {.RIGHT_SHIFT, .SHIFT} + } + if (scancode == .LEFT_CTRL) { + mods |= {.LEFT_CTRL, .CTRL} + } + if (scancode == .RIGHT_CTRL) { + mods |= {.RIGHT_CTRL, .CTRL} + } + if (scancode == .LEFT_ALT) { + mods |= {.LEFT_ALT, .ALT} + } + if (scancode == .RIGHT_ALT) { + mods |= {.RIGHT_ALT, .ALT} + } + if (scancode == .LEFT_META) { + mods |= {.LEFT_META, .META} + } + if (scancode == .RIGHT_META) { + mods |= {.RIGHT_META, .META} + } + if (scancode == .CAPS_LOCK) { + mods |= {.CAPS_LOCK} + } + if (scancode == .NUM_LOCK_OR_CLEAR) { + mods |= {.NUM_LOCK} + } + } else { + if (scancode == .LEFT_SHIFT) { + mods &= ~{.LEFT_SHIFT} + } + if (scancode == .RIGHT_SHIFT) { + mods &= ~{.RIGHT_SHIFT} + } + if (!(.RIGHT_SHIFT in mods) && !(.LEFT_SHIFT in mods)) { + mods &= ~{.SHIFT} + } + + if (scancode == .LEFT_CTRL) { + mods &= ~{.LEFT_CTRL} + } + if (scancode == .RIGHT_CTRL) { + mods &= ~{.RIGHT_CTRL} + } + if (!(.RIGHT_CTRL in mods) && !(.LEFT_CTRL in mods)) { + mods &= ~{.CTRL} + } + + if (scancode == .LEFT_ALT) { + mods &= ~{.LEFT_ALT} + } + if (scancode == .RIGHT_ALT) { + mods &= ~{.RIGHT_ALT} + } + if (!(.RIGHT_ALT in mods) && !(.LEFT_ALT in mods)) { + mods &= ~{.ALT} + } + + if (scancode == .LEFT_META) { + mods &= ~{.LEFT_META} + } + if (scancode == .RIGHT_META) { + mods &= ~{.RIGHT_META} + } + if (!(.RIGHT_META in mods) && !(.LEFT_META in mods)) { + mods &= ~{.META} + } + + if (scancode == .CAPS_LOCK) { + mods &= ~{.CAPS_LOCK} + } + if (scancode == .NUM_LOCK_OR_CLEAR) { + mods &= ~{.NUM_LOCK} + } + } + + zephr_ctx.keyboard.mods = mods + + return mods } \ No newline at end of file