conio.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #include "pocketpy/pocketpy.h"
  2. #include <stdlib.h>
  3. #if PY_SYS_PLATFORM == 0
  4. #define WIN32_LEAN_AND_MEAN
  5. #include <windows.h>
  6. #include <conio.h>
  7. #elif PY_SYS_PLATFORM == 3 || PY_SYS_PLATFORM == 5
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <termios.h>
  11. #include <fcntl.h>
  12. #include <string.h>
  13. // 保存原始终端设置
  14. static struct termios orig_termios;
  15. static bool orig_termios_set;
  16. // 还原终端设置
  17. static void reset_terminal_mode() { tcsetattr(0, TCSANOW, &orig_termios); }
  18. // 设置终端为非阻塞模式
  19. static void set_conio_terminal_mode_if_needed() {
  20. if(orig_termios_set) return;
  21. struct termios new_termios;
  22. // 获取当前终端设置
  23. tcgetattr(0, &orig_termios);
  24. memcpy(&new_termios, &orig_termios, sizeof(new_termios));
  25. // 禁用缓冲和回显
  26. new_termios.c_lflag &= ~(ICANON | ECHO);
  27. tcsetattr(0, TCSANOW, &new_termios);
  28. atexit(reset_terminal_mode);
  29. orig_termios_set = true;
  30. }
  31. // 检查是否有按键按下
  32. int _kbhit() {
  33. set_conio_terminal_mode_if_needed();
  34. struct termios term;
  35. int oldf;
  36. int ch;
  37. int old_flags;
  38. // 获取终端设置
  39. tcgetattr(0, &term);
  40. oldf = term.c_lflag;
  41. term.c_lflag &= ~(ICANON | ECHO);
  42. tcsetattr(0, TCSANOW, &term);
  43. // 设置文件描述符为非阻塞
  44. old_flags = fcntl(STDIN_FILENO, F_GETFL, 0);
  45. fcntl(STDIN_FILENO, F_SETFL, old_flags | O_NONBLOCK);
  46. // 检查是否有输入
  47. ch = getchar();
  48. // 还原文件描述符设置
  49. fcntl(STDIN_FILENO, F_SETFL, old_flags);
  50. // 还原终端设置
  51. term.c_lflag = oldf;
  52. tcsetattr(0, TCSANOW, &term);
  53. if(ch != EOF) {
  54. ungetc(ch, stdin);
  55. return 1;
  56. }
  57. return 0;
  58. }
  59. // 获取一个字符
  60. int _getch() {
  61. set_conio_terminal_mode_if_needed();
  62. int ch;
  63. struct termios oldt, newt;
  64. // 获取当前终端设置
  65. tcgetattr(STDIN_FILENO, &oldt);
  66. newt = oldt;
  67. // 禁用缓冲和回显
  68. newt.c_lflag &= ~(ICANON | ECHO);
  69. tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  70. // 读取字符
  71. ch = getchar();
  72. // 还原终端设置
  73. tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  74. return ch;
  75. }
  76. #endif
  77. #if PK_IS_DESKTOP_PLATFORM && PK_ENABLE_OS
  78. static bool conio_kbhit(int argc, py_Ref argv) {
  79. PY_CHECK_ARGC(0);
  80. int ret = _kbhit();
  81. py_newint(py_retval(), ret);
  82. return true;
  83. }
  84. static bool conio_getch(int argc, py_Ref argv) {
  85. PY_CHECK_ARGC(0);
  86. int ret = _getch();
  87. py_newint(py_retval(), ret);
  88. return true;
  89. }
  90. void pk__add_module_conio() {
  91. py_Ref mod = py_newmodule("conio");
  92. py_bindfunc(mod, "_kbhit", conio_kbhit);
  93. py_bindfunc(mod, "_getch", conio_getch);
  94. }
  95. #else
  96. void pk__add_module_conio() {}
  97. #endif