Created
December 31, 2019 16:49
-
-
Save erica/f04940df22102b4dd677ffb1b7158984 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
do { | |
// Note: scalar.utf8 is only available in 10.15 | |
while let byte = try RawMode.getByte() { | |
let scalar = UnicodeScalar(byte) | |
switch scalar.isASCII { | |
case true: | |
print(Character(UnicodeScalar(byte)), ":", byte) | |
case false: | |
print(scalar.escaped(asASCII: true), ":", byte) | |
} | |
} | |
} catch RawMode.State.eof { | |
print("\n" + "eof") // ^D | |
RawMode.disableRawMode(fileHandle: FileHandle.standardInput) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
import Darwin | |
/// Raw mode handling for character-by-character input in term | |
public enum RawMode { | |
/// Error states for raw mode entry | |
public enum State: Error { | |
case eof | |
} | |
/// Enable raw mode for user input | |
public static func enableRawMode(fileHandle: FileHandle) -> termios { | |
let pointer = UnsafeMutablePointer<termios>.allocate(capacity: 1); defer { pointer.deallocate() } | |
var raw = pointer.pointee | |
tcgetattr(fileHandle.fileDescriptor, &raw) | |
let original = raw | |
raw.c_lflag &= ~(UInt(ECHO | ICANON)) | |
tcsetattr(fileHandle.fileDescriptor, TCSAFLUSH, &raw) | |
return original | |
} | |
/// Disable raw mode for user input | |
public static func disableRawMode(fileHandle: FileHandle) { | |
guard var term = term else { return } | |
tcsetattr(fileHandle.fileDescriptor, TCSAFLUSH, &term); | |
self.term = nil | |
} | |
/// The current termios | |
private static var term: termios? | |
/// Fetches a `UInt8` byte at a time. | |
/// | |
/// Will establish a new termios instance if one is not already available. | |
/// | |
/// - Returns: A single `UInt8` if available, otherwise `nil` | |
/// - Throws: `State.eof` on receiving ^D | |
public static func getByte() throws -> UInt8? { | |
if nil == term { | |
term = enableRawMode(fileHandle: FileHandle.standardInput) | |
} | |
var byte: UInt8 = 0 | |
guard read(FileHandle.standardInput.fileDescriptor, &byte, 1) == 1 else { return nil } | |
if byte == 0x04 { throw State.eof } | |
return byte | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment