part: add mlx_hook.h functions

This commit is contained in:
Zy 2024-10-13 19:38:36 +02:00
parent a93af5c48f
commit cca1adca0c
8 changed files with 405 additions and 26 deletions

120
include/mlx_events.h Normal file
View file

@ -0,0 +1,120 @@
/**
* mlx_events.h
* for the project "MinilibX for 3DS"
* by Zy
* at https://github.com/frzysk/mlx3ds
*
* The content of this file comes from "X.h".
*/
/**
* This file contains the event and mask values to use with mlx_hook().
* The mask values are here for compatibility, they aren't used for the 3DS.
*/
#ifndef MLX_EVENTS_H
# define MLX_EVENTS_H
// TODO docs mlx_events.h
// TODO add function prototypes.
/// @brief Sent when a key starts to be pressed.
/// Hook prototype: `int keypress_hook(int keycode, void *param);`
# define KeyPress 2
/// @brief Sent when a key ends being pressed.
/// Hook prototype: `int keyrelease_hook(int keycode, void *param);`
# define KeyRelease 3
/// @brief Sent when the window was just created, before all other events.
/// Hook prototype: `int create_hook(void *param);`
# define CreateNotify 16
/// @brief Sent to all the windows when the software is quitting, after all
/// the other events.
/// Hook prototype: `int destroy_hook(void *param);`
# define DestroyNotify 17
# define ButtonPress 4 // Unused, this event will never be sent.
# define ButtonRelease 5 // Unused, this event will never be sent.
# define MotionNotify 6 // Unused, this event will never be sent.
# define EnterNotify 7 // Unused, this event will never be sent.
# define LeaveNotify 8 // Unused, this event will never be sent.
# define FocusIn 9 // Unused, this event will never be sent.
# define FocusOut 10 // Unused, this event will never be sent.
# define KeymapNotify 11 // Unused, this event will never be sent.
# define Expose 12 // Unused, this event will never be sent.
# define GraphicsExpose 13 // Unused, this event will never be sent.
# define NoExpose 14 // Unused, this event will never be sent.
# define VisibilityNotify 15 // Unused, this event will never be sent.
# define UnmapNotify 18 // Unused, this event will never be sent.
# define MapNotify 19 // Unused, this event will never be sent.
# define MapRequest 20 // Unused, this event will never be sent.
# define ReparentNotify 21 // Unused, this event will never be sent.
# define ConfigureNotify 22 // Unused, this event will never be sent.
# define ConfigureRequest 23 // Unused, this event will never be sent.
# define GravityNotify 24 // Unused, this event will never be sent.
# define ResizeRequest 25 // Unused, this event will never be sent.
# define CirculateNotify 26 // Unused, this event will never be sent.
# define CirculateRequest 27 // Unused, this event will never be sent.
# define PropertyNotify 28 // Unused, this event will never be sent.
# define SelectionClear 29 // Unused, this event will never be sent.
# define SelectionRequest 30 // Unused, this event will never be sent.
# define SelectionNotify 31 // Unused, this event will never be sent.
# define ColormapNotify 32 // Unused, this event will never be sent.
# define ClientMessage 33 // Unused, this event will never be sent.
# define MappingNotify 34 // Unused, this event will never be sent.
# define GenericEvent 35 // Unused, this event will never be sent.
# define LASTEvent 36 // A number bigger that all event values.
// Unused, the MinilibX for 3DS doesn't use event masks.
# define NoEventMask 0L
// Unused, the MinilibX for 3DS doesn't use event masks.
# define KeyPressMask (1L<<0)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define KeyReleaseMask (1L<<1)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define ButtonPressMask (1L<<2)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define ButtonReleaseMask (1L<<3)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define EnterWindowMask (1L<<4)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define LeaveWindowMask (1L<<5)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define PointerMotionMask (1L<<6)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define PointerMotionHintMask (1L<<7)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define Button1MotionMask (1L<<8)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define Button2MotionMask (1L<<9)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define Button3MotionMask (1L<<10)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define Button4MotionMask (1L<<11)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define Button5MotionMask (1L<<12)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define ButtonMotionMask (1L<<13)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define KeymapStateMask (1L<<14)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define ExposureMask (1L<<15)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define VisibilityChangeMask (1L<<16)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define StructureNotifyMask (1L<<17)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define ResizeRedirectMask (1L<<18)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define SubstructureNotifyMask (1L<<19)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define SubstructureRedirectMask (1L<<20)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define FocusChangeMask (1L<<21)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define PropertyChangeMask (1L<<22)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define ColormapChangeMask (1L<<23)
// Unused, the MinilibX for 3DS doesn't use event masks.
# define OwnerGrabButtonMask (1L<<24)
#endif

