Skip to main content

crosscurses/
lib.rs

1#![allow(non_camel_case_types, non_snake_case)]
2
3#[macro_use]
4extern crate log;
5
6extern crate libc;
7
8#[cfg(unix)]
9extern crate ncurses;
10#[cfg(windows)]
11extern crate pdcurses;
12
13use std::ffi::CString;
14use std::ptr;
15
16#[cfg(windows)]
17use pdcurses as curses;
18#[cfg(windows)]
19pub use pdcurses::{chtype, mmask_t, MEVENT, SCREEN};
20#[cfg(windows)]
21type ScrPtr = *mut SCREEN;
22#[cfg(windows)]
23type FILE = *mut curses::FILE;
24
25#[cfg(unix)]
26use ncurses::ll as curses;
27#[cfg(unix)]
28pub use ncurses::ll::{chtype, mmask_t, MEVENT, SCREEN};
29#[cfg(unix)]
30type ScrPtr = SCREEN;
31#[cfg(unix)]
32type FILE = curses::FILE_p;
33
34mod input;
35pub use self::input::*;
36
37mod attributes;
38pub use self::attributes::*;
39
40pub mod colorpair;
41pub use crate::colorpair::ColorPair;
42
43#[cfg(windows)]
44mod windows;
45#[cfg(windows)]
46pub use self::windows::constants::*;
47#[cfg(windows)]
48use self::windows as platform_specific;
49
50#[cfg(unix)]
51mod unix;
52#[cfg(unix)]
53pub use self::unix::constants::*;
54#[cfg(unix)]
55use self::unix as platform_specific;
56
57pub const OK: i32 = 0;
58pub const ERR: i32 = -1;
59
60mod window;
61pub use crate::window::Window;
62
63pub trait ToChtype {
64    fn to_chtype(&self) -> chtype;
65}
66
67impl ToChtype for char {
68    fn to_chtype(&self) -> chtype {
69        *self as chtype
70    }
71}
72
73impl 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`
80pub fn baudrate() -> i32 {
81    unsafe { curses::baudrate() }
82}
83
84/// Sounds the audible bell on the terminal, if possible; if not, it calls flash().
85pub fn beep() -> i32 {
86    unsafe { curses::beep() }
87}
88
89/// Indicates if the terminal has the capability to change the definition of its colors.
90pub 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.
100pub fn cbreak() -> i32 {
101    unsafe { curses::cbreak() }
102}
103
104/// Maximum number of colors the terminal is capable of displaying.
105pub fn COLORS() -> i32 {
106    platform_specific::_COLORS()
107}
108
109/// Maximum number of color-pairs the terminal is capable of displaying.
110pub 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 crosscurses::{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/// ```
134pub 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).
148pub 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().
154pub 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().
160pub 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.
167pub 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.
177pub 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.
183pub 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.
191pub 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().
200pub fn endwin() -> i32 {
201    unsafe { curses::endwin() }
202}
203
204/// Flashes the screen, if possible; if not, it calls beep().
205pub 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.
211pub fn flushinp() -> i32 {
212    unsafe { curses::flushinp() }
213}
214
215/// Returns the current mouse status in an MEVENT struct.
216pub 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.
224pub fn half_delay(tenths: i32) -> i32 {
225    unsafe { curses::halfdelay(tenths) }
226}
227
228/// Indicates if the terminal supports, and can maniplulate color.
229pub 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.
236pub 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/// Returns the default Window.
243pub fn stdscr() -> Window {
244    let window_pointer = platform_specific::_stdscr();
245    window::new_window(window_pointer, true)
246}
247
248/// Changes the definition of a color. It takes four arguments: the number of the color to be
249/// changed followed by three RGB values (for the amounts of red, green, and blue components).
250/// The first argument must be a legal color value; default colors are not allowed here.
251/// Each of the last three arguments must be a value in the range 0 through 1000. When `init_color`
252/// is used, all occurrences of that color on the screen immediately change to the new definition.
253pub fn init_color(color_number: i16, red: i16, green: i16, blue: i16) -> i32 {
254    unsafe { curses::init_color(color_number, red, green, blue) }
255}
256
257/// Changes the definition of a color-pair.
258///
259/// It takes three arguments: the number of the color-pair to be redefined, and the new values of
260/// the foreground and background colors. The pair number must be between 0 and `COLOR_PAIRS` - 1,
261/// inclusive. The foreground and background must be between 0 and `COLORS()` - 1, inclusive. If the
262/// color pair was previously initialized, the screen is refreshed, and all occurrences of that
263/// color-pair are changed to the new definition.
264pub fn init_pair(pair_index: i16, foreground_color: i16, background_color: i16) -> i32 {
265    unsafe { curses::init_pair(pair_index, foreground_color, background_color) as i32 }
266}
267
268/// Sets the timeout for a mouse click.
269///
270/// Sets the maximum time (in thousands of a second) that can elapse between press and release
271/// events for them to be recognized as aclick. Use mouseinterval(0) to disable click resolution.
272/// This function returns the previous interval value. Use mouseinterval(-1) to obtain the interval
273/// without altering it. The default is one sixth of a second.
274pub fn mouseinterval(interval: i32) -> i32 {
275    unsafe { curses::mouseinterval(interval) }
276}
277
278/// Set the mouse events to be reported.
279///
280/// By default, no mouse events are reported. The function will return a mask to indicate which of
281/// the specified mouse events can be reported; on complete failure it returns 0. If oldmask is
282/// non-NULL, this function fills the indicated location with the previous value of the given
283/// window's mouse event mask.
284///
285/// As a side effect, setting a zero mousemask may turn off the mouse pointer; setting a nonzero
286/// mask may turn it on. Whether this happens is device-dependent.
287pub fn mousemask(newmask: mmask_t, oldmask: *mut mmask_t) -> mmask_t {
288    unsafe { curses::mousemask(newmask, oldmask) }
289}
290
291/// Returns a character string corresponding to the key `code`.
292///
293/// * Printable characters are displayed as themselves, e.g., a one-character string containing the
294///   key.
295/// * Control characters are displayed in the ^X notation.
296/// * DEL (character 127) is displayed as ^?.
297/// * Values above 128 are either meta characters (if the screen has not been initialized, or if
298///   meta has been called with a TRUE parameter), shown in the M-X notation, or are displayed as
299///   themselves. In the latter case, the values may not be printable; this follows the X/Open
300///   specification.
301/// * Values above 256 may be the names of the names of function keys.
302/// * Otherwise (if there is no corresponding name) the function returns `None`, to denote an
303///   error. X/Open also lists an "UNKNOWN KEY" return value, which some implementations return
304///   rather than `None`.
305pub fn keyname(code: i32) -> Option<String> {
306    platform_specific::_keyname(code)
307}
308
309/// Suspends the program for the specified number of milliseconds.
310pub fn napms(ms: i32) -> i32 {
311    unsafe { curses::napms(ms) }
312}
313
314/// A program that outputs to more than one terminal should use the newterm routine for each
315/// terminal instead of initscr.
316///
317/// A program that needs to inspect capabilities, so it can continue to
318/// run in a line-oriented mode if the terminal cannot support a screen-oriented program, would also
319/// use newterm. The routine newterm should be called once for each terminal. It returns a variable
320/// of type `ScrPtr` which should be saved as a reference to that terminal.
321///
322/// (For the PDCurses backend it's just an alternative interface for initscr(). It always returns
323/// SP, or NULL.)
324pub fn newterm(t: Option<&str>, output: FILE, input: FILE) -> ScrPtr {
325    platform_specific::pre_init();
326    let term_type = t.map(|x| CString::new(x).unwrap());
327    let type_ptr = match term_type {
328        Some(ref s) => s.as_ptr(),
329        _ => std::ptr::null(),
330    };
331    unsafe { curses::newterm(type_ptr, output, input) }
332}
333
334/// Creates a new window with the given number of lines, nlines and columns, ncols.
335///
336/// The upper left corner of the window is at line begy, column begx. If nlines is zero, it
337/// defaults to LINES - begy; ncols to COLS - begx. Create a new full-screen window by calling
338/// newwin(0, 0, 0, 0).
339pub fn newwin(nlines: i32, ncols: i32, begy: i32, begx: i32) -> Window {
340    let window_pointer = unsafe { curses::newwin(nlines, ncols, begy, begx) };
341    window::new_window(window_pointer, false)
342}
343
344/// Enables the translation of a carriage return into a newline on input.
345///
346/// nonl() disables this. Initially, the translation does occur.
347pub fn nl() -> i32 {
348    unsafe { curses::nl() }
349}
350
351/// Set nocbreak mode.
352///
353/// In cbreak mode, characters typed by the user are made available immediately, and erase/kill
354/// character processing is not performed.  In nocbreak mode, typed characters are buffered until
355/// a newline or carriage return. Interrupt and flow control characters are unaffected by this
356/// mode.
357pub fn nocbreak() -> i32 {
358    unsafe { curses::nocbreak() }
359}
360
361/// Disables echoing typed characters.
362///
363/// Initially, input characters are echoed. Subsequent calls to echo() and noecho() do not flush
364/// type-ahead.
365pub fn noecho() -> i32 {
366    unsafe { curses::noecho() }
367}
368
369/// Disables the translation of a carriage return into a newline on input.
370///
371/// nl() enables this. Initially, the translation does occur.
372pub fn nonl() -> i32 {
373    unsafe { curses::nonl() }
374}
375
376/// Disable raw mode.
377///
378/// Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to
379/// the user program. The difference is that in raw mode, the INTR, QUIT, SUSP, and STOP characters
380/// are passed through without being interpreted, and without generating a signal.
381pub fn noraw() -> i32 {
382    unsafe { curses::noraw() }
383}
384
385/// Enable raw mode.
386///
387/// Raw mode is similar to cbreak mode, in that characters typed are immediately passed through to
388/// the user program. The difference is that in raw mode, the INTR, QUIT, SUSP, and STOP characters
389/// are passed through without being interpreted, and without generating a signal.
390pub fn raw() -> i32 {
391    unsafe { curses::raw() }
392}
393
394/// Restore the terminal to "program" (in curses) state. This is done
395/// automatically by endwin() and doupdate() after an endwin(), so this would normally not be
396/// called before.
397pub fn reset_prog_mode() -> i32 {
398    unsafe { curses::reset_prog_mode() }
399}
400
401/// Restore the terminal to "shell" (not in curses) state. This is done automatically by
402/// endwin() and doupdate() after an endwin(), so this would normally not be called before.
403pub fn reset_shell_mode() -> i32 {
404    unsafe { curses::reset_shell_mode() }
405}
406
407/// Attempts to resize the screen to the given size.
408///
409/// `resize_term()` is effectively two functions: When called with nonzero values for nlines and
410/// ncols, it attempts to resize the screen to the given size. When called with (0, 0), it merely
411/// adjusts the internal structures to match the current size after the screen is resized by the
412/// user. If you want to support user resizing, you should check for getch() returning `KEY_RESIZE`,
413/// and/or call `is_termresized()` at appropriate times; if either condition occurs, call
414/// `resize_term(0, 0)`. Then, with either user or programmatic resizing, you'll have to resize any
415/// windows you've created.
416pub fn resize_term(nlines: i32, ncols: i32) -> i32 {
417    platform_specific::_resize_term(nlines, ncols)
418}
419
420/// Toggles whether the `A_BLINK` attribute sets an actual blink mode (TRUE), or sets the background
421/// color to high intensity (FALSE).
422///
423/// The default is platform-dependent (FALSE in most cases). It returns OK if it could set the
424/// state to match the given parameter, ERR otherwise. Current platforms also adjust the value
425/// of COLORS() according to this function -- 16 for FALSE, and 8 for TRUE.
426/// (Only supported on Windows)
427pub fn set_blink(enabled: bool) -> i32 {
428    platform_specific::_set_blink(enabled)
429}
430
431/// Switches between different terminals.
432///
433/// The screen reference new becomes the new current terminal. The previous terminal is returned by
434/// the routine. This is the only routine which manipulates ScrPtr's; all other routines  affect
435/// only the current terminal.
436///
437/// (Does nothing meaningful in PDCurses, but is included for compatibility with other curses
438/// implementations.)
439pub fn set_term(new: ScrPtr) -> ScrPtr {
440    unsafe { curses::set_term(new) }
441}
442
443/// Sets the title of the window in which the curses program is running. This function may not do
444/// anything on some platforms. (Only supported on Windows)
445pub fn set_title(title: &str) {
446    platform_specific::_set_title(title);
447}
448
449/// Initializes eight basic colors (black, red, green, yellow, blue, magenta, cyan,
450/// and white), and two global variables accessed through `COLORS()` and `COLOR_PAIRS()` (respectively defining the
451/// maximum number of colors and color-pairs the terminal is capable of displaying).
452pub fn start_color() -> i32 {
453    unsafe { curses::start_color() as i32 }
454}
455
456/// Allows the use of -1 as a foreground or background color with `init_pair()`.
457///
458/// Calls `assume_default_colors(-1, -1);` -1 represents the foreground or background color that
459/// the terminal had at startup.
460pub fn use_default_colors() -> i32 {
461    unsafe { curses::use_default_colors() }
462}