X Tutup
#include "Key.h" #include "UnicodeUtil.h" #if _WIN32 || _WIN64 #define WINDOWS 1 #include #else #include #include #include #endif namespace MiniScript { SimpleVector inputBuffer; ValueDict& KeyDefaultScanMap() { static ValueDict scanMap; if (scanMap.Count() == 0) { #if WINDOWS scanMap.SetValue(83, "\x7F"); // delete scanMap.SetValue(72, "\x13"); // up scanMap.SetValue(80, "\x14"); // down scanMap.SetValue(77, "\x12"); // right scanMap.SetValue(75, "\x11"); // left scanMap.SetValue(71, "\x01"); // home scanMap.SetValue(79, "\x05"); // end #else scanMap.SetValue("\x7F", "\x08"); // backspace scanMap.SetValue("\x1B[3~", "\x7F"); // delete scanMap.SetValue("\x1B[A", "\x13"); // up scanMap.SetValue("\x1B[B", "\x14"); // down scanMap.SetValue("\x1B[C", "\x12"); // right scanMap.SetValue("\x1B[D", "\x11"); // left scanMap.SetValue("\x1B[H", "\x01"); // home scanMap.SetValue("\x1B[F", "\x05"); // end #endif } return scanMap; } void KeyOptimizeScanMap(ValueDict& scanMap) { for (ValueDictIterator kv = scanMap.GetIterator(); !kv.Done(); kv.Next()) { Value k = kv.Key(); Value v = kv.Value(); if (k.type == ValueType::Number) { ValueList optimizedKey; optimizedKey.Add(Value::zero); optimizedKey.Add(k); scanMap.SetValue(optimizedKey, v); } else if (k.type == ValueType::String) { String kStr(k.ToString()); if (kStr.Length() == 0) continue; String first(kStr.Substring(0, 1)); String rest(kStr.Substring(1)); ValueList optimizedKey; optimizedKey.Add(UTF8Decode((unsigned char *)first.c_str())); optimizedKey.Add(Value::zero); if (rest.Length() == 0) { scanMap.SetValue(optimizedKey, v); } else { Value subV = scanMap.Lookup(optimizedKey, Value::null); if (subV.IsNull() || subV.type != ValueType::Map) { ValueDict d; scanMap.SetValue(optimizedKey, d); } ValueDict sub = scanMap.Lookup(optimizedKey, Value::null).GetDict(); sub.SetValue(rest, v); KeyOptimizeScanMap(sub); } } } } // Helper function to read all available characters from STDIN into the global input buffer. void slurpStdin() { #if WINDOWS while (_kbhit()) { struct InputBufferEntry e = {0, 0}; e.c = _getwch(); if (e.c == 0 || e.c == 0xE0) { e.c = 0; e.scanCode = _getwch(); } inputBuffer.push_back(e); } #else // Make terminal reads non-blocking struct termios ttystate, backUp; if (tcgetattr(STDIN_FILENO, &ttystate) < 0) return; memcpy(&backUp, &ttystate, sizeof(ttystate)); ttystate.c_lflag &= ~ICANON; ttystate.c_cc[VMIN] = 0; ttystate.c_cc[VTIME] = 0; if (tcsetattr(STDIN_FILENO, TCSANOW, &ttystate) < 0) return; unsigned char buf[5] = {0, 0, 0, 0, 0}; unsigned char *p = buf; while (true) { // Check if there are some key presses fd_set fds; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; if (select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &tv) < 0) break; if (!FD_ISSET(STDIN_FILENO, &fds)) { // Nothing's left to slurp ; save to the input buffer a current unsaved character if (p > buf) { struct InputBufferEntry e = {0, 0}; e.c = UTF8Decode(buf); inputBuffer.push_back(e); } break; } // Read one byte from STDIN if (read(STDIN_FILENO, p, 1) < 1) break; if (p > buf && !IsUTF8IntraChar(*p)) { // A new character has begun under `p`, save the previous one to the input buffer and continue slurping struct InputBufferEntry e = {0, 0}; e.c = UTF8Decode(buf); inputBuffer.push_back(e); buf[0] = *p; buf[1] = 0; buf[2] = 0; buf[3] = 0; buf[4] = 0; p = buf; } p++; } // Restore terminal tcsetattr(STDIN_FILENO, TCSANOW, &backUp); #endif } Value KeyAvailable() { slurpStdin(); return Value::Truth(inputBuffer.size() > 0); } Value KeyGet(ValueDict& scanMap) { slurpStdin(); if (inputBuffer.size() == 0) return Value::null; struct InputBufferEntry e = inputBuffer[0]; struct InputBufferEntry initialE = e; inputBuffer.deleteIdx(0); int nScanned = 0; while (true) { ValueList optimizedKey; optimizedKey.Add(e.c); optimizedKey.Add(e.scanCode); Value foundVal = scanMap.Lookup(optimizedKey, Value::null); if (foundVal.IsNull()) break; if (foundVal.type == ValueType::String) { for (int i=0; i"; } else { unsigned char buf[5] = {0, 0, 0, 0, 0}; long nBytes = UTF8Encode(initialE.c, buf); s = String((char *)buf, nBytes); } Value v(s); return v; } void KeyPutCodepoint(long codepoint, bool inFront) { struct InputBufferEntry e = {0, 0}; e.c = codepoint; if (inFront) { inputBuffer.insert(e, 0); } else { inputBuffer.push_back(e); } } void KeyPutString(String s, bool inFront) { if (inFront) { for (int i=s.Length()-1; i>=0; i--) { struct InputBufferEntry e = {0, 0}; String character = s.Substring(i, 1); e.c = UTF8Decode((unsigned char *)character.c_str()); inputBuffer.insert(e, 0); } } else { for (int i=0; i
X Tutup