1 #![allow(non_camel_case_types, non_snake_case)] 2 3 #[macro_use] 4 extern crate log; 5 6 extern crate libc; 7 8 #[cfg(unix)] 9 extern crate ncurses; 10 #[cfg(windows)] 11 extern crate pdcurses; 12 13 use std::ffi::CString; 14 use std::ptr; 15 16 #[cfg(windows)] 17 use pdcurses as curses; 18 #[cfg(windows)] 19 pub use pdcurses::{chtype, mmask_t, MEVENT, SCREEN}; 20 #[cfg(windows)] 21 type ScrPtr = *mut SCREEN; 22 #[cfg(windows)] 23 type FILE = *mut curses::FILE; 24 25 #[cfg(unix)] 26 use ncurses::ll as curses; 27 #[cfg(unix)] 28 pub use ncurses::ll::{chtype, mmask_t, MEVENT, SCREEN}; 29 #[cfg(unix)] 30 type ScrPtr = SCREEN; 31 #[cfg(unix)] 32 type FILE = curses::FILE_p; 33 34 mod input; 35 pub use self::input::*; 36 37 mod attributes; 38 pub use self::attributes::*; 39 40 pub mod colorpair; 41 pub use crate::colorpair::ColorPair; 42 43 #[cfg(windows)] 44 mod windows; 45 #[cfg(windows)] 46 pub use self::windows::constants::*; 47 #[cfg(windows)] 48 use self::windows as platform_specific; 49 50 #[cfg(unix)] 51 mod unix; 52 #[cfg(unix)] 53 pub use self::unix::constants::*; 54 #[cfg(unix)] 55 use self::unix as platform_specific; 56 57 pub const OK: i32 = 0; 58 pub const ERR: i32 = -1; 59 60 mod window; 61 pub use crate::window::Window; 62 63 pub trait ToChtype { 64 fn to_chtype(&self) -> chtype; 65 } 66 67 impl ToChtype for char { 68 fn to_chtype(&self) -> chtype { 69 *self as chtype 70 } 71 } 72 73 impl ToChtype for chtype { 74 fn to_chtype(&self) -> chtype { 75 *self 76 } 77 } 78 79 /// Return the output speed of the terminal. On Windows it simply returns `INT_MAX` 80 pub fn baudrate() -> i32 { 81 unsafe { curses::baudrate() } 82 } 83 84 /// Sounds the audible bell on the terminal, if possible; if not, it calls flash(). 85 pub fn beep() -> i32 { 86 unsafe { curses::beep() } 87 } 88 89 /// Indicates if the terminal has the capability to change the definition of its colors. 90 pub fn can_change_color() -> bool { 91 unsafe { curses::can_change_color() != 0 } 92 } 93 94 /// Set cbreak mode. 95 /// 96 /// In cbreak mode, characters typed by the user are made available immediately, and erase/kill 97 /// character processing is not performed. In nocbreak mode, typed characters are buffered until 98 /// a newline or carriage return. Interrupt and flow control characters are unaffected by this 99 /// mode. 100 pub fn cbreak() -> i32 { 101 unsafe { curses::cbreak() } 102 } 103 104 /// Maximum number of colors the terminal is capable of displaying. 105 pub fn COLORS() -> i32 { 106 platform_specific::_COLORS() 107 } 108 109 /// Maximum number of color-pairs the terminal is capable of displaying. 110 pub fn COLOR_PAIRS() -> i32 { 111 platform_specific::_COLOR_PAIRS() 112 } 113 114 /// This routine gives programmers a way to find the intensity of the red, green, and blue (RGB) 115 /// components in a color. It takes the color number as an argument and returns three values 116 /// that tell you the amounts of red, green, and blue components in the given color. The argument 117 /// must be a legal color value, i.e., 0 through COLORS()-1, inclusive. The values that are returned 118 /// are in the range 0 (no component) through 1000 (maximum amount of component), inclusive. 119 /// 120 /// ```rust 121 /// use pancurses::{can_change_color, color_content, endwin, init_color, initscr, start_color}; 122 /// 123 /// initscr(); 124 /// start_color(); 125 /// if can_change_color() { 126 /// init_color(8, 35, 502, 1000); 127 /// let (r, g, b) = color_content(8); 128 /// assert_eq!(35, r); 129 /// assert_eq!(502, g); 130 /// assert_eq!(1000, b); 131 /// } 132 /// endwin(); 133 /// ``` 134 pub fn color_content(color_number: i16) -> (i16, i16, i16) { 135 let mut r: i16 = 0; 136 let mut g: i16 = 0; 137 let mut b: i16 = 0; 138 unsafe { 139 curses::color_content(color_number, &mut r, &mut g, &mut b); 140 } 141 (r, g, b) 142 } 143 144 /// Alters the appearance of the cursor. 145 /// 146 /// A visibility of 0 makes it disappear; 1 makes it appear "normal" (usually an underline) and 2 147 /// makes it "highly visible" (usually a block). 148 pub fn curs_set(visibility: i32) -> i32 { 149 unsafe { curses::curs_set(visibility) } 150 } 151 152 /// Save the current terminal modes as the "program" (in curses) state for use by the 153 /// `reset_prog_mode()` and `reset_shell_mode()` functions. This is done automatically by initscr(). 154 pub fn def_prog_mode() -> i32 { 155 unsafe { curses::def_prog_mode() } 156 } 157 158 /// Save the current terminal modes as the "shell" (not in curses) state for use by the 159 /// `reset_prog_mode()` and `reset_shell_mode()` functions. This is done automatically by initscr(). 160 pub fn def_shell_mode() -> i32 { 161 unsafe { curses::def_shell_mode() } 162 } 163 164 /// Inserts an 'milliseconds' millisecond pause in output. This routine should not be used extensively 165 /// because padding characters are used rather than a CPU pause. If no padding character is 166 /// specified, this uses napms to perform the delay. 167 pub fn delay_output(milliseconds: i32) -> i32 { 168 unsafe { curses::delay_output(milliseconds) } 169 } 170 171 /// Frees storage associated with the SCREEN data structure. 172 /// 173 /// The endwin routine does not do this, so delscreen should be called after endwin if a particular 174 /// SCREEN is no longer needed. 175 /// 176 /// In PDCurses, the parameter must be the value of SP, and delscreen() sets SP to NULL. 177 pub fn delscreen(screen: ScrPtr) { 178 unsafe { curses::delscreen(screen) } 179 } 180 181 /// Compares the virtual screen to the physical screen and performs an update of the physical 182 /// screen. 183 pub fn doupdate() -> i32 { 184 unsafe { curses::doupdate() } 185 } 186 187 /// Enabled echoing typed characters. 188 /// 189 /// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush 190 /// type-ahead. 191 pub fn echo() -> i32 { 192 unsafe { curses::echo() } 193 } 194 195 /// Should be called before exiting or escaping from curses mode temporarily. 196 /// 197 /// It will restore tty modes, move the cursor to the lower left corner of the screen and reset the 198 /// terminal into the proper non-visual mode. To resume curses after a temporary escape, call 199 /// refresh() or doupdate(). 200 pub fn endwin() -> i32 { 201 unsafe { curses::endwin() } 202 } 203 204 /// Flashes the screen, if possible; if not, it calls beep(). 205 pub fn flash() -> i32 { 206 unsafe { curses::flash() } 207 } 208 209 /// Throws away any type-ahead that has been typed by the user and has not yet been read by the 210 /// program. 211 pub fn flushinp() -> i32 { 212 unsafe { curses::flushinp() } 213 } 214 215 /// Returns the current mouse status in an MEVENT struct. 216 pub fn getmouse() -> Result<MEVENT, i32> { 217 platform_specific::_getmouse() 218 } 219 220 /// Similar to cbreak(), but allows for a time limit to be specified, in tenths of a second. 221 /// 222 /// This causes getch() to block for that period before returning None if no key has been received. 223 /// tenths must be between 1 and 255. 224 pub fn half_delay(tenths: i32) -> i32 { 225 unsafe { curses::halfdelay(tenths) } 226 } 227 228 /// Indicates if the terminal supports, and can maniplulate color. 229 pub fn has_colors() -> bool { 230 unsafe { curses::has_colors() > 0 } 231 } 232 233 /// Initialize the curses system, this must be the first function that is called. 234 /// 235 /// Returns a Window struct that is used to access Window specific functions. 236 pub fn initscr() -> Window { 237 platform_specific::pre_init(); 238 let window_pointer = unsafe { curses::initscr() }; 239 window::new_window(window_pointer, true) 240 } 241 242 /// Changes the definition of a color. It takes four arguments: the number of the color to be 243 /// changed followed by three RGB values (for the amounts of red, green, and blue components). 244 /// The first argument must be a legal color value; default colors are not allowed here. 245 /// Each of the last three arguments must be a value in the range 0 through 1000. When `init_color` 246 /// is used, all occurrences of that color on the screen immediately change to the new definition. 247 pub fn init_color(color_number: i16, red: i16, green: i16, blue: i16) -> i32 { 248 unsafe { curses::init_color(color_number, red, green, blue) } 249 } 250 251 /// Changes the definition of a color-pair. 252 /// 253 /// It takes three arguments: the number of the color-pair to be redefined, and the new values of 254 /// the foreground and background colors. The pair number must be between 0 and `COLOR_PAIRS` - 1, 255 /// inclusive. The foreground and background must be between 0 and `COLORS()` - 1, inclusive. If the 256 /// color pair was previously initialized, the screen is refreshed, and all occurrences of that 257 /// color-pair are changed to the new definition. 258 pub fn init_pair(pair_index: i16, foreground_color: i16, background_color: i16) -> i32 { 259 unsafe { curses::init_pair(pair_index, foreground_color, background_color) as i32 } 260 } 261 262 /// Sets the timeout for a mouse click. 263 /// 264 /// Sets the maximum time (in thousands of a second) that can elapse between press and release 265 /// events for them to be recognized as aclick. Use mouseinterval(0) to disable click resolution. 266 /// This function returns the previous interval value. Use mouseinterval(-1) to obtain the interval 267 /// without altering it. The default is one sixth of a second. 268 pub fn mouseinterval(interval: i32) -> i32 { 269 unsafe { curses::mouseinterval(interval) } 270 } 271 272 /// Set the mouse events to be reported. 273 /// 274 /// By default, no mouse events are reported. The function will return a mask to indicate which of 275 /// the specified mouse events can be reported; on complete failure it returns 0. If oldmask is 276 /// non-NULL, this function fills the indicated location with the previous value of the given 277 /// window's mouse event mask. 278 /// 279 /// As a side effect, setting a zero mousemask may turn off the mouse pointer; setting a nonzero 280 /// mask may turn it on. Whether this happens is device-dependent. 281 pub fn mousemask(newmask: mmask_t, oldmask: Option<&mut mmask_t>) -> mmask_t { 282 let oldmask_ptr = oldmask.map(|x| x as *mut _).unwrap_or(std::ptr::null_mut()); 283 unsafe { curses::mousemask(newmask, oldmask_ptr) } 284 } 285 286 /// Returns a character string corresponding to the key `code`. 287 /// 288 /// * Printable characters are displayed as themselves, e.g., a one-character string containing the 289 /// key. 290 /// * Control characters are displayed in the ^X notation. 291 /// * DEL (character 127) is displayed as ^?. 292 /// * Values above 128 are either meta characters (if the screen has not been initialized, or if 293 /// meta has been called with a TRUE parameter), shown in the M-X notation, or are displayed as 294 /// themselves. In the latter case, the values may not be printable; this follows the X/Open 295 /// specification. 296 /// * Values above 256 may be the names of the names of function keys. 297 /// * Otherwise (if there is no corresponding name) the function returns `None`, to denote an 298 /// error. X/Open also lists an "UNKNOWN KEY" return value, which some implementations return 299 /// rather than `None`. 300 pub fn keyname(code: i32) -> Option<String> { 301 platform_specific::_keyname(code) 302 } 303 304 /// Suspends the program for the specified number of milliseconds. 305 pub fn napms(ms: i32) -> i32 { 306 unsafe { curses::napms(ms) } 307 } 308 309 /// A program that outputs to more than one terminal should use the newterm routine for each 310 /// terminal instead of initscr. 311 /// 312 /// A program that needs to inspect capabilities, so it can continue to 313 /// run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also 314 /// use newterm. The routine newterm should be called once for each terminal. It returns a variable 315 /// of type `ScrPtr` which should be saved as a reference to that terminal. 316 /// 317 /// (For the PDCurses backend it's just an alternative interface for initscr(). It always returns 318 /// SP, or NULL.) 319 pub fn newterm(t: Option<&str>, output: FILE, input: FILE) -> ScrPtr { 320 let term_type = t.map(|x| CString::new(x).unwrap()); 321 let type_ptr = match term_type { 322 Some(ref s) => s.as_ptr(), 323 _ => std::ptr::null(), 324 }; 325 unsafe { curses::newterm(type_ptr, output, input) } 326 } 327 328 /// Creates a new window with the given number of lines, nlines and columns, ncols. 329 /// 330 /// The upper left corner of the window is at line begy, column begx. If nlines is zero, it 331 /// defaults to LINES - begy; ncols to COLS - begx. Create a new full-screen window by calling 332 /// newwin(0, 0, 0, 0). 333 pub fn newwin(nlines: i32, ncols: i32, begy: i32, begx: i32) -> Window { 334 let window_pointer = unsafe { curses::newwin(nlines, ncols, begy, begx) }; 335 window::new_window(window_pointer, false) 336 } 337 338 /// Enables the translation of a carriage return into a newline on input. 339 /// 340 /// nonl() disables this. Initially, the translation does occur. 341 pub fn nl() -> i32 { 342 unsafe { curses::nl() } 343 } 344 345 /// Set nocbreak mode. 346 /// 347 /// In cbreak mode, characters typed by the user are made available immediately, and erase/kill 348 /// character processing is not performed. In nocbreak mode, typed characters are buffered until 349 /// a newline or carriage return. Interrupt and flow control characters are unaffected by this 350 /// mode. 351 pub fn nocbreak() -> i32 { 352 unsafe { curses::nocbreak() } 353 } 354 355 /// Disables echoing typed characters. 356 /// 357 /// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush 358 /// type-ahead. 359 pub fn noecho() -> i32 { 360 unsafe { curses::noecho() } 361 } 362 363 /// Disables the translation of a carriage return into a newline on input. 364 /// 365 /// nl() enables this. Initially, the translation does occur. 366 pub fn nonl() -> i32 { 367 unsafe { curses::nonl() } 368 } 369 370 /// Disable raw mode. 371 /// 372 /// Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to 373 /// the user program. The difference is that in raw mode, the INTR, QUIT, SUSP, and STOP characters 374 /// are passed through without being interpreted, and without generating a signal. 375 pub fn noraw() -> i32 { 376 unsafe { curses::noraw() } 377 } 378 379 /// Enable raw mode. 380 /// 381 /// Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to 382 /// the user program. The difference is that in raw mode, the INTR, QUIT, SUSP, and STOP characters 383 /// are passed through without being interpreted, and without generating a signal. 384 pub fn raw() -> i32 { 385 unsafe { curses::raw() } 386 } 387 388 /// Restore the terminal to "program" (in curses) state. This is done 389 /// automatically by endwin() and doupdate() after an endwin(), so this would normally not be 390 /// called before. 391 pub fn reset_prog_mode() -> i32 { 392 unsafe { curses::reset_prog_mode() } 393 } 394 395 /// Restore the terminal to "shell" (not in curses) state. This is done automatically by 396 /// endwin() and doupdate() after an endwin(), so this would normally not be called before. 397 pub fn reset_shell_mode() -> i32 { 398 unsafe { curses::reset_shell_mode() } 399 } 400 401 /// Attempts to resize the screen to the given size. 402 /// 403 /// `resize_term()` is effectively two functions: When called with nonzero values for nlines and 404 /// ncols, it attempts to resize the screen to the given size. When called with (0, 0), it merely 405 /// adjusts the internal structures to match the current size after the screen is resized by the 406 /// user. If you want to support user resizing, you should check for getch() returning `KEY_RESIZE`, 407 /// and/or call `is_termresized()` at appropriate times; if either condition occurs, call 408 /// `resize_term(0, 0)`. Then, with either user or programmatic resizing, you'll have to resize any 409 /// windows you've created. 410 pub fn resize_term(nlines: i32, ncols: i32) -> i32 { 411 platform_specific::_resize_term(nlines, ncols) 412 } 413 414 /// Toggles whether the `A_BLINK` attribute sets an actual blink mode (TRUE), or sets the background 415 /// color to high intensity (FALSE). 416 /// 417 /// The default is platform-dependent (FALSE in most cases). It returns OK if it could set the 418 /// state to match the given parameter, ERR otherwise. Current platforms also adjust the value 419 /// of COLORS() according to this function -- 16 for FALSE, and 8 for TRUE. 420 /// (Only supported on Windows) 421 pub fn set_blink(enabled: bool) -> i32 { 422 platform_specific::_set_blink(enabled) 423 } 424 425 /// Switches between different terminals. 426 /// 427 /// The screen reference new becomes the new current terminal. The previous terminal is returned by 428 /// the routine. This is the only routine which manipulates ScrPtr's; all other routines affect 429 /// only the current terminal. 430 /// 431 /// (Does nothing meaningful in PDCurses, but is included for compatibility with other curses 432 /// implementations.) 433 pub fn set_term(new: ScrPtr) -> ScrPtr { 434 unsafe { curses::set_term(new) } 435 } 436 437 /// Sets the title of the window in which the curses program is running. This function may not do 438 /// anything on some platforms. (Only supported on Windows) 439 pub fn set_title(title: &str) { 440 platform_specific::_set_title(title); 441 } 442 443 /// Initializes eight basic colors (black, red, green, yellow, blue, magenta, cyan, 444 /// and white), and two global variables accessed through `COLORS()` and `COLOR_PAIRS()` (respectively defining the 445 /// maximum number of colors and color-pairs the terminal is capable of displaying). 446 pub fn start_color() -> i32 { 447 unsafe { curses::start_color() as i32 } 448 } 449 450 /// Allows the use of -1 as a foreground or background color with `init_pair()`. 451 /// 452 /// Calls `assume_default_colors(-1, -1);` -1 represents the foreground or background color that 453 /// the terminal had at startup. 454 pub fn use_default_colors() -> i32 { 455 unsafe { curses::use_default_colors() } 456 } 457