Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for mouse clicks and fetching screen size(WIN32 && Linux) #20

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Compile it and run:

```
# Linux
cc main.c -lX11 -lasound -o main && ./main
cc main.c -lX11 -lXinerama -lasound -o main && ./main
# macOS
cc main.c -framework Cocoa -framework AudioToolbox -o main && ./main
# windows
Expand Down
5 changes: 5 additions & 0 deletions examples/input-c/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ static int run() {
}
}
*p = '\0';

int left_down = (f.mouse >> MOUSE_LEFT_BUTTON) & 1;
int middle_down = (f.mouse >> MOUSE_MIDDLE_BUTTON) & 1;
int right_down = (f.mouse >> MOUSE_RIGHT_BUTTON) & 1;

fenster_rect(&f, 0, 0, W, H, 0);
/* draw mouse "pointer" */
if (f.x > 5 && f.y > 5 && f.x < f.width - 5 && f.y < f.height - 5) {
Expand Down
178 changes: 125 additions & 53 deletions fenster.h
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
#ifndef FENSTER_H
#define FENSTER_H

#if defined(__APPLE__)
#include <CoreGraphics/CoreGraphics.h>
#include <objc/NSObjCRuntime.h>
#include <objc/objc-runtime.h>
#elif defined(_WIN32)
#include <windows.h>
#else
#define _DEFAULT_SOURCE 1
#include <X11/XKBlib.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <time.h>
#endif

#include <stdint.h>
#include <stdlib.h>

#define MOUSE_LEFT_BUTTON 0
#define MOUSE_MIDDLE_BUTTON 1
#define MOUSE_RIGHT_BUTTON 2

struct fenster {
const char *title;
const int width;
Expand All @@ -28,7 +18,40 @@ struct fenster {
int x;
int y;
int mouse;
void* backend;
};

#ifndef FENSTER_API
#define FENSTER_API extern
#endif
#ifndef FENSTER_DLL
#define FENSTER_DLL(name,...) name(__VA_ARGS__)
#endif
FENSTER_API void FENSTER_DLL(fenster_screen_size,int *width, int *height);
FENSTER_API int FENSTER_DLL(fenster_open,struct fenster *f);
FENSTER_API int FENSTER_DLL(fenster_loop,struct fenster *f);
FENSTER_API void FENSTER_DLL(fenster_close,struct fenster *f);
FENSTER_API void FENSTER_DLL(fenster_sleep,int64_t ms);
FENSTER_API int64_t FENSTER_DLL(fenster_time,void);
#define fenster_pixel(f, x, y) ((f)->buf[((y) * (f)->width) + (x)])

#ifndef FENSTER_HEADER
#if defined(__APPLE__)
#include <CoreGraphics/CoreGraphics.h>
#include <objc/NSObjCRuntime.h>
#include <objc/objc-runtime.h>
#elif defined(_WIN32)
#include <windows.h>
#else
#define _DEFAULT_SOURCE 1
#include <X11/XKBlib.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <time.h>
#include <X11/extensions/Xinerama.h>
#endif
typedef struct{
#if defined(__APPLE__)
id wnd;
#elif defined(_WIN32)
HWND hwnd;
Expand All @@ -38,19 +61,8 @@ struct fenster {
GC gc;
XImage *img;
#endif
};

#ifndef FENSTER_API
#define FENSTER_API extern
#endif
FENSTER_API int fenster_open(struct fenster *f);
FENSTER_API int fenster_loop(struct fenster *f);
FENSTER_API void fenster_close(struct fenster *f);
FENSTER_API void fenster_sleep(int64_t ms);
FENSTER_API int64_t fenster_time(void);
#define fenster_pixel(f, x, y) ((f)->buf[((y) * (f)->width) + (x)])
} backend_t;

#ifndef FENSTER_HEADER
#if defined(__APPLE__)
#define msg(r, o, s) ((r(*)(id, SEL))objc_msgSend)(o, sel_getUid(s))
#define msg1(r, o, s, A, a) \
Expand Down Expand Up @@ -92,6 +104,10 @@ static BOOL fenster_should_close(id v, SEL s, id w) {
return YES;
}

FENSTER_API void fenster_screen_size(int *width, int *height) {
//NOT IMPLEMENTED
}

FENSTER_API int fenster_open(struct fenster *f) {
msg(id, cls("NSApplication"), "sharedApplication");
msg1(void, NSApp, "setActivationPolicy:", NSInteger, 0);
Expand Down Expand Up @@ -198,8 +214,22 @@ static LRESULT CALLBACK fenster_wndproc(HWND hwnd, UINT msg, WPARAM wParam,
DestroyWindow(hwnd);
break;
case WM_LBUTTONDOWN:
f->mouse |= 1 << MOUSE_LEFT_BUTTON;
break;
case WM_LBUTTONUP:
f->mouse = (msg == WM_LBUTTONDOWN);
f->mouse &= ~(1 << MOUSE_LEFT_BUTTON);
break;
case WM_MBUTTONDOWN:
f->mouse |= 1 << MOUSE_MIDDLE_BUTTON;
break;
case WM_MBUTTONUP:
f->mouse &= ~(1 << MOUSE_MIDDLE_BUTTON);
break;
case WM_RBUTTONDOWN:
f->mouse |= 1 << MOUSE_RIGHT_BUTTON;
break;
case WM_RBUTTONUP:
f->mouse &= ~(1 << MOUSE_RIGHT_BUTTON);
break;
case WM_MOUSEMOVE:
f->y = HIWORD(lParam), f->x = LOWORD(lParam);
Expand All @@ -221,7 +251,16 @@ static LRESULT CALLBACK fenster_wndproc(HWND hwnd, UINT msg, WPARAM wParam,
return 0;
}

FENSTER_API void fenster_screen_size(int *width, int *height) {
RECT desktop;
const HWND hDesktop = GetDesktopWindow();
GetWindowRect(hDesktop, &desktop);
*width = desktop.right;
*height = desktop.bottom;
}

FENSTER_API int fenster_open(struct fenster *f) {
backend_t* b = malloc(sizeof(backend_t));
HINSTANCE hInstance = GetModuleHandle(NULL);
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(WNDCLASSEX);
Expand All @@ -230,71 +269,104 @@ FENSTER_API int fenster_open(struct fenster *f) {
wc.hInstance = hInstance;
wc.lpszClassName = f->title;
RegisterClassEx(&wc);
f->hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, f->title, f->title,
b->hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, f->title, f->title,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
f->width, f->height, NULL, NULL, hInstance, NULL);

if (f->hwnd == NULL)
if (b->hwnd == NULL)
return -1;
SetWindowLongPtr(f->hwnd, GWLP_USERDATA, (LONG_PTR)f);
ShowWindow(f->hwnd, SW_NORMAL);
UpdateWindow(f->hwnd);
SetWindowLongPtr(b->hwnd, GWLP_USERDATA, (LONG_PTR)f);
ShowWindow(b->hwnd, SW_NORMAL);
UpdateWindow(b->hwnd);
f->backend = b;
return 0;
}

FENSTER_API void fenster_close(struct fenster *f) { (void)f; }
FENSTER_API void fenster_close(struct fenster *f) {
free(f->backend);
}

FENSTER_API int fenster_loop(struct fenster *f) {
backend_t* b = (backend_t*)f->backend;
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
return -1;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
InvalidateRect(f->hwnd, NULL, TRUE);
InvalidateRect(b->hwnd, NULL, TRUE);
return 0;
}
#else
// clang-format off
static int FENSTER_KEYCODES[124] = {XK_BackSpace,8,XK_Delete,127,XK_Down,18,XK_End,5,XK_Escape,27,XK_Home,2,XK_Insert,26,XK_Left,20,XK_Page_Down,4,XK_Page_Up,3,XK_Return,10,XK_Right,19,XK_Tab,9,XK_Up,17,XK_apostrophe,39,XK_backslash,92,XK_bracketleft,91,XK_bracketright,93,XK_comma,44,XK_equal,61,XK_grave,96,XK_minus,45,XK_period,46,XK_semicolon,59,XK_slash,47,XK_space,32,XK_a,65,XK_b,66,XK_c,67,XK_d,68,XK_e,69,XK_f,70,XK_g,71,XK_h,72,XK_i,73,XK_j,74,XK_k,75,XK_l,76,XK_m,77,XK_n,78,XK_o,79,XK_p,80,XK_q,81,XK_r,82,XK_s,83,XK_t,84,XK_u,85,XK_v,86,XK_w,87,XK_x,88,XK_y,89,XK_z,90,XK_0,48,XK_1,49,XK_2,50,XK_3,51,XK_4,52,XK_5,53,XK_6,54,XK_7,55,XK_8,56,XK_9,57};
// clang-format on
FENSTER_API void fenster_screen_size(int *width, int *height){
Display *display = XOpenDisplay(NULL);

if (XineramaIsActive(display)) {
int screen_count;
XineramaScreenInfo *screens = XineramaQueryScreens(display, &screen_count);
if(screens){
*width = screens[0].width;
*height = screens[0].height;
XFree(screens);
}

}
else {
Screen *screen = XScreenOfDisplay(display,0);
*width = WidthOfScreen(screen);
*height = HeightOfScreen(screen);
}

XCloseDisplay(display);
}
FENSTER_API int fenster_open(struct fenster *f) {
f->dpy = XOpenDisplay(NULL);
int screen = DefaultScreen(f->dpy);
f->w = XCreateSimpleWindow(f->dpy, RootWindow(f->dpy, screen), 0, 0, f->width,
f->height, 0, BlackPixel(f->dpy, screen),
WhitePixel(f->dpy, screen));
f->gc = XCreateGC(f->dpy, f->w, 0, 0);
XSelectInput(f->dpy, f->w,
backend_t* b = malloc(sizeof(backend_t));
b->dpy = XOpenDisplay(NULL);
int screen = DefaultScreen(b->dpy);
b->w = XCreateSimpleWindow(b->dpy, RootWindow(b->dpy, screen), 0, 0, f->width,
f->height, 0, BlackPixel(b->dpy, screen),
WhitePixel(b->dpy, screen));
b->gc = XCreateGC(b->dpy, b->w, 0, 0);
XSelectInput(b->dpy, b->w,
ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask |
ButtonReleaseMask | PointerMotionMask);
XStoreName(f->dpy, f->w, f->title);
XMapWindow(f->dpy, f->w);
XSync(f->dpy, f->w);
f->img = XCreateImage(f->dpy, DefaultVisual(f->dpy, 0), 24, ZPixmap, 0,
XStoreName(b->dpy, b->w, f->title);
XMapWindow(b->dpy, b->w);
XSync(b->dpy, b->w);
b->img = XCreateImage(b->dpy, DefaultVisual(b->dpy, 0), 24, ZPixmap, 0,
(char *)f->buf, f->width, f->height, 32, 0);
f->backend = b;
return 0;
}
FENSTER_API void fenster_close(struct fenster *f) { XCloseDisplay(f->dpy); }
FENSTER_API void fenster_close(struct fenster *f) {
XCloseDisplay(((backend_t*)f->backend)->dpy);
free(f->backend);
}
FENSTER_API int fenster_loop(struct fenster *f) {
backend_t* b = f->backend;
XEvent ev;
XPutImage(f->dpy, f->w, f->gc, f->img, 0, 0, 0, 0, f->width, f->height);
XFlush(f->dpy);
while (XPending(f->dpy)) {
XNextEvent(f->dpy, &ev);
XPutImage(b->dpy, b->w, b->gc, b->img, 0, 0, 0, 0, f->width, f->height);
XFlush(b->dpy);
while (XPending(b->dpy)) {
XNextEvent(b->dpy, &ev);
switch (ev.type) {
case ButtonPress:
f->mouse |= 1 << (ev.xbutton.button -1);
break;
case ButtonRelease:
f->mouse = (ev.type == ButtonPress);
f->mouse &= ~(1 << (ev.xbutton.button -1));
break;
case MotionNotify:
f->x = ev.xmotion.x, f->y = ev.xmotion.y;
break;
case KeyPress:
case KeyRelease: {
int m = ev.xkey.state;
int k = XkbKeycodeToKeysym(f->dpy, ev.xkey.keycode, 0, 0);
int k = XkbKeycodeToKeysym(b->dpy, ev.xkey.keycode, 0, 0);
for (unsigned int i = 0; i < 124; i += 2) {
if (FENSTER_KEYCODES[i] == k) {
f->keys[FENSTER_KEYCODES[i + 1]] = (ev.type == KeyPress);
Expand Down Expand Up @@ -327,7 +399,7 @@ FENSTER_API void fenster_sleep(int64_t ms) {
}
FENSTER_API int64_t fenster_time(void) {
struct timespec time;
clock_gettime(CLOCK_REALTIME, &time);
clock_gettime(0/*CLOCK_REALTIME*/, &time);
return time.tv_sec * 1000 + (time.tv_nsec / 1000000);
}
#endif
Expand Down