2023-12-13 06:58:08 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <X11/Xatom.h>
|
2023-12-17 03:52:35 +02:00
|
|
|
#include <X11/cursorfont.h>
|
|
|
|
|
#include <X11/Xutil.h>
|
2023-12-13 06:58:08 +02:00
|
|
|
#include <glad/glx.h>
|
2023-12-17 03:52:35 +02:00
|
|
|
#include <stb_image.h>
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
#include "audio.h"
|
|
|
|
|
#include "core.h"
|
|
|
|
|
#include "timer.h"
|
|
|
|
|
#include "ui.h"
|
|
|
|
|
#include "zephr.h"
|
|
|
|
|
|
|
|
|
|
Display *x11_display;
|
|
|
|
|
Window x11_window;
|
|
|
|
|
Colormap x11_colormap;
|
|
|
|
|
GLXContext glx_context;
|
|
|
|
|
/* XIC x11_xic; */
|
|
|
|
|
|
|
|
|
|
ZephrContext *zephr_ctx = NULL;
|
|
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Common
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////
|
|
|
|
|
|
|
|
|
|
ZephrKeycode zephr_evdev_scancode_to_zephr_scancode_map[] = {
|
|
|
|
|
ZEPHR_KEYCODE_NULL,
|
|
|
|
|
ZEPHR_KEYCODE_ESCAPE,
|
|
|
|
|
ZEPHR_KEYCODE_1,
|
|
|
|
|
ZEPHR_KEYCODE_2,
|
|
|
|
|
ZEPHR_KEYCODE_3,
|
|
|
|
|
ZEPHR_KEYCODE_4,
|
|
|
|
|
ZEPHR_KEYCODE_5,
|
|
|
|
|
ZEPHR_KEYCODE_6,
|
|
|
|
|
ZEPHR_KEYCODE_7,
|
|
|
|
|
ZEPHR_KEYCODE_8,
|
|
|
|
|
ZEPHR_KEYCODE_9,
|
|
|
|
|
ZEPHR_KEYCODE_0,
|
|
|
|
|
ZEPHR_KEYCODE_MINUS,
|
|
|
|
|
ZEPHR_KEYCODE_EQUALS,
|
|
|
|
|
ZEPHR_KEYCODE_BACKSPACE,
|
|
|
|
|
ZEPHR_KEYCODE_TAB,
|
|
|
|
|
ZEPHR_KEYCODE_Q,
|
|
|
|
|
ZEPHR_KEYCODE_W,
|
|
|
|
|
ZEPHR_KEYCODE_E,
|
|
|
|
|
ZEPHR_KEYCODE_R,
|
|
|
|
|
ZEPHR_KEYCODE_T,
|
|
|
|
|
ZEPHR_KEYCODE_Y,
|
|
|
|
|
ZEPHR_KEYCODE_U,
|
|
|
|
|
ZEPHR_KEYCODE_I,
|
|
|
|
|
ZEPHR_KEYCODE_O,
|
|
|
|
|
ZEPHR_KEYCODE_P,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_BRACKET,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_BRACKET,
|
|
|
|
|
ZEPHR_KEYCODE_ENTER,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_CTRL,
|
|
|
|
|
ZEPHR_KEYCODE_A,
|
|
|
|
|
ZEPHR_KEYCODE_S,
|
|
|
|
|
ZEPHR_KEYCODE_D,
|
|
|
|
|
ZEPHR_KEYCODE_F,
|
|
|
|
|
ZEPHR_KEYCODE_G,
|
|
|
|
|
ZEPHR_KEYCODE_H,
|
|
|
|
|
ZEPHR_KEYCODE_J,
|
|
|
|
|
ZEPHR_KEYCODE_K,
|
|
|
|
|
ZEPHR_KEYCODE_L,
|
|
|
|
|
ZEPHR_KEYCODE_SEMICOLON,
|
|
|
|
|
ZEPHR_KEYCODE_APOSTROPHE,
|
|
|
|
|
ZEPHR_KEYCODE_GRAVE,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_SHIFT,
|
|
|
|
|
ZEPHR_KEYCODE_BACKSLASH,
|
|
|
|
|
ZEPHR_KEYCODE_Z,
|
|
|
|
|
ZEPHR_KEYCODE_X,
|
|
|
|
|
ZEPHR_KEYCODE_C,
|
|
|
|
|
ZEPHR_KEYCODE_V,
|
|
|
|
|
ZEPHR_KEYCODE_B,
|
|
|
|
|
ZEPHR_KEYCODE_N,
|
|
|
|
|
ZEPHR_KEYCODE_M,
|
|
|
|
|
ZEPHR_KEYCODE_COMMA,
|
|
|
|
|
ZEPHR_KEYCODE_PERIOD,
|
|
|
|
|
ZEPHR_KEYCODE_SLASH,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_SHIFT,
|
|
|
|
|
ZEPHR_KEYCODE_KP_MULTIPLY,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_ALT,
|
|
|
|
|
ZEPHR_KEYCODE_SPACE,
|
|
|
|
|
ZEPHR_KEYCODE_CAPS_LOCK,
|
|
|
|
|
ZEPHR_KEYCODE_F1,
|
|
|
|
|
ZEPHR_KEYCODE_F2,
|
|
|
|
|
ZEPHR_KEYCODE_F3,
|
|
|
|
|
ZEPHR_KEYCODE_F4,
|
|
|
|
|
ZEPHR_KEYCODE_F5,
|
|
|
|
|
ZEPHR_KEYCODE_F6,
|
|
|
|
|
ZEPHR_KEYCODE_F7,
|
|
|
|
|
ZEPHR_KEYCODE_F8,
|
|
|
|
|
ZEPHR_KEYCODE_F9,
|
|
|
|
|
ZEPHR_KEYCODE_F10,
|
|
|
|
|
ZEPHR_KEYCODE_NUM_LOCK_OR_CLEAR,
|
|
|
|
|
ZEPHR_KEYCODE_SCROLL_LOCK,
|
|
|
|
|
ZEPHR_KEYCODE_KP_7,
|
|
|
|
|
ZEPHR_KEYCODE_KP_8,
|
|
|
|
|
ZEPHR_KEYCODE_KP_9,
|
|
|
|
|
ZEPHR_KEYCODE_KP_MINUS,
|
|
|
|
|
ZEPHR_KEYCODE_KP_4,
|
|
|
|
|
ZEPHR_KEYCODE_KP_5,
|
|
|
|
|
ZEPHR_KEYCODE_KP_6,
|
|
|
|
|
ZEPHR_KEYCODE_KP_PLUS,
|
|
|
|
|
ZEPHR_KEYCODE_KP_1,
|
|
|
|
|
ZEPHR_KEYCODE_KP_2,
|
|
|
|
|
ZEPHR_KEYCODE_KP_3,
|
|
|
|
|
ZEPHR_KEYCODE_KP_0,
|
|
|
|
|
ZEPHR_KEYCODE_KP_PERIOD,
|
|
|
|
|
[85] = ZEPHR_KEYCODE_LANG5, // KEY_ZENKAKUHANKAKU
|
|
|
|
|
ZEPHR_KEYCODE_NON_US_BACKSLASH, // KEY_102ND
|
|
|
|
|
ZEPHR_KEYCODE_F11,
|
|
|
|
|
ZEPHR_KEYCODE_F12,
|
|
|
|
|
ZEPHR_KEYCODE_INTERNATIONAL1, // KEY_RO,
|
|
|
|
|
ZEPHR_KEYCODE_LANG3, // KEY_KATAKANA
|
|
|
|
|
ZEPHR_KEYCODE_LANG4, // KEY_HIRAGANA
|
|
|
|
|
ZEPHR_KEYCODE_INTERNATIONAL4, // KEY_HENKAN
|
|
|
|
|
ZEPHR_KEYCODE_INTERNATIONAL2, // KEY_KATAKANAHIRAGANA
|
|
|
|
|
ZEPHR_KEYCODE_INTERNATIONAL5, // KEY_MUHENKAN
|
|
|
|
|
ZEPHR_KEYCODE_INTERNATIONAL5, // KEY_KPJOCOMMA
|
|
|
|
|
ZEPHR_KEYCODE_KP_ENTER,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_CTRL,
|
|
|
|
|
ZEPHR_KEYCODE_KP_DIVIDE,
|
|
|
|
|
ZEPHR_KEYCODE_SYSREQ,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_ALT,
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_LINEFEED
|
|
|
|
|
ZEPHR_KEYCODE_HOME,
|
|
|
|
|
ZEPHR_KEYCODE_UP,
|
|
|
|
|
ZEPHR_KEYCODE_PAGE_UP,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT,
|
|
|
|
|
ZEPHR_KEYCODE_END,
|
|
|
|
|
ZEPHR_KEYCODE_DOWN,
|
|
|
|
|
ZEPHR_KEYCODE_PAGE_DOWN,
|
|
|
|
|
ZEPHR_KEYCODE_INSERT,
|
|
|
|
|
ZEPHR_KEYCODE_DELETE,
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_MACRO
|
|
|
|
|
ZEPHR_KEYCODE_MUTE,
|
|
|
|
|
ZEPHR_KEYCODE_VOLUME_DOWN,
|
|
|
|
|
ZEPHR_KEYCODE_VOLUME_UP,
|
|
|
|
|
ZEPHR_KEYCODE_POWER,
|
|
|
|
|
ZEPHR_KEYCODE_KP_EQUALS,
|
|
|
|
|
ZEPHR_KEYCODE_KP_PLUS_MINUS,
|
|
|
|
|
ZEPHR_KEYCODE_PAUSE,
|
|
|
|
|
[121] = ZEPHR_KEYCODE_KP_COMMA,
|
|
|
|
|
ZEPHR_KEYCODE_LANG1, // KEY_HANGUEL
|
|
|
|
|
ZEPHR_KEYCODE_LANG2, // KEY_HANJA
|
|
|
|
|
ZEPHR_KEYCODE_INTERNATIONAL3, // KEY_YEN
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_META,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_META,
|
|
|
|
|
ZEPHR_KEYCODE_APPLICATION, // KEY_COMPOSE
|
|
|
|
|
ZEPHR_KEYCODE_STOP,
|
|
|
|
|
ZEPHR_KEYCODE_AGAIN,
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PROPS
|
|
|
|
|
ZEPHR_KEYCODE_UNDO,
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_FRONT
|
|
|
|
|
ZEPHR_KEYCODE_COPY,
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_OPEN
|
|
|
|
|
ZEPHR_KEYCODE_PASTE,
|
|
|
|
|
ZEPHR_KEYCODE_FIND,
|
|
|
|
|
ZEPHR_KEYCODE_CUT,
|
|
|
|
|
ZEPHR_KEYCODE_HELP,
|
|
|
|
|
ZEPHR_KEYCODE_MENU,
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // CALCULATOR
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SETUP
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // SLEEP
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_WAKEUP
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_FILE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SENDFILE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_DELETEFILE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_XFER
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PROG1
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PROG2
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // WWW
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_MSDOS
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_COFFEE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_DIRECTION
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_CYCLEWINDOWS
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // MAIL
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AC_BOOKMARKS
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // COMPUTER
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AC_BACK
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AC_FORWARD
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_CLOSECD
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // EJECT
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_EJECTCLOSECD
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AUDIO_NEXT
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AUDIO_PLAY
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AUDIO_PREV
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AUDIO_STOP
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_RECORD
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AUDIO_REWIND
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PHONE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_ISO
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_CONFIG
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AC_HOME
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AC_REFRESH
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_EXIT
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_MOVE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_EDIT
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SCROLLUP
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SCROLLDOWN
|
|
|
|
|
ZEPHR_KEYCODE_KP_LEFT_PAREN,
|
|
|
|
|
ZEPHR_KEYCODE_KP_RIGHT_PAREN,
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_NEW
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_REDO
|
|
|
|
|
ZEPHR_KEYCODE_F13,
|
|
|
|
|
ZEPHR_KEYCODE_F14,
|
|
|
|
|
ZEPHR_KEYCODE_F15,
|
|
|
|
|
ZEPHR_KEYCODE_F16,
|
|
|
|
|
ZEPHR_KEYCODE_F17,
|
|
|
|
|
ZEPHR_KEYCODE_F18,
|
|
|
|
|
ZEPHR_KEYCODE_F19,
|
|
|
|
|
ZEPHR_KEYCODE_F20,
|
|
|
|
|
ZEPHR_KEYCODE_F21,
|
|
|
|
|
ZEPHR_KEYCODE_F22,
|
|
|
|
|
ZEPHR_KEYCODE_F23,
|
|
|
|
|
ZEPHR_KEYCODE_F24,
|
|
|
|
|
[200] = ZEPHR_KEYCODE_NULL, // KEY_PLAYCD
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PAUSECD
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PROG3
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PROG4
|
|
|
|
|
[205] = ZEPHR_KEYCODE_NULL, // KEY_SUSPEND
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_CLOSE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PLAY
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AUDIO_FASTFORWARD
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_BASSBOOST
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_PRINT
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_HP
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_CAMERA
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SOUND
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_QUESTION
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_EMAIL
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_CHAT
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // AC_SEARCH
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_CONNECT
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_FINANCE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SPORT
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SHOP
|
|
|
|
|
ZEPHR_KEYCODE_ALT_ERASE,
|
|
|
|
|
ZEPHR_KEYCODE_CANCEL,
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // BRIGHTNESS_DOWN
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // BRIGHNESS_UP
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_MEDIA
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // DISPLAY_SWITCH
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KBD_ILLUM_TOGGLE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KBD_ILLUM_DOWN
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KBD_ILLUM_UP
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SEND
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_REPLY
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_FORWARDEMAIL
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_SAVE
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_DOCUMENTS
|
|
|
|
|
ZEPHR_KEYCODE_NULL, // KEY_BATTERY
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ZephrKeycode zephr_x11_fn_keysym_to_zephr_keycode_map[] = {
|
|
|
|
|
[0x08] = ZEPHR_KEYCODE_BACKSPACE,
|
|
|
|
|
ZEPHR_KEYCODE_TAB,
|
|
|
|
|
|
|
|
|
|
[0x0b] = ZEPHR_KEYCODE_CLEAR,
|
|
|
|
|
[0x0d] = ZEPHR_KEYCODE_ENTER,
|
|
|
|
|
[0x13] = ZEPHR_KEYCODE_PAUSE,
|
|
|
|
|
ZEPHR_KEYCODE_SCROLL_LOCK,
|
|
|
|
|
ZEPHR_KEYCODE_SYSREQ,
|
|
|
|
|
[0x1b] = ZEPHR_KEYCODE_ESCAPE,
|
|
|
|
|
|
|
|
|
|
[0x50] = ZEPHR_KEYCODE_HOME,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT,
|
|
|
|
|
ZEPHR_KEYCODE_UP,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT,
|
|
|
|
|
ZEPHR_KEYCODE_DOWN,
|
|
|
|
|
ZEPHR_KEYCODE_PAGE_UP,
|
|
|
|
|
ZEPHR_KEYCODE_PAGE_DOWN,
|
|
|
|
|
ZEPHR_KEYCODE_END,
|
|
|
|
|
|
|
|
|
|
[0x60] = ZEPHR_KEYCODE_SELECT,
|
|
|
|
|
ZEPHR_KEYCODE_PRINT_SCREEN,
|
|
|
|
|
ZEPHR_KEYCODE_EXECUTE,
|
|
|
|
|
ZEPHR_KEYCODE_INSERT,
|
|
|
|
|
|
|
|
|
|
[0x65] = ZEPHR_KEYCODE_UNDO,
|
|
|
|
|
[0x67] = ZEPHR_KEYCODE_MENU,
|
|
|
|
|
ZEPHR_KEYCODE_FIND,
|
|
|
|
|
ZEPHR_KEYCODE_CANCEL,
|
|
|
|
|
ZEPHR_KEYCODE_HELP,
|
|
|
|
|
|
|
|
|
|
[0x7f] = ZEPHR_KEYCODE_NUM_LOCK_OR_CLEAR,
|
|
|
|
|
[0x80] = ZEPHR_KEYCODE_KP_SPACE,
|
|
|
|
|
[0x89] = ZEPHR_KEYCODE_KP_TAB,
|
|
|
|
|
[0x8d] = ZEPHR_KEYCODE_KP_ENTER,
|
|
|
|
|
[0xbd] = ZEPHR_KEYCODE_KP_EQUALS,
|
|
|
|
|
|
|
|
|
|
[0xaa] = ZEPHR_KEYCODE_KP_MULTIPLY,
|
|
|
|
|
ZEPHR_KEYCODE_KP_PLUS,
|
|
|
|
|
|
|
|
|
|
[0xad] = ZEPHR_KEYCODE_KP_MINUS,
|
|
|
|
|
ZEPHR_KEYCODE_KP_DECIMAL,
|
|
|
|
|
ZEPHR_KEYCODE_KP_DIVIDE,
|
|
|
|
|
|
|
|
|
|
[0xb0] = ZEPHR_KEYCODE_KP_0,
|
|
|
|
|
ZEPHR_KEYCODE_KP_1,
|
|
|
|
|
ZEPHR_KEYCODE_KP_2,
|
|
|
|
|
ZEPHR_KEYCODE_KP_3,
|
|
|
|
|
ZEPHR_KEYCODE_KP_4,
|
|
|
|
|
ZEPHR_KEYCODE_KP_5,
|
|
|
|
|
ZEPHR_KEYCODE_KP_6,
|
|
|
|
|
ZEPHR_KEYCODE_KP_7,
|
|
|
|
|
ZEPHR_KEYCODE_KP_8,
|
|
|
|
|
ZEPHR_KEYCODE_KP_9,
|
|
|
|
|
|
|
|
|
|
[0xbe] = ZEPHR_KEYCODE_F1,
|
|
|
|
|
ZEPHR_KEYCODE_F2,
|
|
|
|
|
ZEPHR_KEYCODE_F3,
|
|
|
|
|
ZEPHR_KEYCODE_F4,
|
|
|
|
|
ZEPHR_KEYCODE_F5,
|
|
|
|
|
ZEPHR_KEYCODE_F6,
|
|
|
|
|
ZEPHR_KEYCODE_F7,
|
|
|
|
|
ZEPHR_KEYCODE_F8,
|
|
|
|
|
ZEPHR_KEYCODE_F9,
|
|
|
|
|
ZEPHR_KEYCODE_F10,
|
|
|
|
|
ZEPHR_KEYCODE_F11,
|
|
|
|
|
ZEPHR_KEYCODE_F12,
|
|
|
|
|
ZEPHR_KEYCODE_F13,
|
|
|
|
|
ZEPHR_KEYCODE_F14,
|
|
|
|
|
ZEPHR_KEYCODE_F15,
|
|
|
|
|
ZEPHR_KEYCODE_F16,
|
|
|
|
|
ZEPHR_KEYCODE_F17,
|
|
|
|
|
ZEPHR_KEYCODE_F18,
|
|
|
|
|
ZEPHR_KEYCODE_F19,
|
|
|
|
|
ZEPHR_KEYCODE_F20,
|
|
|
|
|
ZEPHR_KEYCODE_F21,
|
|
|
|
|
ZEPHR_KEYCODE_F22,
|
|
|
|
|
ZEPHR_KEYCODE_F23,
|
|
|
|
|
ZEPHR_KEYCODE_F24,
|
|
|
|
|
|
|
|
|
|
[0xe1] = ZEPHR_KEYCODE_LEFT_SHIFT,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_SHIFT,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_CTRL,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_CTRL,
|
|
|
|
|
ZEPHR_KEYCODE_CAPS_LOCK,
|
|
|
|
|
ZEPHR_KEYCODE_CAPS_LOCK, // TODO: ???
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_META,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_META,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_ALT,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_ALT,
|
|
|
|
|
ZEPHR_KEYCODE_LEFT_META, // TODO: ???
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_META, // TODO: ???
|
|
|
|
|
|
|
|
|
|
[0xff] = ZEPHR_KEYCODE_DELETE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ZephrKeycode zephr_x11_fn_ex_keysym_to_zephr_keycode_map[] = {
|
|
|
|
|
[0x03] = ZEPHR_KEYCODE_RIGHT_ALT,
|
|
|
|
|
[0xff] = ZEPHR_KEYCODE_NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ZephrKeycode zephr_x11_latin1_keysym_to_zephr_keycode_map[] = {
|
|
|
|
|
[0x20] = ZEPHR_KEYCODE_SPACE,
|
|
|
|
|
[0x27] = ZEPHR_KEYCODE_APOSTROPHE,
|
|
|
|
|
[0x2c] = ZEPHR_KEYCODE_COMMA,
|
|
|
|
|
ZEPHR_KEYCODE_MINUS,
|
|
|
|
|
ZEPHR_KEYCODE_PERIOD,
|
|
|
|
|
ZEPHR_KEYCODE_SLASH,
|
|
|
|
|
ZEPHR_KEYCODE_0,
|
|
|
|
|
ZEPHR_KEYCODE_1,
|
|
|
|
|
ZEPHR_KEYCODE_2,
|
|
|
|
|
ZEPHR_KEYCODE_3,
|
|
|
|
|
ZEPHR_KEYCODE_4,
|
|
|
|
|
ZEPHR_KEYCODE_5,
|
|
|
|
|
ZEPHR_KEYCODE_6,
|
|
|
|
|
ZEPHR_KEYCODE_7,
|
|
|
|
|
ZEPHR_KEYCODE_8,
|
|
|
|
|
ZEPHR_KEYCODE_9,
|
|
|
|
|
|
|
|
|
|
[0x3b] = ZEPHR_KEYCODE_SEMICOLON,
|
|
|
|
|
[0x3d] = ZEPHR_KEYCODE_EQUALS,
|
|
|
|
|
|
|
|
|
|
[0x5b] = ZEPHR_KEYCODE_LEFT_BRACKET,
|
|
|
|
|
ZEPHR_KEYCODE_BACKSLASH,
|
|
|
|
|
ZEPHR_KEYCODE_RIGHT_BRACKET,
|
|
|
|
|
[0x60] = ZEPHR_KEYCODE_GRAVE,
|
|
|
|
|
ZEPHR_KEYCODE_A,
|
|
|
|
|
ZEPHR_KEYCODE_B,
|
|
|
|
|
ZEPHR_KEYCODE_C,
|
|
|
|
|
ZEPHR_KEYCODE_D,
|
|
|
|
|
ZEPHR_KEYCODE_E,
|
|
|
|
|
ZEPHR_KEYCODE_F,
|
|
|
|
|
ZEPHR_KEYCODE_G,
|
|
|
|
|
ZEPHR_KEYCODE_H,
|
|
|
|
|
ZEPHR_KEYCODE_I,
|
|
|
|
|
ZEPHR_KEYCODE_J,
|
|
|
|
|
ZEPHR_KEYCODE_K,
|
|
|
|
|
ZEPHR_KEYCODE_L,
|
|
|
|
|
ZEPHR_KEYCODE_M,
|
|
|
|
|
ZEPHR_KEYCODE_N,
|
|
|
|
|
ZEPHR_KEYCODE_O,
|
|
|
|
|
ZEPHR_KEYCODE_P,
|
|
|
|
|
ZEPHR_KEYCODE_Q,
|
|
|
|
|
ZEPHR_KEYCODE_R,
|
|
|
|
|
ZEPHR_KEYCODE_S,
|
|
|
|
|
ZEPHR_KEYCODE_T,
|
|
|
|
|
ZEPHR_KEYCODE_U,
|
|
|
|
|
ZEPHR_KEYCODE_V,
|
|
|
|
|
ZEPHR_KEYCODE_W,
|
|
|
|
|
ZEPHR_KEYCODE_X,
|
|
|
|
|
ZEPHR_KEYCODE_Y,
|
|
|
|
|
ZEPHR_KEYCODE_Z,
|
|
|
|
|
|
|
|
|
|
[0xff] = ZEPHR_KEYCODE_NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// X11
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////
|
|
|
|
|
|
|
|
|
|
ZephrKeycode x11_keysym_to_zephr_keycode_map(KeySym sym) {
|
|
|
|
|
if (sym >= 0xff00 && sym <= 0xffff) {
|
|
|
|
|
return zephr_x11_fn_keysym_to_zephr_keycode_map[sym - 0xff00];
|
|
|
|
|
} else if (sym >= 0xfe00 && sym <= 0xfeff) {
|
|
|
|
|
return zephr_x11_fn_ex_keysym_to_zephr_keycode_map[sym - 0xfe00];
|
|
|
|
|
} else if (sym >= 0x100 && sym <= 0x1ff) {
|
|
|
|
|
return ZEPHR_KEYCODE_NULL;
|
|
|
|
|
/* return zephr_x11_latin2_keysym_to_zephr_keycode_map[sym - 0x100]; */
|
|
|
|
|
} else if (sym <= 0xff) {
|
|
|
|
|
return zephr_x11_latin1_keysym_to_zephr_keycode_map[sym];
|
|
|
|
|
} else {
|
|
|
|
|
return ZEPHR_KEYCODE_NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// update internal keyboard map when the keyboard layout changes during runtime
|
|
|
|
|
/* void x11_keyboard_map_update() { */
|
|
|
|
|
/* // reset the keycodes to map directly to the scancodes */
|
|
|
|
|
/* for (int kc = 0; kc < ZEPHR_KEYCODE_COUNT; kc++) { */
|
|
|
|
|
/* zephr_ctx.keyboard.scancode_to_keycode[kc] = kc; */
|
|
|
|
|
/* zephr_ctx.keyboard.keycode_to_scancode[kc] = kc; */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* XkbStateRec state; */
|
|
|
|
|
/* XkbGetUpdatedMap(x11_display, XkbAllClientInfoMask, zephr_ctx.xkb); */
|
|
|
|
|
|
|
|
|
|
/* unsigned int group = 0; */
|
|
|
|
|
/* if (XkbGetState(x11_display, XkbUseCoreKbd, &state) == Success) { */
|
|
|
|
|
/* group = state.group; */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* int first_keycode = zephr_ctx.xkb->min_key_code; */
|
|
|
|
|
/* int last_keycode = zephr_ctx.xkb->max_key_code; */
|
|
|
|
|
/* // we don't map any more keys in evdev after 236 */
|
|
|
|
|
/* if (last_keycode > 236) { */
|
|
|
|
|
/* last_keycode = 236; */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* // some x11 magic: https://youtu.be/Y7yIwWIaD-Q?t=12993 */
|
|
|
|
|
/* // last_keycode - first_keycode exclusive because the first keycode is a NULL keycode */
|
|
|
|
|
/* // evdev scancodes are 8 less than x11 keycodes */
|
|
|
|
|
/* XkbGetKeySyms(x11_display, first_keycode, last_keycode - first_keycode, zephr_ctx.xkb); */
|
|
|
|
|
/* XkbClientMapRec *client_map = zephr_ctx.xkb->map; */
|
|
|
|
|
/* for (int x11keycode = 8; x11keycode < last_keycode; x11keycode++) { */
|
|
|
|
|
/* XkbSymMapRec *sym_map = &client_map->key_sym_map[x11keycode]; */
|
|
|
|
|
/* int sym_start_idx = sym_map->offset; */
|
|
|
|
|
/* // since we do not want any key modifiers, our shift is 0 */
|
|
|
|
|
/* int shift = 0; */
|
|
|
|
|
/* int sym_idx = sym_start_idx + (sym_map->width * group) + shift; */
|
|
|
|
|
/* KeySym sym = client_map->syms[sym_idx]; */
|
|
|
|
|
|
|
|
|
|
/* ZephrScancode scancode = zephr_evdev_scancode_to_zephr_scancode_map[x11keycode]; */
|
|
|
|
|
/* ZephrKeycode keycode = x11_keysym_to_zephr_keycode_map(sym); */
|
|
|
|
|
|
|
|
|
|
/* zephr_ctx.keyboard.scancode_to_keycode[scancode] = keycode; */
|
|
|
|
|
/* zephr_ctx.keyboard.keycode_to_scancode[keycode] = scancode; */
|
|
|
|
|
/* } */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
void x11_resize_window(void) {
|
|
|
|
|
XWindowAttributes win_attrs;
|
|
|
|
|
XGetWindowAttributes(x11_display, x11_window, &win_attrs);
|
|
|
|
|
glViewport(0, 0, win_attrs.width, win_attrs.height);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
// BUG: fullscreen doesn't work on gnome. may or may not be related to the window being
|
|
|
|
|
// opened as a dialog window
|
2023-12-13 06:58:08 +02:00
|
|
|
void x11_go_fullscreen(void) {
|
|
|
|
|
XEvent xev;
|
|
|
|
|
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
|
|
|
|
|
Atom fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
|
|
|
|
|
memset(&xev, 0, sizeof(xev));
|
|
|
|
|
xev.type = ClientMessage;
|
|
|
|
|
xev.xclient.window = x11_window;
|
|
|
|
|
xev.xclient.message_type = wm_state;
|
|
|
|
|
xev.xclient.format = 32;
|
|
|
|
|
xev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD
|
|
|
|
|
xev.xclient.data.l[1] = fullscreen;
|
|
|
|
|
xev.xclient.data.l[2] = 0;
|
|
|
|
|
XSendEvent(x11_display, DefaultRootWindow(x11_display), False,
|
|
|
|
|
SubstructureNotifyMask | SubstructureRedirectMask, &xev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_return_fullscreen(void) {
|
|
|
|
|
XEvent xev;
|
|
|
|
|
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
|
|
|
|
|
Atom fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
|
|
|
|
|
memset(&xev, 0, sizeof(xev));
|
|
|
|
|
xev.type = ClientMessage;
|
|
|
|
|
xev.xclient.window = x11_window;
|
|
|
|
|
xev.xclient.message_type = wm_state;
|
|
|
|
|
xev.xclient.format = 32;
|
|
|
|
|
xev.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE
|
|
|
|
|
xev.xclient.data.l[1] = fullscreen;
|
|
|
|
|
xev.xclient.data.l[2] = 0;
|
|
|
|
|
XSendEvent(x11_display, DefaultRootWindow(x11_display), False,
|
|
|
|
|
SubstructureNotifyMask | SubstructureRedirectMask, &xev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_toggle_fullscreen(bool fullscreen) {
|
|
|
|
|
if (fullscreen) {
|
|
|
|
|
x11_return_fullscreen();
|
|
|
|
|
} else {
|
|
|
|
|
x11_go_fullscreen();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-27 22:42:35 +02:00
|
|
|
// TODO: currently the icon shows on gnome's sidebar correctly but not in gnome-system-monitor.
|
|
|
|
|
// investigate.
|
2023-12-17 03:52:35 +02:00
|
|
|
void x11_assign_window_icon(const char *icon_path) {
|
|
|
|
|
int icon_width, icon_height;
|
|
|
|
|
unsigned char *icon_data = stbi_load(icon_path, &icon_width, &icon_height, NULL, STBI_rgb_alpha);
|
|
|
|
|
CORE_ASSERT(icon_data, "Failed to load icon image\n");
|
|
|
|
|
|
|
|
|
|
u32 target_size = 2 + icon_width * icon_height;
|
|
|
|
|
|
|
|
|
|
u64 *data = malloc(target_size * sizeof(u64));
|
|
|
|
|
u64 *target = data;
|
|
|
|
|
|
|
|
|
|
// first two elements are width and height
|
|
|
|
|
*target++ = icon_width;
|
|
|
|
|
*target++ = icon_height;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < icon_width * icon_height; i++) {
|
|
|
|
|
*target++ = (icon_data[i * 4] << 16) | (icon_data[i * 4 + 1] << 8) | (icon_data[i * 4 + 2] << 0) | (icon_data[i * 4 + 3] << 24);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
|
|
|
|
|
|
|
|
|
|
XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)data, target_size);
|
|
|
|
|
|
|
|
|
|
free(data);
|
|
|
|
|
stbi_image_free(icon_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int x11_create_window(const char* title, int window_width, int window_height, const char *icon_path) {
|
2023-12-13 06:58:08 +02:00
|
|
|
x11_display = XOpenDisplay(NULL);
|
|
|
|
|
CORE_ASSERT(x11_display, "Cannot open x11 display connection\n");
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
int screen_num = DefaultScreen(x11_display);
|
|
|
|
|
Window root = RootWindow(x11_display, screen_num);
|
|
|
|
|
Visual *visual = DefaultVisual(x11_display, screen_num);
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
x11_colormap = XCreateColormap(x11_display, root, visual, AllocNone);
|
|
|
|
|
|
|
|
|
|
XSetWindowAttributes attributes;
|
|
|
|
|
attributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
|
2023-12-17 03:52:35 +02:00
|
|
|
StructureNotifyMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
|
2023-12-13 06:58:08 +02:00
|
|
|
attributes.colormap = x11_colormap;
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
Screen *screen = DefaultScreenOfDisplay(x11_display);
|
|
|
|
|
|
|
|
|
|
int window_start_x = screen->width / 2 - window_width / 2;
|
|
|
|
|
int window_start_y = screen->height / 2 - window_height / 2;
|
|
|
|
|
|
|
|
|
|
x11_window = XCreateWindow(x11_display, root, window_start_x, window_start_y, window_width, window_height, 0,
|
|
|
|
|
DefaultDepth(x11_display, screen_num), InputOutput, visual,
|
2023-12-13 06:58:08 +02:00
|
|
|
CWColormap | CWEventMask, &attributes);
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
if (icon_path) {
|
|
|
|
|
x11_assign_window_icon(icon_path);
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-13 06:58:08 +02:00
|
|
|
// Hints to the WM that the window is a dialog window which makes it a floating
|
|
|
|
|
// window in tiling WMs (only tested on DWM though)
|
|
|
|
|
// Of course this is only a hint and the WM can ignore it
|
|
|
|
|
Atom net_wm_window_type = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False);
|
|
|
|
|
Atom net_wm_window_type_dialog = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
|
|
|
|
XChangeProperty(x11_display, x11_window, net_wm_window_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&net_wm_window_type_dialog, 1);
|
|
|
|
|
|
|
|
|
|
Atom wm_delete_window = XInternAtom(x11_display, "WM_DELETE_WINDOW", False);
|
|
|
|
|
XSetWMProtocols(x11_display, x11_window, &wm_delete_window, 1);
|
|
|
|
|
zephr_ctx->window_delete_atom = wm_delete_window;
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
// BUG: window title is broken on gnome's sidebar but works on the window itself.
|
|
|
|
|
// sidebar shows "Unknown"
|
2023-12-13 06:58:08 +02:00
|
|
|
XStoreName(x11_display, x11_window, title);
|
2023-12-17 03:52:35 +02:00
|
|
|
XTextProperty text_property;
|
|
|
|
|
text_property.value = (unsigned char *)title;
|
|
|
|
|
text_property.format = 8;
|
|
|
|
|
text_property.encoding = XA_STRING;
|
|
|
|
|
text_property.nitems = strlen(title);
|
|
|
|
|
XSetWMName(x11_display, x11_window, &text_property);
|
|
|
|
|
|
|
|
|
|
XMapWindow(x11_display, x11_window);
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
CORE_ASSERT(x11_window, "Failed to create window\n");
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
int glx_version = gladLoaderLoadGLX(x11_display, screen_num);
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
if (!glx_version) {
|
|
|
|
|
printf("[FATAL] Failed to load GLX\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("[INFO] Loaded GLX %d.%d\n",
|
|
|
|
|
GLAD_VERSION_MAJOR(glx_version), GLAD_VERSION_MINOR(glx_version));
|
|
|
|
|
|
|
|
|
|
GLint visual_attributes[] = {
|
|
|
|
|
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
|
|
|
|
GLX_DEPTH_SIZE, 24,
|
|
|
|
|
GLX_DOUBLEBUFFER, 1,
|
|
|
|
|
GLX_SAMPLES, 4, // MSAA
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int num_fbc = 0;
|
|
|
|
|
GLXFBConfig *fbc =
|
2023-12-17 03:52:35 +02:00
|
|
|
glXChooseFBConfig(x11_display, screen_num, visual_attributes, &num_fbc);
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
GLint context_attributes[] = {
|
|
|
|
|
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
|
|
|
|
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
|
|
|
|
|
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
glx_context = glXCreateContextAttribsARB(x11_display, fbc[0], NULL, 1,
|
|
|
|
|
context_attributes);
|
|
|
|
|
|
|
|
|
|
if (!glx_context) {
|
|
|
|
|
printf("[FATAL] Failed to create GLX context\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glXMakeCurrent(x11_display, x11_window, glx_context);
|
|
|
|
|
|
|
|
|
|
int gl_version = gladLoaderLoadGL();
|
|
|
|
|
|
|
|
|
|
if (!gl_version) {
|
|
|
|
|
printf("[FATAL] Failed to load GL\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
printf("[INFO] Loaded GL %d.%d\n",
|
|
|
|
|
GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
|
|
|
|
|
|
|
|
|
|
XWindowAttributes win_attrs;
|
|
|
|
|
XGetWindowAttributes(x11_display, x11_window, &win_attrs);
|
|
|
|
|
|
|
|
|
|
glad_glXSwapIntervalEXT(x11_display, x11_window, 1);
|
|
|
|
|
// we enable blending for text
|
|
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
glEnable(GL_MULTISAMPLE);
|
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
glViewport(0, 0, win_attrs.width, win_attrs.height);
|
|
|
|
|
x11_resize_window();
|
|
|
|
|
|
|
|
|
|
XFree(fbc);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
int x11_init(const char* title, int window_width, int window_height, const char *icon_path) {
|
|
|
|
|
int res = x11_create_window(title, window_width, window_height, icon_path);
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
/* // loads the XMODIFIERS environment variable to see what IME to use */
|
|
|
|
|
/* XSetLocaleModifiers(""); */
|
|
|
|
|
/* XIM xim = XOpenIM(x11_display, 0, 0, 0); */
|
|
|
|
|
/* if(!xim){ */
|
|
|
|
|
/* // fallback to internal input method */
|
|
|
|
|
/* XSetLocaleModifiers("@im=none"); */
|
|
|
|
|
/* xim = XOpenIM(x11_display, 0, 0, 0); */
|
|
|
|
|
/* } */
|
|
|
|
|
/* zephr_ctx.xim = xim; */
|
|
|
|
|
|
|
|
|
|
/* // XIC */
|
|
|
|
|
/* // create an input context that is used by the whole window */
|
|
|
|
|
/* // you are supposed to have one of these per text field, but this should do */
|
|
|
|
|
/* x11_xic = XCreateIC(zephr_ctx.xim, */
|
|
|
|
|
/* XNInputStyle, XIMPreeditNothing | XIMStatusNothing, */
|
|
|
|
|
/* XNClientWindow, x11_window, XNFocusWindow, x11_window, */
|
|
|
|
|
/* NULL); */
|
|
|
|
|
|
|
|
|
|
/* XSetICFocus(x11_xic); */
|
|
|
|
|
|
|
|
|
|
/* // TODO: do we need to flush?? */
|
|
|
|
|
/* XFlush(x11_display); */
|
|
|
|
|
|
|
|
|
|
// XKB
|
|
|
|
|
/* { */
|
|
|
|
|
/* XAutoRepeatOn(x11_display); */
|
|
|
|
|
/* int major = 1, minor = 0; */
|
|
|
|
|
/* CORE_ASSERT(XkbQueryExtension(x11_display, NULL, NULL, NULL, &major, &minor), "XKB not supported"); */
|
|
|
|
|
|
|
|
|
|
/* zephr_ctx.xkb = XkbGetMap(x11_display, XkbAllClientInfoMask, XkbUseCoreKbd); */
|
|
|
|
|
|
|
|
|
|
/* int repeat = 0; */
|
|
|
|
|
/* XkbSetDetectableAutoRepeat(x11_display, True, &repeat); */
|
|
|
|
|
|
|
|
|
|
/* XkbSelectEvents(x11_display, XkbUseCoreKbd, XkbMapNotifyMask, XkbMapNotifyMask); */
|
|
|
|
|
|
|
|
|
|
/* x11_keyboard_map_update(); */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_close(void) {
|
|
|
|
|
glXMakeCurrent(x11_display, 0, 0);
|
|
|
|
|
glXDestroyContext(x11_display, glx_context);
|
|
|
|
|
|
|
|
|
|
XDestroyWindow(x11_display, x11_window);
|
|
|
|
|
XFreeColormap(x11_display, x11_colormap);
|
|
|
|
|
XCloseDisplay(x11_display);
|
|
|
|
|
|
|
|
|
|
gladLoaderUnloadGLX();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_get_screen_size(int *width, int *height) {
|
|
|
|
|
Screen *screen = DefaultScreenOfDisplay(x11_display);
|
|
|
|
|
|
|
|
|
|
*width = screen->width;
|
|
|
|
|
*height = screen->height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void x11_make_window_non_resizable(int width, int height) {
|
|
|
|
|
XSizeHints *size_hints = XAllocSizeHints();
|
|
|
|
|
size_hints->flags = PMinSize | PMaxSize;
|
|
|
|
|
size_hints->min_width = width;
|
|
|
|
|
size_hints->min_height = height;
|
|
|
|
|
size_hints->max_width = width;
|
|
|
|
|
size_hints->max_height = height;
|
|
|
|
|
XSetWMNormalHints(x11_display, x11_window, size_hints);
|
|
|
|
|
XFree(size_hints);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Zephr
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////
|
|
|
|
|
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
void zephr_init(const char* font_path, const char* icon_path, const char* window_title, Size window_size) {
|
2023-12-27 22:42:35 +02:00
|
|
|
zephr_ctx = calloc(1, sizeof(ZephrContext));
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
// TODO: should I initalize the audio here or let the game handle that??
|
|
|
|
|
int res = audio_init();
|
|
|
|
|
CORE_ASSERT(res == 0, "Failed to initialize audio");
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
res = x11_init(window_title, window_size.width, window_size.height, icon_path);
|
2023-12-13 06:58:08 +02:00
|
|
|
CORE_ASSERT(res == 0, "Failed to initialize X11");
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
res = init_ui(font_path);
|
2023-12-13 06:58:08 +02:00
|
|
|
CORE_ASSERT(res == 0, "Failed to initialize UI");
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
zephr_ctx->window.size = window_size;
|
|
|
|
|
zephr_ctx->projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f);
|
|
|
|
|
zephr_ctx->cursors[ZEPHR_CURSOR_ARROW] = XCreateFontCursor(x11_display, XC_left_ptr);
|
|
|
|
|
zephr_ctx->cursors[ZEPHR_CURSOR_IBEAM] = XCreateFontCursor(x11_display, XC_xterm);
|
|
|
|
|
zephr_ctx->cursors[ZEPHR_CURSOR_CROSSHAIR] = XCreateFontCursor(x11_display, XC_crosshair);
|
|
|
|
|
zephr_ctx->cursors[ZEPHR_CURSOR_HAND] = XCreateFontCursor(x11_display, XC_hand1);
|
|
|
|
|
zephr_ctx->cursors[ZEPHR_CURSOR_HRESIZE] = XCreateFontCursor(x11_display, XC_sb_h_double_arrow);
|
|
|
|
|
zephr_ctx->cursors[ZEPHR_CURSOR_VRESIZE] = XCreateFontCursor(x11_display, XC_sb_v_double_arrow);
|
|
|
|
|
|
2023-12-13 06:58:08 +02:00
|
|
|
x11_get_screen_size(&zephr_ctx->screen_size.width, &zephr_ctx->screen_size.height);
|
|
|
|
|
start_internal_timer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void zephr_deinit(void) {
|
|
|
|
|
x11_close();
|
|
|
|
|
audio_close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool zephr_should_quit(void) {
|
|
|
|
|
CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized");
|
|
|
|
|
|
|
|
|
|
glClearColor(0, 0, 0, 1);
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
|
2023-12-27 22:42:35 +02:00
|
|
|
zephr_ctx->cursor = ZEPHR_CURSOR_ARROW;
|
|
|
|
|
zephr_ctx->mouse.released = false;
|
|
|
|
|
|
2023-12-13 06:58:08 +02:00
|
|
|
audio_update();
|
|
|
|
|
|
|
|
|
|
return zephr_ctx->should_quit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This MUST be called at the end of the frame
|
|
|
|
|
void zephr_swap_buffers(void) {
|
|
|
|
|
CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized");
|
|
|
|
|
|
|
|
|
|
glXSwapBuffers(x11_display, x11_window);
|
2023-12-27 22:42:35 +02:00
|
|
|
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[zephr_ctx->cursor]);
|
2023-12-13 06:58:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Size zephr_get_window_size(void) {
|
|
|
|
|
return zephr_ctx->window.size;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
// This MUST be called after calling zephr_init()
|
2023-12-13 06:58:08 +02:00
|
|
|
void zephr_make_window_non_resizable(void) {
|
|
|
|
|
CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized");
|
|
|
|
|
|
|
|
|
|
x11_make_window_non_resizable(zephr_ctx->window.size.width, zephr_ctx->window.size.height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void zephr_toggle_fullscreen(void) {
|
|
|
|
|
x11_toggle_fullscreen(zephr_ctx->window.is_fullscreen);
|
|
|
|
|
|
|
|
|
|
zephr_ctx->window.is_fullscreen = !zephr_ctx->window.is_fullscreen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void zephr_quit(void) {
|
|
|
|
|
zephr_ctx->should_quit = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Color ColorRGBA(u8 r, u8 g, u8 b, u8 a) {
|
|
|
|
|
return (Color){ r, g, b, a };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ZephrKeyMod zephr_x11_mods_to_zephr_mods(XKeyEvent xkey) {
|
|
|
|
|
ZephrKeyMod zephr_mods = 0;
|
|
|
|
|
|
|
|
|
|
if (xkey.state & ShiftMask) {
|
|
|
|
|
if (XLookupKeysym(&xkey, 0) == XK_Shift_L) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_LEFT_SHIFT;
|
|
|
|
|
} else if (XLookupKeysym(&xkey, 0) == XK_Shift_R) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_RIGHT_SHIFT;
|
|
|
|
|
} else {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_SHIFT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (xkey.state & ControlMask){
|
|
|
|
|
if (XLookupKeysym(&xkey, 0) == XK_Control_L) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_LEFT_CTRL;
|
|
|
|
|
} else if (XLookupKeysym(&xkey, 0) == XK_Control_R) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_RIGHT_CTRL;
|
|
|
|
|
} else {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_CTRL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (xkey.state & Mod1Mask) {
|
|
|
|
|
if (XLookupKeysym(&xkey, 0) == XK_Alt_L) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_LEFT_ALT;
|
|
|
|
|
} else if (XLookupKeysym(&xkey, 0) == XK_Alt_R) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_RIGHT_ALT;
|
|
|
|
|
} else {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_ALT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (xkey.state & Mod4Mask) {
|
|
|
|
|
if (XLookupKeysym(&xkey, 0) == XK_Super_L) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_LEFT_META;
|
|
|
|
|
} else if (XLookupKeysym(&xkey, 0) == XK_Super_R) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_RIGHT_META;
|
|
|
|
|
} else {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_META;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (xkey.state & LockMask) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_CAPS_LOCK;
|
|
|
|
|
}
|
|
|
|
|
if (xkey.state & Mod2Mask) {
|
|
|
|
|
zephr_mods |= ZEPHR_KEY_MOD_NUM_LOCK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return zephr_mods;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool zephr_iter_events(ZephrEvent *event_out) {
|
|
|
|
|
XEvent xev;
|
|
|
|
|
|
|
|
|
|
while (XPending(x11_display)) {
|
|
|
|
|
XNextEvent(x11_display, &xev);
|
|
|
|
|
|
|
|
|
|
if (xev.type == ConfigureNotify) {
|
|
|
|
|
XConfigureEvent xce = xev.xconfigure;
|
|
|
|
|
|
|
|
|
|
if (xce.width != zephr_ctx->window.size.width || xce.height != zephr_ctx->window.size.height) {
|
|
|
|
|
zephr_ctx->window.size = (Size){ .width = xce.width, .height = xce.height };
|
|
|
|
|
zephr_ctx->projection = orthographic_projection_2d(0.f, xce.width, xce.height, 0.f);
|
|
|
|
|
x11_resize_window();
|
|
|
|
|
|
|
|
|
|
event_out->type = ZEPHR_EVENT_WINDOW_RESIZED;
|
|
|
|
|
event_out->window.width = xce.width;
|
|
|
|
|
event_out->window.height = xce.height;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else if (xev.type == DestroyNotify) {
|
|
|
|
|
// window destroy event
|
|
|
|
|
event_out->type = ZEPHR_EVENT_WINDOW_CLOSED;
|
|
|
|
|
return true;
|
|
|
|
|
} else if (xev.type == ClientMessage) {
|
|
|
|
|
// window close event
|
|
|
|
|
if ((Atom)xev.xclient.data.l[0] == zephr_ctx->window_delete_atom) {
|
|
|
|
|
event_out->type = ZEPHR_EVENT_WINDOW_CLOSED;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
} else if (xev.type == KeyPress) {
|
|
|
|
|
XKeyEvent xke = xev.xkey;
|
|
|
|
|
|
|
|
|
|
u32 evdev_keycode = xke.keycode - 8;
|
|
|
|
|
ZephrScancode scancode = zephr_evdev_scancode_to_zephr_scancode_map[evdev_keycode];
|
|
|
|
|
|
|
|
|
|
event_out->type = ZEPHR_EVENT_KEY_PRESSED;
|
|
|
|
|
event_out->key.code = scancode;
|
|
|
|
|
event_out->key.mods = zephr_x11_mods_to_zephr_mods(xke);
|
|
|
|
|
|
|
|
|
|
/* { */
|
|
|
|
|
/* // remove the control modifier as it causes control codes to be returned */
|
|
|
|
|
/* xev.xkey.state &= ~ControlMask; */
|
|
|
|
|
|
|
|
|
|
/* char string[4] = {0}; */
|
|
|
|
|
/* KeySym keysym = 0; */
|
|
|
|
|
/* u8 string_length = Xutf8LookupString(x11_xic, &xev.xkey, string, sizeof(string), &keysym, NULL); */
|
|
|
|
|
|
|
|
|
|
/* // do not send any keys like ctrl, shift, function, arrow, escape, return, backspace. */
|
|
|
|
|
/* // instead, send regular key events. */
|
|
|
|
|
/* if (string_length && !(keysym >= 0xfd00 && keysym <= 0xffff)) { */
|
|
|
|
|
/* os_event_queue_virt_key_input_utf8(string, string_length); */
|
|
|
|
|
/* } */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* // an X11 keycode is conceptually the same as our keycode. */
|
|
|
|
|
/* // they are both used to represent a physical key. */
|
|
|
|
|
/* // map evdev enumeration to our keycode */
|
|
|
|
|
/* u32 evdev_keycode = xev.xkey.keycode - 8; */
|
|
|
|
|
/* ZephrKeycode keycode; */
|
|
|
|
|
/* if (evdev_keycode < CORE_ARRAY_COUNT(os_linux_keyboard_evdev_keycode_to_keycode_map)) { */
|
|
|
|
|
/* keycode = os_linux_keyboard_evdev_keycode_to_keycode_map[evdev_keycode]; */
|
|
|
|
|
/* } else { */
|
|
|
|
|
/* keycode = ZEPHR_KEYCODE_NULL; */
|
|
|
|
|
/* } */
|
|
|
|
|
/* os_event_queue_virt_key_changed(xev.type == KeyPress, keycode); */
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
} else if (xev.type == KeyRelease) {
|
|
|
|
|
XKeyEvent xke = xev.xkey;
|
|
|
|
|
|
|
|
|
|
unsigned int evdev_keycode = xke.keycode - 8;
|
|
|
|
|
ZephrScancode scancode = zephr_evdev_scancode_to_zephr_scancode_map[evdev_keycode];
|
|
|
|
|
|
|
|
|
|
event_out->type = ZEPHR_EVENT_KEY_RELEASED;
|
|
|
|
|
event_out->key.code = scancode;
|
|
|
|
|
event_out->key.mods = zephr_x11_mods_to_zephr_mods(xke);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
} else if (xev.type == ButtonPress) {
|
|
|
|
|
event_out->type = ZEPHR_EVENT_MOUSE_BUTTON_PRESSED;
|
|
|
|
|
event_out->mouse.position = (Vec2){ .x = xev.xbutton.x, .y = xev.xbutton.y };
|
2023-12-17 03:52:35 +02:00
|
|
|
zephr_ctx->mouse.pressed = true;
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
switch (xev.xbutton.button) {
|
|
|
|
|
case Button1:
|
|
|
|
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_LEFT;
|
2023-12-17 03:52:35 +02:00
|
|
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_LEFT;
|
2023-12-13 06:58:08 +02:00
|
|
|
break;
|
|
|
|
|
case Button2:
|
|
|
|
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_MIDDLE;
|
2023-12-17 03:52:35 +02:00
|
|
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_MIDDLE;
|
2023-12-13 06:58:08 +02:00
|
|
|
break;
|
|
|
|
|
case Button3:
|
|
|
|
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_RIGHT;
|
2023-12-17 03:52:35 +02:00
|
|
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_RIGHT;
|
2023-12-13 06:58:08 +02:00
|
|
|
break;
|
|
|
|
|
case Button4:
|
|
|
|
|
event_out->type = ZEPHR_EVENT_MOUSE_SCROLL;
|
|
|
|
|
event_out->mouse.scroll_direction = ZEPHR_MOUSE_SCROLL_UP;
|
|
|
|
|
break;
|
|
|
|
|
case Button5:
|
|
|
|
|
event_out->type = ZEPHR_EVENT_MOUSE_SCROLL;
|
|
|
|
|
event_out->mouse.scroll_direction = ZEPHR_MOUSE_SCROLL_DOWN;
|
|
|
|
|
break;
|
|
|
|
|
case 8: // Back
|
|
|
|
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_BACK;
|
2023-12-17 03:52:35 +02:00
|
|
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_BACK;
|
2023-12-13 06:58:08 +02:00
|
|
|
break;
|
|
|
|
|
case 9: // Forward
|
|
|
|
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_FORWARD;
|
2023-12-17 03:52:35 +02:00
|
|
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_FORWARD;
|
2023-12-13 06:58:08 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
printf("[WARN] Unknown mouse button pressed: %d\n", xev.xbutton.button);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
} else if (xev.type == ButtonRelease) {
|
|
|
|
|
event_out->type = ZEPHR_EVENT_MOUSE_BUTTON_RELEASED;
|
|
|
|
|
event_out->mouse.position = (Vec2){ .x = xev.xbutton.x, .y = xev.xbutton.y };
|
2023-12-17 03:52:35 +02:00
|
|
|
zephr_ctx->mouse.released = true;
|
|
|
|
|
zephr_ctx->mouse.pressed = false;
|
2023-12-13 06:58:08 +02:00
|
|
|
|
|
|
|
|
switch (xev.xbutton.button) {
|
|
|
|
|
case Button1:
|
|
|
|
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_LEFT;
|
|
|
|
|
break;
|
|
|
|
|
case Button2:
|
|
|
|
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_MIDDLE;
|
|
|
|
|
break;
|
|
|
|
|
case Button3:
|
|
|
|
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_RIGHT;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
} else if (xev.type == MappingNotify) {
|
|
|
|
|
// input device mapping changed
|
|
|
|
|
if (xev.xmapping.request != MappingKeyboard) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
XRefreshKeyboardMapping(&xev.xmapping);
|
|
|
|
|
/* x11_keyboard_map_update(); */
|
|
|
|
|
break;
|
2023-12-17 03:52:35 +02:00
|
|
|
} else if (xev.type == MotionNotify) {
|
|
|
|
|
event_out->type = ZEPHR_EVENT_MOUSE_MOVED;
|
|
|
|
|
event_out->mouse.position = (Vec2){ .x = xev.xmotion.x, .y = xev.xmotion.y };
|
|
|
|
|
zephr_ctx->mouse.pos = event_out->mouse.position;
|
|
|
|
|
return true;
|
2023-12-13 06:58:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-17 03:52:35 +02:00
|
|
|
void zephr_set_cursor(ZephrCursor cursor) {
|
|
|
|
|
if (zephr_ctx->cursor == cursor) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
zephr_ctx->cursor = cursor;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-13 06:58:08 +02:00
|
|
|
/* bool zephr_keyboard_scancode_is_pressed(ZephrScancode scancode) { */
|
|
|
|
|
/* return core_bitset_is_set(zephr_ctx.keyboard.scancode_is_pressed_bitset, scancode); */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* bool zephr_keyboard_scancode_has_been_pressed(ZephrScancode scancode) { */
|
|
|
|
|
/* return core_bitset_is_set(zephr_ctx.keyboard.scancode_has_been_pressed_bitset, scancode); */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* bool zephr_keyboard_scancode_has_been_released(ZephrScancode scancode) { */
|
|
|
|
|
/* return core_bitset_is_set(zephr_ctx.keyboard.scancode_has_been_released_bitset, scancode); */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* bool zephr_keyboard_keycode_is_pressed(ZephrKeycode keycode) { */
|
|
|
|
|
/* return core_bitset_is_set(zephr_ctx.keyboard.keycode_is_pressed_bitset, keycode); */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* bool zephr_keyboard_keycode_has_been_pressed(ZephrKeycode keycode) { */
|
|
|
|
|
/* return core_bitset_is_set(zephr_ctx.keyboard.keycode_has_been_pressed_bitset, keycode); */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* bool zephr_keyboard_keycode_has_been_released(ZephrKeycode keycode) { */
|
|
|
|
|
/* return core_bitset_is_set(zephr_ctx.keyboard.keycode_has_been_released_bitset, keycode); */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ZephrScancode zephr_keyboard_keycode_to_scancode(ZephrKeycode keycode) { */
|
|
|
|
|
/* return zephr_ctx.keyboard.keycode_to_scancode[keycode]; */
|
|
|
|
|
/* } */
|
|
|
|
|
|
|
|
|
|
/* ZephrKeycode zephr_keyboard_scancode_to_keycode(ZephrScancode scancode) { */
|
|
|
|
|
/* return zephr_ctx.keyboard.scancode_to_keycode[scancode]; */
|
|
|
|
|
/* } */
|