Skip to content

Instantly share code, notes, and snippets.

@erica
Created December 31, 2019 16:49
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save erica/f04940df22102b4dd677ffb1b7158984 to your computer and use it in GitHub Desktop.
Save erica/f04940df22102b4dd677ffb1b7158984 to your computer and use it in GitHub Desktop.
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)
}
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