pocketpy/src/modules/conio.c
2025-07-01 15:13:46 +08:00

129 lines
2.6 KiB
C

#include "pocketpy/pocketpy.h"
#if PY_SYS_PLATFORM == 0
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <conio.h>
#elif PY_SYS_PLATFORM == 3 || PY_SYS_PLATFORM == 5
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <fcntl.h>
#include <string.h>
// 保存原始终端设置
static struct termios orig_termios;
static bool orig_termios_set;
// 还原终端设置
static void reset_terminal_mode() { tcsetattr(0, TCSANOW, &orig_termios); }
// 设置终端为非阻塞模式
static void set_conio_terminal_mode_if_needed() {
if(orig_termios_set) return;
struct termios new_termios;
// 获取当前终端设置
tcgetattr(0, &orig_termios);
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
// 禁用缓冲和回显
new_termios.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0, TCSANOW, &new_termios);
atexit(reset_terminal_mode);
orig_termios_set = true;
}
// 检查是否有按键按下
int _kbhit() {
set_conio_terminal_mode_if_needed();
struct termios term;
int oldf;
int ch;
int old_flags;
// 获取终端设置
tcgetattr(0, &term);
oldf = term.c_lflag;
term.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0, TCSANOW, &term);
// 设置文件描述符为非阻塞
old_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, old_flags | O_NONBLOCK);
// 检查是否有输入
ch = getchar();
// 还原文件描述符设置
fcntl(STDIN_FILENO, F_SETFL, old_flags);
// 还原终端设置
term.c_lflag = oldf;
tcsetattr(0, TCSANOW, &term);
if(ch != EOF) {
ungetc(ch, stdin);
return 1;
}
return 0;
}
// 获取一个字符
int _getch() {
set_conio_terminal_mode_if_needed();
int ch;
struct termios oldt, newt;
// 获取当前终端设置
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
// 禁用缓冲和回显
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
// 读取字符
ch = getchar();
// 还原终端设置
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
#endif
#if PK_IS_DESKTOP_PLATFORM && PK_ENABLE_OS
static bool conio_kbhit(int argc, py_Ref argv) {
PY_CHECK_ARGC(0);
int ret = _kbhit();
py_newint(py_retval(), ret);
return true;
}
static bool conio_getch(int argc, py_Ref argv) {
PY_CHECK_ARGC(0);
int ret = _getch();
py_newint(py_retval(), ret);
return true;
}
void pk__add_module_conio() {
py_Ref mod = py_newmodule("conio");
py_bindfunc(mod, "_kbhit", conio_kbhit);
py_bindfunc(mod, "_getch", conio_getch);
}
#else
void pk__add_module_conio() {}
#endif