Design Pattern Examples
Overview of object-oriented design patterns
cursor.cpp
Go to the documentation of this file.
1
6
7#include <iostream>
8#include <string>
9#include <vector>
10
11#ifdef _MSC_VER
12#include <windows.h>
13#else
14#include <termios.h>
15#include <unistd.h>
16#endif
17
18#include "_countof.h"
19#include "cursor.h"
20#include "split.h"
21#include "formatstring.h"
22
23namespace
24{
25 bool inputEchoDisabled = false;
26#ifdef _MSC_VER
27 HANDLE hStdIn = INVALID_HANDLE_VALUE;
28 HANDLE hStdOut = INVALID_HANDLE_VALUE;
29 DWORD inputMode = 0;
30
34 void _init_console_mode()
35 {
36 if (hStdOut == INVALID_HANDLE_VALUE)
37 {
38 hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
39 if (hStdOut == INVALID_HANDLE_VALUE)
40 {
41 DWORD lastError = ::GetLastError();
42 std::cout << Helpers::formatstring("GetStdHandle(STD_OUTPUT_HANDLE) failed: code = 0x%x", lastError) << std::endl;
43 }
44 }
45 if (hStdIn == INVALID_HANDLE_VALUE)
46 {
47 hStdIn = GetStdHandle(STD_INPUT_HANDLE);
48 if (hStdIn != INVALID_HANDLE_VALUE)
49 {
50 ::GetConsoleMode(hStdIn, &inputMode);
51 }
52 else
53 {
54 DWORD lastError = ::GetLastError();
55 std::cout << Helpers::formatstring("GetStdHandle(STD_INPUT_HANDLE) failed: code = 0x%x", lastError) << std::endl;
56 }
57 }
58 }
59#else
60 static struct termios oldt, newt;
61#endif
62
68 {
69#ifdef _MSC_VER
70 _init_console_mode();
71 if (hStdIn != INVALID_HANDLE_VALUE)
72 {
73 DWORD newMode = inputMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
74 if (!::SetConsoleMode(hStdIn, newMode))
75 {
76 DWORD lastError = ::GetLastError();
77 std::cout << Helpers::formatstring("SetConsoleMode(hStdIn, newMode) failed: code = 0x%x", lastError) << std::endl;
78 }
79 }
80#else
81 tcgetattr(STDIN_FILENO, &oldt);
82 newt = oldt;
83 newt.c_lflag &= ~(ICANON | ECHO);
84 tcsetattr(STDIN_FILENO, TCSANOW, &newt);
85#endif
86 inputEchoDisabled = true;
87 }
88
92 void _enableInputEcho()
93 {
94#ifdef _MSC_VER
95 _init_console_mode();
96 if (hStdIn != INVALID_HANDLE_VALUE)
97 {
98 if (!::SetConsoleMode(hStdIn, inputMode))
99 {
100 DWORD lastError = ::GetLastError();
101 std::cout << Helpers::formatstring("SetConsoleMode(hStdIn, inputMode) failed: code = 0x%x", lastError) << std::endl;
102 }
103 }
104#else
105 tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
106#endif
107 inputEchoDisabled = false;
108 }
109
110} // end anonymous namespace
111
112
113namespace Helpers
114{
116 // disableinputecho()
119 {
121 {
123 }
124 }
125
127 // enableinputecho()
130 {
132 {
134 }
135 }
136
138 // setcursorposition()
140 void setcursorposition(int row, int column)
141 {
142 std::cout << "\x1b[" << row << ";" << column << "H";
143 std::cout.flush();
144 }
145
147 // getcursorposition()
149 void getcursorposition(int *row, int *column)
150 {
151 if (row != nullptr && column != nullptr)
152 {
153 // Don't disable input echo if it is already disabled.
154 bool wasInputEchoDisabled = inputEchoDisabled;
155 if (!wasInputEchoDisabled)
156 {
158 }
159
160 std::cout << "\x1b[6n";
161 std::cout.flush();
162 char buffer[16]{ 0 };
163 // Must specify a delimiter, otherwise will block until eof (ctrl-Z).
164 std::cin.get(buffer, _countof(buffer), 'R');
165 int lastChar = std::cin.get(); // Retrieve the delimiter
166 std::string input(buffer);
167 input += (char)lastChar;
168 // Expecting ESC [ <r> ; <c> R (no spaces)
169 if (input.size() > 2 && input[0] == '\x1b' && input[1] == '[')
170 {
171 std::vector<std::string> elements = split(input, "[;R");
172 if (elements.size() >= 3)
173 {
174 *row = std::stoi(elements[1], nullptr);
175 *column = std::stoi(elements[2], nullptr);
176 }
177 }
178 if (!wasInputEchoDisabled)
179 {
181 }
182 }
183 }
184
185} // end namespace
static bool inputEchoDisabled
Definition: cursor.c:19
static void _enableInputEcho(void)
Enable echoing of input.
Definition: cursor.c:89
static struct termios oldt newt
Definition: cursor.c:26
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
#define _countof(w)
Declaration of the setcursorposition() and getcursorposition() functions for manipulating the cursor ...
Declaration of the formatstring() function that replaces sprintf() and snprintf() by allocating the r...
Declaration of the split functions, for splitting a string on delimiters.
int ENABLE_ECHO_INPUT
Flag to enable echoing everything in standard input.
int INVALID_HANDLE_VALUE
Windows indicator of an invalid handle.
int ENABLE_LINE_INPUT
Flag to enable buffering standard input until Enter is pressed.
The namespace containing all the "helper" functions in the C++ code.
void enableinputecho()
Enable echoing input, which should be the default mode. Call this only after calling disableinputecho...
Definition: cursor.cpp:129
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....
void disableinputecho()
Disable echoing input until enableinputecho() is called.
Definition: cursor.cpp:118
std::vector< std::string > split(const char *pszString, const char *splitChars)
Split the given string into a list of strings given the character on which to split....
Definition: split.cpp:13
void setcursorposition(int row, int column)
Move the text cursor to the specified screen coordinates.
Definition: cursor.cpp:140
void getcursorposition(int *row, int *column)
Retrieve the current cursor position in the console window.
Definition: cursor.cpp:149