View file

@ -27,6 +27,7 @@
# define MLX_HOOK_H
# include "mlx3ds_typealiases.h"
# include "mlx_events.h"
/// @brief Doesn't do anything, the 3DS doesn't have a mouse.
///
@ -34,10 +35,10 @@
/// @param funct_ptr Unused
/// @param param Unused.
/// @return Unused.
int _mlx_mouse_hook(t_win win_ptr, int (*funct_ptr)(), void *param);
int mlx_mouse_hook(t_win win_ptr, int (*funct_ptr)(), void *param);
/// @brief Assign a function to a key event. When a key is pressed, the function
/// will be called.
/// @brief Assign a function to a key event. When a key is released, the
/// function will be called.
///
/// @param win_ptr Window to affect.
/// @param funct_ptr Function to call when the event occurs. `keycode` is the
@ -47,7 +48,7 @@ int _mlx_mouse_hook(t_win win_ptr, int (*funct_ptr)(), void *param);
/// The return value is unused.
/// @param param Address to pass to the function every time it is called.
/// @return Unused.
int _mlx_key_hook(t_win win_ptr,
int mlx_key_hook(t_win win_ptr,
int (*funct_ptr)(int keycode, void *param), void *param);
/// @brief Assign a function which will be called when the window should be
@ -60,7 +61,7 @@ int _mlx_key_hook(t_win win_ptr,
/// unused.
/// @param param Address to pass to the function every time it is called.
/// @return Unused.
int _mlx_expose_hook(t_win win_ptr,
int mlx_expose_hook(t_win win_ptr,
int (*funct_ptr)(void *param), void *param);
/// @brief Assign a function which will be called in loop non-stop.
@ -71,21 +72,34 @@ int _mlx_expose_hook(t_win win_ptr,
/// unused.
/// @param param Address to pass to the function every time it is called.
/// @return Unused.
int _mlx_loop_hook(t_mlx mlx_ptr,
int mlx_loop_hook(t_mlx mlx_ptr,
int (*funct_ptr)(void *param), void *param);
/// @brief Loop indefinitely and wait for events to occurs to call the
/// corresponding functions.
///
/// @param mlx_ptr mlx connection identifier returned by mlx_init().
/// @return This function never returns.
int _mlx_loop(void *mlx_ptr);
/// @return This function returns only when the program is quitting or if
/// mlx_loop_end() is used. The return value is unused.
int mlx_loop(t_mlx mlx_ptr);
// ???
int _mlx_loop_end(void *mlx_ptr);
/// @brief Stop the loop of mlx_loop. Doesn't do anything if mlx_loop isn't
/// running.
///
/// @param mlx_ptr mlx connection identifier returned by mlx_init().
/// @return Unused.
int mlx_loop_end(t_mlx mlx_ptr);
// god
int _mlx_hook(t_mlx win_ptr, int x_event, int x_mask,
/// @brief Assign a function to a custom event.
///
/// @param win_ptr Window to affect.
/// @param x_event The event to use. "See mlx_events.h".
/// @param x_mask Unused.
/// @param funct Function to call when the event occurs. The prototype depends
/// on the event type, "see mlx_events.h".
/// @param param Address to pass to the function every time it is called.
/// @return Unused.
int mlx_hook(t_mlx win_ptr, int x_event, int x_mask,
int (*funct)(), void *param);
#endif

View file

@ -34,6 +34,4 @@
/// NULL if failed.
t_mlx mlx_init(void); // TODO should call this before REALLY anything else?
// TODO a mlx_end() necessary?
#endif

View file

@ -40,6 +40,47 @@ static void draw_rainbow_image(t_mlx mlx, t_win win, int x, int y)
}
}
static int keydown_hook(int keycode, void *param)
{
(void)param;
cout << "[D" << keycode << "] (B to continue)" << endl;
return (0);
};
static int create_hook(void *param) {
(void)param;
cout << "create_hook() called" << endl;
int file = open("__tmp_heya.txt", O_RDONLY);
if (!file)
cout << "can't open file __tmp_heya.txt" << endl;
else {
static char buf[100];
if (read(file, buf, 100) < 0)
cout << "can't read file" << endl;
else
cout << "buf :\"" << buf << "\"" << endl;
}
close(file);
cout
<< "quit software to create file:" << endl
<< " __tmp_heya.txt" << endl;
return (0);
};
static int destroy_hook(void **ptrs) {
int file = open("__tmp_heya.txt", O_WRONLY | O_CREAT);
if (!file) {
cout << "can't create file" << endl;
return (0);
}
write(file, "spaghetti :3\n", 13);
if (!file)
cout << "can't write on file" << endl;
close(file);
mlx_loop_end(ptrs[0]);
return (0);
};
int main(void) {
void *const mlx = mlx_init();
void *win;
@ -47,7 +88,7 @@ int main(void) {
// MENU
{
switch (uc_menu_quick("pixels", "images", "xpm", "files",
"navigate", "assets", "xpm files", "quit", NULL))
"navigate", "assets", "xpm files", "events", "quit", NULL))
{
case 0:
goto pixels;
@ -70,6 +111,9 @@ int main(void) {
case 6:
goto xpm_files;
break;
case 7:
goto events;
break;
}
goto end;
}
@ -582,6 +626,59 @@ xpm_files:
}
goto end;
events:
{
win = mlx_new_window(mlx, 400, 240, NULL);
const static auto loop_hook = [](void *param) -> int {
(void)param;
cout << "hi from loop_hook (B to continue)" << endl;
hidScanInput();
if (hidKeysDown() & KEY_B)
mlx_loop_end(param);
return (0);
};
mlx_loop_hook(mlx, loop_hook, mlx);
mlx_loop(mlx);
cout << "mlx_loop() returned." << endl;
mlx_destroy_window(mlx, win);
mlx_loop_hook(mlx, NULL, NULL);
uc_pause();
}
{
win = mlx_new_window(mlx, 400, 240, NULL);
const static auto key_hook = [](int keycode, void *param) -> int {
cout << "[U" << keycode << "] (B to continue)" << endl;
if (keycode == KEY_B)
mlx_loop_end(param);
return (0);
};
mlx_key_hook(win, key_hook, mlx);
mlx_hook(win, KeyPress, 0, (int (*)())(void *)&keydown_hook, mlx);
mlx_loop(mlx);
cout << "mlx_loop() returned." << endl;
mlx_destroy_window(mlx, win);
uc_pause();
}
{
win = mlx_new_window(mlx, 400, 240, NULL);
void *ptrs[2];
ptrs[0] = mlx;
ptrs[1] = win;
mlx_hook(win, CreateNotify, 0, (int (*)())(void *)&create_hook, NULL);
mlx_hook(win, DestroyNotify, 0, (int (*)())(void *)&destroy_hook, &ptrs);
mlx_loop(mlx);
cout << "mlx_loop() returned." << endl;
mlx_destroy_window(mlx, win);
uc_pause();
}
goto end;
end:
cout << "Exit..." << endl;
uc_pause();

135
source/mlx_hook.c Normal file
View file

@ -0,0 +1,135 @@
/**
* mlx_hook.c
* for the project "MinilibX for 3DS"
* by Zy
* at https://github.com/frzysk/mlx3ds
*/
#include "mlx_hook.h"
#include "mlx_internal.h"
int mlx_mouse_hook(t_win win_ptr, int (*funct_ptr)(), void *param)
{
(void)win_ptr;
(void)funct_ptr;
(void)param;
// ╮(︶▽︶)╭
return (0);
}
int mlx_key_hook(t_win win_ptr,
int (*funct_ptr)(int keycode, void *param), void *param)
{
((t_internal_win *)win_ptr)->hooks[KeyRelease].hook = funct_ptr;
((t_internal_win *)win_ptr)->hooks[KeyRelease].param = param;
return (0);
}
int mlx_expose_hook(t_win win_ptr,
int (*funct_ptr)(void *param), void *param)
{
// TODO use expose hook?
((t_internal_win *)win_ptr)->hooks[Expose].hook = funct_ptr;
((t_internal_win *)win_ptr)->hooks[Expose].param = param;
return (0);
}
#include <stdlib.h> // remove debug TODO
#include <stdio.h>
#include "utilsconsole.h"
int mlx_loop_hook(t_mlx mlx_ptr,
int (*funct_ptr)(void *param), void *param)
{
((t_internal_mlx *)mlx_ptr)->hook_loop_function = funct_ptr;
((t_internal_mlx *)mlx_ptr)->hook_loop_param = param;
return (0);
}
int mlx_hook(t_win win_ptr, int x_event, int x_mask,
int (*funct)(), void *param)
{
(void)x_mask;
((t_internal_win *)win_ptr)->hooks[x_event].hook = funct;
((t_internal_win *)win_ptr)->hooks[x_event].param = param;
return (0);
}
typedef struct
{
u32 held;
u32 down;
u32 up;
} t_keys_status;
static t_keys_status keys_events(void)
{
static u32 last_held;
static u32 real_last_held;
t_keys_status r;
u32 real_held = hidKeysHeld();
hidScanInput();
r.held = real_held | real_last_held;
r.up = last_held & ~r.held;
r.down = ~last_held & r.held;
last_held = r.held;
real_last_held = real_held;
return (r);
}
static void call_events(t_internal_win *win, t_keys_status keys)
{
if (win->hooks[KeyRelease].hook && keys.up)
for (int i = 0; i < 32; i++)
if ((keys.up >> i) & 1)
win->hooks[KeyRelease].hook(
1 << i, win->hooks[KeyRelease].param);
if (win->hooks[KeyPress].hook && keys.down)
for (int i = 0; i < 32; i++)
if ((keys.down >> i) & 1)
win->hooks[KeyPress].hook(
1 << i, win->hooks[KeyPress].param);
}
static void call_start_events(t_internal_win *win)
{
if (win->hooks[CreateNotify].hook)
win->hooks[CreateNotify].hook(win->hooks[CreateNotify].param);
}
static void call_end_events(t_internal_win *win)
{
if (win->hooks[DestroyNotify].hook)
win->hooks[DestroyNotify].hook(win->hooks[DestroyNotify].param);
}
int mlx_loop(t_mlx mlx_ptr)
{
t_internal_mlx *mlx = mlx_ptr;
mlx->loop = true;
if (mlx->top_window)
call_start_events(mlx->top_window);
while (aptMainLoop() && mlx->loop)
{
t_keys_status keys = keys_events();
if (mlx->top_window)
call_events(mlx->top_window, keys);
if (mlx->hook_loop_function)
mlx->hook_loop_function(mlx->hook_loop_param);
gfxFlushBuffers(); // aptMainLoop() doesn't work without that
}
if (!aptMainLoop())
if (mlx->top_window)
call_end_events(mlx->top_window);
mlx->loop = false;
return (0);
}
int mlx_loop_end(t_mlx mlx_ptr)
{
((t_internal_mlx *)mlx_ptr)->loop = false;
return (0);
}

View file

@ -11,10 +11,7 @@
#include <stdlib.h>
#include "3ds.h"
static t_internal_mlx g_internal_mlx = {
.is_init_called = false,
.top_window = NULL,
};
static t_internal_mlx g_internal_mlx;
t_mlx mlx_init(void)
{

View file

@ -14,6 +14,7 @@
# include <stdbool.h>
# include "3ds.h"
# include "mlx_events.h"
/// @brief Write an error message and exit the program.
///
@ -29,23 +30,38 @@ typedef struct s_internal_mlx
bool is_init_called;
/// @brief Window displayed on the top screen.
struct s_internal_win *top_window;
/// @brief Function called in loop by mlx_loop().
int (*hook_loop_function)(void *param);
/// @brief Parameter given to hook_loop_function.
void *hook_loop_param;
/// @brief Set to false to break the loop of mlx_loop().
bool loop;
} t_internal_mlx;
// TODO docs
typedef struct s_internal_win_hook
{
int (*hook)();
void *param;
} t_internal_win_hook;
/// @brief Represents a window.
typedef struct s_internal_win
{
/// @brief mlx connection identifier
t_internal_mlx *mlx;
t_internal_mlx *mlx;
/// @brief Width of the window
int width;
int width;
/// @brief Height of the window
int height;
int height;
/// @brief Buffer of the screen.
u8 *framebuffer;
u8 *framebuffer;
/// @brief Width of the screen (on x).
u16 framebuffer_width;
u16 framebuffer_width;
/// @brief Height of the screen (on y).
u16 framebuffer_height;
u16 framebuffer_height;
// TODO docs
t_internal_win_hook hooks[LASTEvent];
} t_internal_win;
/// @brief Represents an image in memory.

View file

@ -10,6 +10,7 @@
#include "3ds.h"
#include "mlx_internal.h"
#include <stdlib.h>
#include <strings.h>
t_win mlx_new_window(t_mlx mlx_ptr, int size_x, int size_y, const char *title)
{
@ -21,10 +22,11 @@ t_win mlx_new_window(t_mlx mlx_ptr, int size_x, int size_y, const char *title)
r = malloc(sizeof(t_internal_win));
if (!r)
return (NULL);
bzero(r, sizeof(t_internal_win));
r->mlx = mlx_ptr;
r->mlx->top_window = r;
r->width = size_x;
r->height = size_y;
r->framebuffer = NULL;
return (r);
}