Skip to content

Commit b880673

Browse files
Merge pull request #8 from dreamer-coding/keyboard_handler
Keyboard handler
2 parents aeb80e5 + ddbbdd7 commit b880673

File tree

8 files changed

+542
-2
lines changed

8 files changed

+542
-2
lines changed

code/logic/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ set(TEST_CODE
1313
output.c
1414
soap.c
1515
stream.c
16+
keyboard.c
1617
)
1718

1819
# Create the library target

code/logic/fossil/io/framework.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define FOSSIL_IO_FRAMEWORK_H
1616

1717
// Include the necessary headers
18+
#include "keyboard.h"
1819
#include "output.h"
1920
#include "input.h"
2021
#include "error.h"

code/logic/fossil/io/keyboard.h

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/*
2+
* -----------------------------------------------------------------------------
3+
* Project: Fossil Logic
4+
*
5+
* This file is part of the Fossil Logic project, which aims to develop high-
6+
* performance, cross-platform applications and libraries. The code contained
7+
* herein is subject to the terms and conditions defined in the project license.
8+
*
9+
* Author: Michael Gene Brockus (Dreamer)
10+
*
11+
* Copyright (C) 2024 Fossil Logic. All rights reserved.
12+
* -----------------------------------------------------------------------------
13+
*/
14+
#ifndef FOSSIL_IO_KEYBOARD_H
15+
#define FOSSIL_IO_KEYBOARD_H
16+
17+
#include <stdint.h>
18+
#include <stddef.h>
19+
20+
#ifdef __cplusplus
21+
extern "C" {
22+
#endif
23+
24+
// Define a keyboard event structure
25+
typedef struct {
26+
int shift; // 1 if Shift is pressed, 0 otherwise
27+
int ctrl; // 1 if Ctrl is pressed, 0 otherwise
28+
int alt; // 1 if Alt is pressed, 0 otherwise
29+
char key; // The character of the key pressed
30+
} fossil_io_keyboard_event_t;
31+
32+
// Define a callback type for key events
33+
typedef void (*fossil_io_keyboard_callback_t)(fossil_io_keyboard_event_t event);
34+
35+
/**
36+
* Initialize the keyboard library.
37+
* Sets up any platform-specific configurations.
38+
*/
39+
void fossil_io_keyboard_init(void);
40+
41+
/**
42+
* Shut down the keyboard library.
43+
* Cleans up any platform-specific configurations.
44+
*/
45+
void fossil_io_keyboard_shutdown(void);
46+
47+
/**
48+
* Clear all keybindings from the library.
49+
*/
50+
void fossil_io_keyboard_clear_bindings(void);
51+
52+
/**
53+
* Register a keybinding with the library.
54+
*
55+
* @param event The keyboard event to bind to.
56+
* @param callback The callback function to call when the event occurs.
57+
*/
58+
void fossil_io_keyboard_register_binding(fossil_io_keyboard_event_t event, fossil_io_keyboard_callback_t callback);
59+
60+
/**
61+
* Unregister a keybinding with the library.
62+
*
63+
* @param event The keyboard event to unbind.
64+
*/
65+
void fossil_io_keyboard_unregister_binding(fossil_io_keyboard_event_t event);
66+
67+
/**
68+
* Poll for keyboard events and trigger any registered callbacks.
69+
* This function should be called in the main loop of the application.
70+
*/
71+
void fossil_io_keyboard_poll_events(void);
72+
73+
#ifdef __cplusplus
74+
}
75+
76+
/**
77+
* C++ wrapper for the SOAP API.
78+
*/
79+
namespace fossil {
80+
81+
/**
82+
* Namespace for I/O operations.
83+
*/
84+
namespace io {
85+
/**
86+
* Class for interacting with the keyboard.
87+
*/
88+
class keyboard {
89+
public:
90+
/**
91+
* Initialize the keyboard library.
92+
* Sets up any platform-specific configurations.
93+
*/
94+
static void init() {
95+
fossil_io_keyboard_init();
96+
}
97+
98+
/**
99+
* Shut down the keyboard library.
100+
* Cleans up any platform-specific configurations.
101+
*/
102+
static void shutdown() {
103+
fossil_io_keyboard_shutdown();
104+
}
105+
106+
/**
107+
* Clear all keybindings from the library.
108+
*/
109+
static void clear_bindings() {
110+
fossil_io_keyboard_clear_bindings();
111+
}
112+
113+
/**
114+
* Register a keybinding with the library.
115+
*
116+
* @param event The keyboard event to bind to.
117+
* @param callback The callback function to call when the event occurs.
118+
*/
119+
static void register_binding(fossil_io_keyboard_event_t event, fossil_io_keyboard_callback_t callback) {
120+
fossil_io_keyboard_register_binding(event, callback);
121+
}
122+
123+
/**
124+
* Unregister a keybinding with the library.
125+
*
126+
* @param event The keyboard event to unbind.
127+
*/
128+
static void unregister_binding(fossil_io_keyboard_event_t event) {
129+
fossil_io_keyboard_unregister_binding(event);
130+
}
131+
132+
/**
133+
* Poll for keyboard events and trigger any registered callbacks.
134+
* This function should be called in the main loop of the application.
135+
*/
136+
static void poll_events() {
137+
fossil_io_keyboard_poll_events();
138+
}
139+
};
140+
}
141+
}
142+
143+
#endif
144+
145+
#endif /* FOSSIL_IO_FRAMEWORK_H */

