Console Library 8.0.0
A header-only library that makes C++ simple
Loading...
Searching...
No Matches
kb.h
Go to the documentation of this file.
1
10
11/*
12Copyright (c) 2026 MrXie1109
13
14Permission is hereby granted, free of charge, to any person obtaining a copy
15of this software and associated documentation files (the "Software"), to deal
16in the Software without restriction, including without limitation the rights
17to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18copies of the Software, and to permit persons to whom the Software is
19furnished to do so, subject to the following conditions:
20
21The above copyright notice and this permission notice shall be included in all
22copies or substantial portions of the Software.
23
24THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30SOFTWARE.
31*/
32
33#pragma once
34#ifdef _WIN32
35#define WIN32_LEAN_AND_MEAN // 排除不常用的 Windows 组件
36#define NOMINMAX 1 // 避免 min/max 宏污染
37#define NOGDI // 不需要图形设备接口
38#define NOUSER // 不需要窗口管理
39#define NOSERVICE // 不需要服务
40#define NOMCX // 不需要媒体中心扩展
41#define NOHELP // 不需要 WinHelp
42#define NOSOUND // 不需要声音
43#define NOCOMM // 不需要串口
44#define NOKANJI // 不需要日文
45#define NOCLIPBOARD // 不需要剪贴板
46#define NOCOLOR // 不需要颜色表
47#define NODRAWTEXT // 不需要 DrawText
48#define NOMENUS // 不需要菜单
49#define NOICONS // 不需要图标
50#define NOSYSCOMMANDS // 不需要系统命令
51#define NORASTEROPS // 不需要光栅操作
52#define NOSHOWWINDOW // 不需要 ShowWindow
53#define NOATOM // 不需要原子表
54#define NOCTLMGR // 不需要控件管理器
55#define NOMETAFILE // 不需要元文件
56#define NOOPENFILE // 不需要 OpenFile
57#define NOSCROLL // 不需要滚动条
58#define NOTEXTMETRIC // 不需要文本度量
59#define NOWH // 不需要 Windows 挂钩
60#define NOPROFILER // 不需要性能分析器
61#define NODEFERWINDOWPOS // 不需要窗口位置调整
62#include <conio.h>
63#include <windows.h>
64#else
65#include <poll.h>
66#include <termios.h>
67#include <unistd.h>
68#endif
69#include <iostream>
70
71namespace console {
76 enum class Key : int {
77 None = 0,
79
80 A = 'A',
85 F,
86 G,
87 H,
88 I,
106
107 Num0 = '0',
117
118 Space = ' ',
119
120 Enter = 13,
121 Esc = 27,
123 Tab = 9,
124
125 Up = 1000,
129
130 F1,
131 F2,
132 F3,
133 F4,
134 F5,
135 F6,
136 F7,
137 F8,
138 F9,
142 };
143
150 inline std::ostream &operator<<(std::ostream &os, Key k) {
151 if ((k >= Key::A && k <= Key::Z) || (k >= Key::Num0 && k <= Key::Num9))
152 return os << static_cast<char>(k);
153 if (k >= Key::F1 && k <= Key::F12)
154 return os << "<F"
155 << static_cast<int>(k) - static_cast<int>(Key::F1) + 1
156 << '>';
157 switch (k) {
158 case Key::Space:
159 os << "<space>";
160 break;
161 case Key::Enter:
162 os << "<enter>";
163 break;
164 case Key::Esc:
165 os << "<esc>";
166 break;
167 case Key::Backspace:
168 os << "<backspace>";
169 break;
170 case Key::Tab:
171 os << "<tab>";
172 break;
173 case Key::Up:
174 os << "<up>";
175 break;
176 case Key::Down:
177 os << "<down>";
178 break;
179 case Key::Left:
180 os << "<left>";
181 break;
182 case Key::Right:
183 os << "<right>";
184 break;
185 case Key::None:
186 os << "<none>";
187 break;
188 default:
189 os << "<unknown>";
190 break;
191 }
192 return os;
193 }
194
199 class Keyboard {
200 public:
206#ifdef _WIN32
207 hStdin = GetStdHandle(STD_INPUT_HANDLE);
208 GetConsoleMode(hStdin, &oldMode);
209 SetConsoleMode(
210 hStdin, oldMode & ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT));
211#else
212 tcgetattr(STDIN_FILENO, &oldTio);
213 struct termios newTio = oldTio;
214 newTio.c_lflag &= ~(ICANON | ECHO);
215 newTio.c_cc[VMIN] = 0;
216 newTio.c_cc[VTIME] = 0;
217 tcsetattr(STDIN_FILENO, TCSANOW, &newTio);
218#endif
219 }
220
226#ifdef _WIN32
227 SetConsoleMode(hStdin, oldMode);
228#else
229 tcsetattr(STDIN_FILENO, TCSANOW, &oldTio);
230#endif
231 }
232
234 Keyboard(const Keyboard &) = delete;
235
237 Keyboard(Keyboard &&) = delete;
238
240 Keyboard &operator=(const Keyboard &) = delete;
241
244
250 int raw = readRaw();
251 if (raw == -1) return Key::None;
252 return parse(raw);
253 }
254
260 while (true) {
261 int raw = readRawBlock();
262 if (raw != -1) return parse(raw);
263 }
264 }
265
270 void ignore(int n = -1) {
271 for (int i = 0; i != n && get() != Key::None; i++);
272 }
273
274 private:
275#ifdef _WIN32
276 HANDLE hStdin;
277 DWORD oldMode;
278#else
279 struct termios oldTio;
281#endif
282
289 int readRaw() {
290#ifdef _WIN32
291 if (_kbhit()) return _getch();
292 return -1;
293#else
294 struct pollfd pfd = {STDIN_FILENO, POLLIN, 0};
295 if (poll(&pfd, 1, 0) <= 0) return -1;
296 unsigned char c;
297 if (read(STDIN_FILENO, &c, 1) != 1) return -1;
298 return c;
299#endif
300 }
301
309#ifdef _WIN32
310 return _getch();
311#else
312 unsigned char c;
313 struct pollfd pfd = {STDIN_FILENO, POLLIN, 0};
314 while (true) {
315 if (poll(&pfd, 1, -1) > 0) {
316 if (read(STDIN_FILENO, &c, 1) == 1) return c;
317 }
318 }
319#endif
320 }
321
334 Key parse(int raw) {
335 if ((raw >= 'A' && raw <= 'Z') || (raw >= '0' && raw <= '9')) {
336 return static_cast<Key>(raw);
337 }
338 if (raw >= 'a' && raw <= 'z') {
339 return static_cast<Key>(raw - 32);
340 }
341 switch (raw) {
342 case ' ':
343 return Key::Space;
344 case 13:
345 return Key::Enter;
346 case 27:
347 return handleEscape();
348 case 8:
349 case 127:
350 return Key::Backspace;
351 case 9:
352 return Key::Tab;
353 }
354#ifdef _WIN32
355 if (raw == 0xE0 || raw == 0x00) {
356 int ext = _getch();
357 switch (ext) {
358 case 0x48:
359 return Key::Up;
360 case 0x50:
361 return Key::Down;
362 case 0x4B:
363 return Key::Left;
364 case 0x4D:
365 return Key::Right;
366 case 0x3B:
367 return Key::F1;
368 case 0x3C:
369 return Key::F2;
370 case 0x3D:
371 return Key::F3;
372 case 0x3E:
373 return Key::F4;
374 case 0x3F:
375 return Key::F5;
376 case 0x40:
377 return Key::F6;
378 case 0x41:
379 return Key::F7;
380 case 0x42:
381 return Key::F8;
382 case 0x43:
383 return Key::F9;
384 case 0x44:
385 return Key::F10;
386 case 0x85:
387 return Key::F11;
388 case 0x86:
389 return Key::F12;
390 }
391 }
392#endif
393 return Key::Unknown;
394 }
395
404#ifndef _WIN32
405 struct pollfd pfd = {STDIN_FILENO, POLLIN, 0};
406 if (poll(&pfd, 1, 5) <= 0) return Key::Esc;
407 char seq[3];
408 int n = read(STDIN_FILENO, seq, 3);
409 if (n >= 2 && seq[0] == '[') {
410 switch (seq[1]) {
411 case 'A':
412 return Key::Up;
413 case 'B':
414 return Key::Down;
415 case 'C':
416 return Key::Right;
417 case 'D':
418 return Key::Left;
419 }
420 }
421#endif
422 return Key::Esc;
423 }
424 };
425}
struct termios oldTio
原始终端I/O属性(用于析构时恢复规范模式与回显)
Definition kb.h:279
Key handleEscape()
处理以 ESC (27) 开头的转义序列(主要针对 Linux 终端)。
Definition kb.h:403
Keyboard & operator=(Keyboard &&)=delete
被删除的移动赋值
Keyboard()
构造函数,开始监视键盘键击。
Definition kb.h:205
Key wait()
等待直到键击并取得当前按键。
Definition kb.h:259
int readRaw()
读取一个原始按键值(非阻塞)。
Definition kb.h:289
Keyboard(Keyboard &&)=delete
被删除的移动构造函数
Key get()
试图取得当前键击的按键。
Definition kb.h:249
int readRawBlock()
读取一个原始按键值(阻塞)。
Definition kb.h:308
void ignore(int n=-1)
消耗留在缓冲区内的按键。
Definition kb.h:270
Key parse(int raw)
将原始扫描码解析为 Key 枚举值。
Definition kb.h:334
Keyboard(const Keyboard &)=delete
被删除的拷贝构造函数
Keyboard & operator=(const Keyboard &)=delete
被删除的拷贝赋值
~Keyboard()
析构函数,结束对键盘键击的监视。
Definition kb.h:225
本库所有组件所在的顶层命名空间。
Key
用于表示常用按键的枚举。
Definition kb.h:76
@ X
Definition kb.h:103
@ Num6
Definition kb.h:113
@ Down
Definition kb.h:126
@ C
Definition kb.h:82
@ F6
Definition kb.h:135
@ Z
Definition kb.h:105
@ Up
Definition kb.h:125
@ F5
Definition kb.h:134
@ E
Definition kb.h:84
@ P
Definition kb.h:95
@ F7
Definition kb.h:136
@ F8
Definition kb.h:137
@ Num7
Definition kb.h:114
@ F3
Definition kb.h:132
@ U
Definition kb.h:100
@ V
Definition kb.h:101
@ Y
Definition kb.h:104
@ Tab
Definition kb.h:123
@ S
Definition kb.h:98
@ W
Definition kb.h:102
@ F11
Definition kb.h:140
@ M
Definition kb.h:92
@ None
Definition kb.h:77
@ Num2
Definition kb.h:109
@ Num5
Definition kb.h:112
@ A
Definition kb.h:80
@ Num0
Definition kb.h:107
@ Unknown
Definition kb.h:78
@ F9
Definition kb.h:138
@ Num8
Definition kb.h:115
@ N
Definition kb.h:93
@ Esc
Definition kb.h:121
@ Right
Definition kb.h:128
@ Left
Definition kb.h:127
@ B
Definition kb.h:81
@ Num3
Definition kb.h:110
@ K
Definition kb.h:90
@ F10
Definition kb.h:139
@ T
Definition kb.h:99
@ Num1
Definition kb.h:108
@ Backspace
Definition kb.h:122
@ L
Definition kb.h:91
@ Space
Definition kb.h:118
@ Num9
Definition kb.h:116
@ Num4
Definition kb.h:111
@ F1
Definition kb.h:130
@ R
Definition kb.h:97
@ F4
Definition kb.h:133
@ F12
Definition kb.h:141
@ Q
Definition kb.h:96
@ Enter
Definition kb.h:120
@ O
Definition kb.h:94
@ D
Definition kb.h:83
@ F2
Definition kb.h:131
@ J
Definition kb.h:89
MultiArray< decltype(std::declval< T >()<< std::declval< U >()), Dims... > operator<<(const MultiArray< T, Dims... > &a, const MultiArray< U, Dims... > &b)
Definition multiarray.h:1607