Design Pattern Examples
Overview of object-oriented design patterns
cursor.c
Go to the documentation of this file.
1
5
6#include <stdlib.h>
7#include <stdio.h>
8
9#ifdef _MSC_VER
10#include <windows.h>
11#else
12#include <termios.h>
13#include <unistd.h>
14#endif
15
16#include "cursor.h"
17#include "split.h"
18
19static bool inputEchoDisabled = false;
20
21#ifdef _MSC_VER
22static HANDLE hStdIn = INVALID_HANDLE_VALUE;
23static HANDLE hStdOut = INVALID_HANDLE_VALUE;
24static DWORD inputMode = 0;
25#else
26static struct termios oldt, newt;
27#endif
28
29#ifdef _MSC_VER
33static void _init_console_mode(void)
34{
35 if (hStdOut == INVALID_HANDLE_VALUE)
36 {
37 hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
38 if (hStdOut == INVALID_HANDLE_VALUE)
39 {
40 DWORD lastError = GetLastError();
41 printf("GetStdHandle(STD_OUTPUT_HANDLE) failed: code = 0x%x\n", lastError);
42 }
43 }
44 if (hStdIn == INVALID_HANDLE_VALUE)
45 {
46 hStdIn = GetStdHandle(STD_INPUT_HANDLE);
47 if (hStdIn != INVALID_HANDLE_VALUE)
48 {
49 GetConsoleMode(hStdIn, &inputMode);
50 }
51 else
52 {
53 DWORD lastError = GetLastError();
54 printf("GetStdHandle(STD_INPUT_HANDLE) failed: code = 0x%x\n", lastError);
55 }
56 }
57}
58#endif
59
64static void _disableInputEcho(void)
65{
66#ifdef _MSC_VER
67 _init_console_mode();
68 if (hStdIn != INVALID_HANDLE_VALUE)
69 {
70 DWORD newMode = inputMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
71 if (!SetConsoleMode(hStdIn, newMode))
72 {
73 DWORD lastError = GetLastError();
74 printf("SetConsoleMode(hStdIn, newMode) failed: code = 0x%x\n", lastError);
75 }
76 }
77#else
78 tcgetattr(STDIN_FILENO, &oldt);
79 newt = oldt;
80 newt.c_lflag &= ~(ICANON | ECHO);
81 tcsetattr(STDIN_FILENO, TCSANOW, &newt);
82#endif
83 inputEchoDisabled = true;
84}
85
89static void _enableInputEcho(void)
90{
91#ifdef _MSC_VER
92 _init_console_mode();
93 if (hStdIn != INVALID_HANDLE_VALUE)
94 {
95 if (!SetConsoleMode(hStdIn, inputMode))
96 {
97 DWORD lastError = GetLastError();
98 printf("SetConsoleMode(hStdIn, inputMode) failed: code = 0x%x\n", lastError);
99 }
100 }
101#else
102 tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
103#endif
104 inputEchoDisabled = false;
105}
106
107//=============================================================================
108
110// disableinputecho()
113{
115 {
117 }
118}
119
121// enableinputecho()
124{
126 {
128 }
129}
130
132// setcursorposition()
134void setcursorposition(int row, int column)
135{
136 printf("\x1b[%d;%dH", row, column);
137 fflush(stdout);
138}
139
141// getcursorposition()
143void getcursorposition(int *row, int *column)
144{
145 if (row != NULL && column != NULL)
146 {
147 // Don't disable input echo if it is already disabled.
148 bool wasInputEchoDisabled = inputEchoDisabled;
149 if (!wasInputEchoDisabled)
150 {
152 }
153
154 printf("\x1b[6n");
155 fflush(stdout);
156 char buffer[16] = { 0 };
157 // Must specify a delimiter, otherwise will block until eof (ctrl-Z).
158 int c = 0;
159 size_t bufferIndex = 0;
160 while (c != 'R' && c != EOF && bufferIndex < sizeof(buffer))
161 {
162 c = getc(stdin);
163 buffer[bufferIndex] = (char)c;
164 bufferIndex++;
165 }
166 // If we filled the buffer, we got some really strange input so assume
167 // it's something we can't handle and ignore it.
168 if (bufferIndex < sizeof(buffer))
169 {
170 // Expecting ESC [ <r> ; <c> R (no spaces)
171 if (bufferIndex > 2 && buffer[0] == '\x1b' && buffer[1] == '[')
172 {
173 SplitList elements = { 0 };
174 split(buffer, "[;R", &elements);
175 if (elements.strings_count >= 3)
176 {
177 *row = (int)strtol(elements.strings[1], NULL, 0);
178 *column = (int)strtol(elements.strings[2], NULL, 0);
179 }
180 SplitList_Clear(&elements);
181 }
182 }
183 if (!wasInputEchoDisabled)
184 {
186 }
187 }
188}
void disableinputecho(void)
Disable echoing input until enableinputecho() is called.
Definition: cursor.c:112
static bool inputEchoDisabled
Definition: cursor.c:19
void enableinputecho(void)
Enable echoing input, which should be the default mode. Call this only after calling disableinputecho...
Definition: cursor.c:123
static void _enableInputEcho(void)
Enable echoing of input.
Definition: cursor.c:89
static struct termios oldt newt
Definition: cursor.c:26
void setcursorposition(int row, int column)
Move the text cursor to the specified screen coordinates.
Definition: cursor.c:134
void getcursorposition(int *row, int *column)
Retrieve the current cursor position in the console window.
Definition: cursor.c:143
static void _disableInputEcho(void)
Disable echoing of input and disable line input mode (where the Enter key must be entered to complete...
Definition: cursor.c:64
Declaration of the setcursorposition() and getcursorposition() functions for manipulating the cursor ...
Declaration of the split functions, for splitting a string on delimiters.
void SplitList_Clear(SplitList *list)
Clear the given SplitList object so it can be reused again. Releases the list of sub-strings (but doe...
Definition: split.c:30
void split(char *s, const char *splitChars, SplitList *components)
Split the given path into multiple strings based on the given delimiter. The pointers to each string ...
Definition: split.c:72
Represents a collection of sub-strings split from a single string using the split() function.
Definition: helpers/split.h:17
size_t strings_count
Number of sub-strings.
Definition: helpers/split.h:19
const char ** strings
Pointers to each sub-string.
Definition: helpers/split.h:18