code/logic/keyboard.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
* -----------------------------------------------------------------------------
3+
* Project: Fossil Logic
4+
*
5+
* This file is part of the Fossil Logic project, which aims to develop high-
6+
* performance, cross-platform applications and libraries. The code contained
7+
* herein is subject to the terms and conditions defined in the project license.
8+
*
9+
* Author: Michael Gene Brockus (Dreamer)
10+
*
11+
* Copyright (C) 2024 Fossil Logic. All rights reserved.
12+
* -----------------------------------------------------------------------------
13+
*/
14+
#include "fossil/io/keyboard.h"
15+
#include <stdio.h>
16+
#include <stdlib.h>
17+
#include <string.h>
18+
19+
#if defined(_WIN32) || defined(_WIN64)
20+
#include <conio.h>
21+
#include <windows.h>
22+
#else
23+
#include <termios.h>
24+
#include <unistd.h>
25+
#include <fcntl.h>
26+
#include <sys/select.h> // For fd_set, FD_ZERO, FD_SET, select
27+
#include <sys/time.h> // For struct timeval
28+
#include <sys/types.h> // For system types
29+
#endif
30+
31+
#define MAX_KEYBINDS 256
32+
33+
typedef struct {
34+
fossil_io_keyboard_event_t event;
35+
fossil_io_keyboard_callback_t callback;
36+
} fossil_io_keyboard_binding_t;
37+
38+
typedef struct {
39+
fossil_io_keyboard_binding_t bindings[MAX_KEYBINDS];
40+
size_t count;
41+
} fossil_io_keyboard_manager_t;
42+
43+
static fossil_io_keyboard_manager_t keyboard_manager = { .count = 0 };
44+
45+
#if defined(_WIN32) || defined(_WIN64)
46+
47+
static int fossil_io_keyboard_is_key_pressed(void) {
48+
return _kbhit();
49+
}
50+
51+
static fossil_io_keyboard_event_t fossil_io_keyboard_get_event(void) {
52+
fossil_io_keyboard_event_t event = {0};
53+
int key = _getch();
54+
55+
// Check for extended keys (e.g., arrow keys, function keys)
56+
if (key == 0 || key == 224) {
57+
key = _getch(); // Fetch the actual key code
58+
}
59+
60+
// Check modifiers
61+
event.shift = GetKeyState(VK_SHIFT) & 0x8000;
62+
event.ctrl = GetKeyState(VK_CONTROL) & 0x8000;
63+
event.alt = GetKeyState(VK_MENU) & 0x8000;
64+
event.key = (char)key;
65+
66+
return event;
67+
}
68+
69+
#else
70+
static struct termios old_termios, new_termios;
71+
72+
static void fossil_io_keyboard_enable_raw_mode(void) {
73+
tcgetattr(STDIN_FILENO, &old_termios);
74+
new_termios = old_termios;
75+
new_termios.c_lflag &= ~(ICANON | ECHO);
76+
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
77+
}
78+
79+
static void fossil_io_keyboard_disable_raw_mode(void) {
80+
tcsetattr(STDIN_FILENO, TCSANOW, &old_termios);
81+
}
82+
83+
static int fossil_io_keyboard_is_key_pressed(void) {
84+
struct timeval timeout = {0L, 0L};
85+
fd_set fds;
86+
FD_ZERO(&fds);
87+
FD_SET(STDIN_FILENO, &fds);
88+
return select(STDIN_FILENO + 1, &fds, NULL, NULL, &timeout) > 0;
89+
}
90+
91+
static fossil_io_keyboard_event_t fossil_io_keyboard_get_event(void) {
92+
fossil_io_keyboard_event_t event = {0};
93+
char c;
94+
read(STDIN_FILENO, &c, 1);
95+
96+
event.key = c;
97+
98+
// Modifier keys (POSIX doesn't have direct access to key states; approximation)
99+
if (c == 27) { // Alt key (ESC sequence)
100+
event.alt = 1;
101+
read(STDIN_FILENO, &c, 1);
102+
event.key = c;
103+
} else if (c < 32) { // Ctrl key (control characters)
104+
event.ctrl = 1;
105+
event.key = c + 96; // Map to lowercase ASCII
106+
} else if (c == 127) { // Backspace key with Ctrl
107+
event.ctrl = 1;
108+
event.key = 8;
109+
}
110+
111+
return event;
112+
}
113+
#endif
114+
115+
void fossil_io_keyboard_init(void) {
116+
#if defined(_WIN32) || defined(_WIN64)
117+
// Windows doesn't require explicit setup for raw mode.
118+
#else
119+
fossil_io_keyboard_enable_raw_mode();
120+
atexit(fossil_io_keyboard_disable_raw_mode);
121+
#endif
122+
}
123+
124+
void fossil_io_keyboard_shutdown(void) {
125+
#if defined(_WIN32) || defined(_WIN64)
126+
// Windows doesn't require explicit cleanup for raw mode.
127+
#else
128+
fossil_io_keyboard_disable_raw_mode();
129+
#endif
130+
}
131+
132+
void fossil_io_keyboard_clear_bindings(void) {
133+
keyboard_manager.count = 0;
134+
}
135+
136+
void fossil_io_keyboard_register_binding(fossil_io_keyboard_event_t event, fossil_io_keyboard_callback_t callback) {
137+
if (keyboard_manager.count < MAX_KEYBINDS) {
138+
keyboard_manager.bindings[keyboard_manager.count].event = event;
139+
keyboard_manager.bindings[keyboard_manager.count].callback = callback;
140+
keyboard_manager.count++;
141+
} else {
142+
fprintf(stderr, "Max keybindings reached.\n");
143+
}
144+
}
145+
146+
void fossil_io_keyboard_unregister_binding(fossil_io_keyboard_event_t event) {
147+
for (size_t i = 0; i < keyboard_manager.count; ++i) {
148+
if (keyboard_manager.bindings[i].event.key == event.key &&
149+
keyboard_manager.bindings[i].event.shift == event.shift &&
150+
keyboard_manager.bindings[i].event.ctrl == event.ctrl &&
151+
keyboard_manager.bindings[i].event.alt == event.alt) {
152+
for (size_t j = i; j < keyboard_manager.count - 1; ++j) {
153+
keyboard_manager.bindings[j] = keyboard_manager.bindings[j + 1];
154+
}
155+
keyboard_manager.count--;
156+
return;
157+
}
158+
}
159+
fprintf(stderr, "No matching keybinding to unregister.\n");
160+
}
161+
162+
void fossil_io_keyboard_poll_events(void) {
163+
if (fossil_io_keyboard_is_key_pressed()) {
164+
fossil_io_keyboard_event_t event = fossil_io_keyboard_get_event();
165+
166+
for (size_t i = 0; i < keyboard_manager.count; ++i) {
167+
fossil_io_keyboard_binding_t *binding = &keyboard_manager.bindings[i];
168+
if (binding->event.key == event.key &&
169+
binding->event.shift == event.shift &&
170+
binding->event.ctrl == event.ctrl &&
171+
binding->event.alt == event.alt) {
172+
if (binding->callback) {
173+
binding->callback(event);
174+
}
175+
break;
176+
}
177+
}
178+
}
179+
}

code/logic/meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ dir = include_directories('.')
22

33

44
fossil_io_lib = library('fossil-io',
5-
files('input.c', 'output.c', 'error.c', 'soap.c', 'stream.c'),
5+
files('input.c', 'output.c', 'error.c', 'soap.c', 'stream.c', 'keyboard.c'),
66
install: true,
77
include_directories: dir)
88

0 commit comments

Comments
 (0)