-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtyping_simulator_v2.c
More file actions
279 lines (217 loc) · 10.6 KB
/
Copy pathtyping_simulator_v2.c
File metadata and controls
279 lines (217 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
// gcc typing_simulator.c -o typing_simulator -lncurses
#include <ncurses.h> // Library for terminal manipulation (text-based UI)
#include <unistd.h> // For usleep() function to introduce delays
#include <stdlib.h> // For standard functions like rand(), srand(), malloc(), etc.
#include <time.h> // For time() function to seed the random number generator
#include <string.h> // For string manipulation functions like strlen(), strcmp(), etc.
#include <ctype.h> // For character classification functions like isalnum()
// The following lines define the minimum and maximum delay between character typing
// DELAY_MIN: Minimum delay in microseconds
// DELAY_MAX: Maximum delay in microseconds
#define DELAY_MIN 4000 // Minimum delay in microseconds
#define DELAY_MAX 40000 // Maximum delay in microseconds
// ERROR_PROB defines the probability of making a typing error (e.g., random character insertion)
#define ERROR_PROB 0.020 // Probability of making a typing error (2%)
// Global variables
int count_of_scroll = 0; // Tracks the number of times the window has scrolled
int color_pair = 1; // Stores the current color pair used for text display
// Function to introduce a delay in milliseconds
void ms_sleep(int ms) {
usleep(ms * 1000); // Convert milliseconds to microseconds and sleep
}
// Function to update the status line that shows the current cursor position
void update_status_line() {
int y, x;
getyx(stdscr, y, x); // Get the current cursor position
int current_lines = getmaxy(stdscr); // Get the total number of lines in the terminal
int width = getmaxx(stdscr); // Get the total number of columns (width of the terminal)
// Buffer to hold the full status line
char status[width];
// Create the status line with "-- INSERT --" at the start
snprintf(status, sizeof(status), "-- INSERT --");
// Calculate the position to start printing the cursor coordinates
int coord_position = width - 18; // 18 characters from the right edge
// Fill the space between "-- INSERT --" and the coordinates with spaces
memset(status + 12, ' ', coord_position - 12);
// Convert coordinates to string
char coord_str[15];
snprintf(coord_str, sizeof(coord_str), "%d,%d", y + 1 + count_of_scroll, x + 1);
// Append the coordinates at the calculated position
strncpy(status + coord_position, coord_str, strlen(coord_str));
// Fill the remaining space after the coordinates with spaces
int coord_length = strlen(coord_str);
memset(status + coord_position + coord_length, ' ', width - (coord_position + coord_length));
// Null-terminate the status string
status[width-1] = '\0';
// Move the cursor to the bottom of the screen
move(current_lines - 1, 0);
// Clear the status line to remove remnants from previous updates
//clrtoeol();
// Display the status line with the current color pair
attron(COLOR_PAIR(2));
attron(A_REVERSE);
printw("%s", status);
attroff(A_REVERSE);
attroff(COLOR_PAIR(2));
// Return the cursor to its original position
move(y, x);
refresh(); // Refresh the screen to reflect changes
}
// Function to delete the last character typed
void delete_last_char() {
if (getcurx(stdscr) > 0) { // Ensure the cursor is not at the beginning of the line
move(getcury(stdscr), getcurx(stdscr) - 1); // Move cursor one position left
addch(' '); // Replace the character with a space (effectively deleting it)
move(getcury(stdscr), getcurx(stdscr) - 1); // Move cursor back to the deleted position
refresh();
// Introduce a random delay to simulate realistic typing speed
usleep(rand() % (DELAY_MAX - DELAY_MIN + 1) + DELAY_MIN);
// Update the status line after deleting the character
update_status_line();
}
}
// Function to introduce a random typing error by inserting a random character
void type_with_errors() {
// Character set including letters, digits, and special symbols
const char char_set[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"`~!@#$%^&*()-=_+[]\\{}|;':\",./<>? ";
int num_of_chars = sizeof(char_set) - 1; // Total number of characters in the set
char randomChar = char_set[rand() % num_of_chars]; // Pick a random character
// Display the random character
addch(randomChar);
refresh();
usleep(rand() % (DELAY_MAX - DELAY_MIN + 1) + DELAY_MIN);
// Delete the random character to simulate a typing error correction
delete_last_char();
attron(COLOR_PAIR(color_pair)); // Restore the color pair after correction
refresh();
usleep(rand() % (DELAY_MAX - DELAY_MIN + 1) + DELAY_MIN);
}
void type_char(char c) {
int y, x;
getyx(stdscr, y, x); // Get the current cursor position (y, x)
int current_lines = getmaxy(stdscr); // Get the total number of lines in the terminal window
// Check if the cursor is on the second to last line and the character to be typed is a newline
if (y == LINES - 2 && c == '\n') { // LINES - 2 ensures the status line is preserved
// Clear the last line to make space for the status line
move(current_lines - 1, 0);
clrtoeol(); // Clear from the cursor to the end of the line
// Move the cursor to the second to last line
move(current_lines - 2 - 1, x);
refresh(); // Refresh the screen to apply the changes
scrollok(stdscr, TRUE); // Enable scrolling for the window
wscrl(stdscr, 1); // Scroll the window content up by one line
refresh(); // Refresh the screen to apply the scrolling
// Increment the scroll count to keep track of how many times the window has scrolled
count_of_scroll++;
}
// Randomly decide whether to introduce a typing error based on ERROR_PROB
if ((double)rand() / RAND_MAX < ERROR_PROB) {
type_with_errors(); // Introduce a typing error
}
addch(c); // Type the actual character
refresh(); // Refresh the screen to display the typed character
update_status_line(); // Update the status line with the current cursor position
usleep(rand() % (DELAY_MAX - DELAY_MIN + 1) + DELAY_MIN); // Introduce a delay to simulate realistic typing speed
}
void print_highlighted(const char* code) {
// List of C/C++ keywords to be highlighted
const char* keywords[] = {"int", "bool", "vector", "return", "if", "else", "while", "for", "void"};
int num_keywords = sizeof(keywords) / sizeof(keywords[0]); // Calculate the number of keywords
while (*code) {
int is_keyword = 0; // Flag to check if the current word is a keyword
for (int i = 0; i < num_keywords; i++) {
size_t len = strlen(keywords[i]); // Get the length of the current keyword
// Check if the current segment of code matches a keyword and is followed by a non-alphanumeric character
if (strncmp(code, keywords[i], len) == 0 && !isalnum(code[len])) {
// If it's a keyword, highlight it
for (size_t j = 0; j < len; j++) {
color_pair = 2;
attron(COLOR_PAIR(2)); // Set color for keywords
type_char(*code++); // Type the keyword character by character
attroff(COLOR_PAIR(2)); // Turn off keyword color attribute
}
is_keyword = 1; // Mark that we found a keyword
break; // Break out of the loop since the keyword has been processed
}
}
if (!is_keyword) { // If the current segment is not a keyword
if (*code == '"') { // Check if it's the start of a string literal
do {
color_pair = 3;
attron(COLOR_PAIR(3)); // Set color for string literals
type_char(*code++); // Type the string character by character
attroff(COLOR_PAIR(3)); // Turn off string color attribute
} while (*code && *code != '"'); // Continue until the end of the string literal
color_pair = 3;
attron(COLOR_PAIR(3)); // Set color for the closing quote of the string
type_char(*code++); // Type the closing quote
attroff(COLOR_PAIR(3)); // Turn off string color attribute
} else { // If it's not a keyword or string literal, treat it as regular code
color_pair = 1;
attron(COLOR_PAIR(1)); // Set color for regular code
type_char(*code++); // Type the character
attroff(COLOR_PAIR(1)); // Turn off regular code color attribute
}
}
}
}
void read_code_from_file(const char* filename, char** buffer) {
// Open the file in read mode
FILE* file = fopen(filename, "r");
if (!file) {
// If the file fails to open, print an error message and terminate the program
perror("Failed to open file");
exit(EXIT_FAILURE);
}
// Move the file pointer to the end of the file to determine the file size
fseek(file, 0, SEEK_END);
long length = ftell(file); // Get the current file pointer position, which is the file size
fseek(file, 0, SEEK_SET); // Reset the file pointer back to the beginning of the file
// Allocate memory to hold the contents of the file plus one extra byte for the null-terminator
*buffer = malloc(length + 1);
if (!*buffer) {
// If memory allocation fails, print an error message and terminate the program
perror("Failed to allocate memory");
exit(EXIT_FAILURE);
}
// Read the entire file into the buffer
fread(*buffer, 1, length, file);
(*buffer)[length] = '\0'; // Add a null-terminator at the end of the buffer to make it a valid C string
// Close the file
fclose(file);
}
int main() {
// Seed the random number generator using the current time
srand(time(NULL));
// Initialize ncurses
initscr(); // Start curses mode
start_color(); // Enable color functionality in the terminal
// Set default background color (default terminal background)
use_default_colors();
// Set the terminal to "cbreak" mode, where input is immediately available to the program
cbreak();
noecho(); // Disable echoing of input characters
curs_set(1); // Make the cursor visible
// Define color pairs for different types of text
init_pair(1, COLOR_GREEN, -1); // Color pair 1: Green text on transparent background (regular code text)
init_pair(2, COLOR_WHITE, -1); // Color pair 2: White text on transparent background (keywords)
init_pair(3, COLOR_YELLOW, -1); // Color pair 3: Yellow text on transparent background (string literals)
// Clear the terminal screen
clear();
char* code = NULL; // Pointer to hold the code read from the file
read_code_from_file("code.c", &code); // Read the code from "code.c" into the buffer
print_highlighted(code); // Print the code with syntax highlighting
free(code); // Free the allocated memory for the code
// Update and display the status line with the current cursor position
update_status_line(); // Call the function to display the status line
// Wait for a key press before exiting
getch();
// End ncurses mode and restore the terminal to its normal state
curs_set(0); // Hide the cursor
endwin(); // End curses mode
return 0;
}