pancurses is a curses library for Rust that supports both Linux and Windows

by abstracting away the backend that it uses

pancurses

(ncurses-rs and pdcurses-sys respectively).

The aim is to provide a more Rustic interface over the usual curses functions for ease of use while remaining close enough to curses to make porting easy.

Documentation

Requirements

Linux

ncurses-rs links with the native ncurses library so that needs to be installed so that the linker can find it.

Check ncurses-rs for more details.

Windows

pdcurses-sys compiles the native PDCurses library as part of the build process, so you need to have a compatible C compiler available that matches the ABI of the version of Rust you're using (so either gcc for the GNU ABI or cl for MSVC)

Check pdcurses-sys for more details.

Usage

Cargo.toml

[dependencies]
pancurses = "0.16"

main.rs

extern crate pancurses;

use pancurses::{initscr, endwin};

fn main() {
  let window = initscr();
  window.printw("Hello Rust");
  window.refresh();
  window.getch();
  endwin();
}

Pattern matching with getch()

extern crate pancurses;

use pancurses::{initscr, endwin, Input, noecho};

fn main() {
  let window = initscr();
  window.printw("Type things, press delete to quit\n");
  window.refresh();
  window.keypad(true);
  noecho();
  loop {
      match window.getch() {
          Some(Input::Character(c)) => { window.addch(c); },
          Some(Input::KeyDC) => break,
          Some(input) => { window.addstr(&format!("{:?}", input)); },
          None => ()
      }
  }
  endwin();
}

Handling mouse input

To receive mouse events you need to both enable keypad mode and set a mouse mask that corresponds to the events you are interested in. Mouse events are received in the same way as keyboard events, ie. by calling getch().

extern crate pancurses;

use pancurses::{ALL_MOUSE_EVENTS, endwin, getmouse, initscr, mousemask, Input};

fn main() {
    let window = initscr();

    window.keypad(true); // Set keypad mode
    mousemask(ALL_MOUSE_EVENTS, std::ptr::null_mut()); // Listen to all mouse events

    window.printw("Click in the terminal, press q to exit\n");
    window.refresh();

    loop {
        match window.getch() {
            Some(Input::KeyMouse) => {
                if let Ok(mouse_event) = getmouse() {
                    window.mvprintw(1, 0,
                                    &format!("Mouse at {},{}", mouse_event.x, mouse_event.y),
                    );
                };
            }
            Some(Input::Character(x)) if x == 'q' => break,
            _ => (),
        }
    }
    endwin();
}

You can also receive events for the mouse simply moving (as long as the terminal you're running on supports it) by also specifying the REPORT_MOUSE_POSITION flag:

mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, std::ptr::null_mut());

Terminal resizing

Whenever the terminal is resized by the user a Input::KeyResize event is raised. You should handle this by calling resize_term(0, 0) to have curses adjust it's internal structures to match the new size.

PDCurses (Windows) details

pdcurses-sys supports two flavors of PDCurses, win32a and win32. win32a is the GDI mode while win32 runs in the Windows console. win32a has better support for colors and text effects.

By default the win32a flavor is used, but you can specify which one you want to use by using Cargo flags. Simply specify the feature in Cargo.toml like so:

[dependencies.pancurses]
version = "0.16"
features = ["win32a"]

or

[dependencies.pancurses]
version = "0.16"
features = ["win32"]

(Font, Paste) menu

PDCurses win32a has a menu that allows you to change the font and paste text into the window. pancurses disables the window by default, though the user can still right-click the title bar to access it. If you want to retain the PDCurses default behaviour of having the menu there set the feature "show_menu".

Resizing

On win32a the default is to allow the user to freely resize the window. If you wish to disable resizing set the feature "disable_resize"

License

Licensed under the MIT license, see LICENSE.md

Issues

Collection of the latest Issues

file-acomplaint

file-acomplaint

0

The Example for Mouse Input throws

error[E0308]: mismatched types --> src/main.rs:9:33 expected enum Option, found *-ptr

note: expected enum Option<&mut u32> found raw pointer *mut _

on version 17.0. Sadly I couldn't find a fix myself.

alexanderkjall

alexanderkjall

0

Hi

I did some fuzzing of display of untrusted strings in cursive that uses this library and found this crash:

It seems to be because the library uses this construct CString::new(string.as_ref()).unwrap(); which fails on some strings, for example a string created like this:

As far as I can find there is 8 different cases of this pattern.

GOKOP

GOKOP

3

So basically I want to create a window border with the character. I've read in old issues here that addch() doesn't work because it calls a non-wide char using function in the backend so I guess it's the same for border(). Does that mean I have to print the border tediously using addstr() or is there a better way?

And to make it more of an issue and less of a support question, I'm not sure if ncurses and pdcurses have wide char border functions but since Rust is so unicode-oriented I guess pancurses should call wide functions whenever possible

polyrtm

polyrtm

0

Is there currently a way to disable wrapping lines in pancurses? Normal curses has it in the form of add_wchstr, but there doesn't seem to be any parallel in pancurses.

kpcyrd

kpcyrd

2

During some tests my program segfaulted and the backtrace was indicating a crash in the way pancurses uses libncursesw.

The segfault is due to a read from an invalid pointer:

Backtrace:

ghost

ghost

2

Hi, thanks for the library.

When I press backspace, the match arm for KeyBackspace is skipped over and instead a match is found for Character('\u{7f}').

I did some research and tried running in raw mode, but there was no change in behavior.

bollian

bollian

3

The pancurses::mousemask accepts a mutable pointer as a second argument and proceeds to pass this to an unsafe FFI. Part of the point of a library around an FFI is to allow the Rust programmer to work without unsafe features, like pointers.

With this in mind, I was wondering if there was a reason that mousemask didn't just accept an Option<&mut mmask_t> for its second argument. This solves both requirements of the pointer API, in that you have to be able to pass a "nonexistent" option (null pointer) or a reference to a modifiable mmask_t. The advantage is that you no longer risk passing a non-null pointer that doesn't reference valid memory.

In fact, if I'm reading this correctly, the Option version of the interface could even be used in the extern function declaration, though that's outside the scope of this library.

remexre

remexre

2

Is it sound to make Window impl Send? Right now, I'm trying to make an ncurses-based UI that is a futures::Sink, but all useful tokio operations require Sink: Send.

loovjo

loovjo

1

As per the title.

For example, the following code segfaults:

extern crate pancurses;
use pancurses::noecho;
fn main() {
    noecho();
}

This should at least be documented, if not fixed as segfaults in Rust are very rare and don't provide much insight into where the error is.

gyscos

gyscos

0
  • ncurses provides the stdscr() -> WINDOW method
  • pdcurses-sys provides a pub static mut stdscr: *mut WINDOW;

Without this, it appears difficult to use pancurses::newterm(), since it doesn't return a Window.

saethlin

saethlin

7

It looks to me like ncurses-sys and pdcurses-sys both have unicode support, but I can't figure out how to enable it here. Is this a planned feature?

Versions

Find the latest versions by id

v0.17.0 - Sep 29, 2021

  • Updated ncurses-rs to 5.101.0 (#60, #83)
  • Cleanup Window::drop() (#61)
  • Expose Window::resize() (#65)
  • Fix Unix A_CHARTEXT constant (#67)
  • Rust 2018 edition compatibility (#69)
  • Use slice::iter instead of into_iter to avoid future breakage (#70)
  • Use setlocale from libc rather than ncurses-rs (#78)
  • Fix warnings and lints (#81)
  • Make compatible with ncurses-rs NetBSD fixes (#82)

v0.16.1 - Dec 26, 2018

  • Fixed an issue on windows, using the wrong min function (#49)
  • Rename bgkdset() -> bkgdset() to be consistent with bkgd() (#52)
  • Remove try! so example compiles with 2018 edition (#55)
  • Fix Window::mouse_trafo's implementation (#56)
  • Make Window::mouse_trafo take an immutable &self (#59)

v0.16.0 - Jun 09, 2018

  • Make the various window string methods generic on AsRef (#39)
  • Fixed registry permissions (#45)
  • Fixed missing log crate when using the win32 feature (#46)

v0.15.0 - Feb 25, 2018

  • Improved input handling, pancurses supports UTF-16 input on Windows and UTF-8 on Linux.
  • Numpad keys are now converted consistently between platforms.
  • Added raw() and noraw().

v0.14.0 - Jan 20, 2018

  • Merged pull requests #24, #27, #30 and #31
  • Added insdelln() and insertln()
  • Tidied up the code

v0.13.0 - Nov 18, 2017

  • Mouse event constants are now exported allowing easier handling of mouse events
  • Added mouseinterval(), enclose() and mouse_trafo() (#18)
  • Use pdcurses-sys 0.7 adding support for the win32 flavor of PDCurses
  • Enable resizing win32a windows by default (#20)
  • Disable the Font menu on win32 by default (#17)

v0.12.0 - Nov 04, 2017

  • Implement Drop for Window (#19)
  • Added is_linetouched(), is_touched(), touch(), touchline(), touchln(), untouch(), dupwin(), mvderwin() and mvwin()
  • Fix typo in pancurses::set_blink documentation (#21)
  • pdcurses-sys 0.6

v0.11.0 - Sep 18, 2017

  • Updated pdcurses-sys dependency to 0.5 (related to #13)
  • Added ACS box char aliases (ACS_BSSB etc.)

0.10.0 - Sep 17, 2017

Issue #10: Added ACS characters Issue #15: Added insch() and mvinsch()

0.9.0 - Jul 24, 2017

Issue #11 : COLORS() and COLOR_PAIRS() now available Issue #12 : newterm(), set_term() and delscreen() implemented Issue #14 : echo() implemented

0.8.0 - Mar 05, 2017

  • Added doupdate(), noutrefresh(), delay_output()
  • There is now an Attribute enum and a ColorPair struct that should make working with attributes and color pairs easier. This is the first step towards deprecating the 'chtype' based API in favour of a more strongly typed one. Attributes and ColorPairs support the | and ^ operators, at least for now, so that they work as a drop-in replacement for chtypes.

0.7.0 - Oct 22, 2016

  • attrget(), baudrate(), beep(), bgkdset(), can_change_color(), chgat(), clrtobot(), clrtoeol(), color_content(), color_set(), copywin(), def_prog_mode(), def_shell_mode(), delwin(), flash(), getbkgd(), init_color, mvchgat(), overlay(), overwrite(), reset_prog_mode(), reset_shell_mode()
  • Input derives Eq and Hash

0.6.0 - Oct 12, 2016

Proper handling of unicode on Linux (enable the wide feature for ncurses and call setlocale before initscr()).

0.5.0 - Oct 11, 2016

Added get_cur_x(), get_cur_y(), get_cur_yx(), border(), delch(), deleteln(), hline() and vline()

0.4.1 - Oct 11, 2016

Fixed a panic that was caused by certain key combinations.

0.4.0 - Oct 10, 2016

Mouse handling, addnstr, attroff, mvaddnstr, mvprintw, clearok, scrollok, setscrreg, set_title (PDCurses only), set_blink (PDCurses only).

The 'newtest' PDCurses example is ported, though lacking some PDCurses-specific bits.

0.3.0 - Mar 31, 2016

The newdemo example has been implemented and all the functions it requires a long with it.

0.2.0 - Mar 25, 2016

A much improved getch(), it now returns an Option instead of just an integer. The Input enum makes it easy to pattern match the return value to determine if it was a character or a special key. Support for the rain example.

0.1.0 - Mar 20, 2016

Information - Updated Apr 16, 2022

Stars: 341
Forks: 33
Issues: 22

Repositories & Extras

macOS/iOS Security framework for Rust

MIT license (LICENSE-MIT or

macOS/iOS Security framework for Rust

A fast and flexible CSV reader and writer for Rust, with support for Serde

Dual-licensed under MIT or the If you're new to Rust, the

A fast and flexible CSV reader and writer for Rust, with support for Serde

Fast linear time &amp; space suffix arrays for Rust

Dual-licensed under MIT or the If you just want the details on how construction algorithm used, see the

Fast linear time &amp; space suffix arrays for Rust

OpenGliderNetwork client for Rust based on actix

MIT license (LICENSE-MIT or

OpenGliderNetwork client for Rust based on actix

The arkworks ecosystem consist of Rust libraries for designing and working with zero knowledge succinct...

This library is released under the MIT License and the Apache v2 License (see License)

The arkworks ecosystem consist of Rust libraries for designing and working with zero knowledge succinct...

Threshold Secret Sharing

Efficient pure-Rust library for MIT license (LICENSE-MIT or

Threshold Secret Sharing

The low-level io_uring userspace interface for Rust

The low-level MIT license (LICENSE-MIT or

The low-level io_uring userspace interface for Rust

An attempt to build a compiler from scratch for a simple language, using Rust

New issues and pull requests are welcome on GitHub at MIT License

An attempt to build a compiler from scratch for a simple language, using Rust

iCalendar in Rust

Please double check the MIT license (LICENSE-MIT or issues or comprehensive pull requests are welcome!

iCalendar in Rust

Rust library for low-level abstraction of MIPS32 processors

This project is licensed under the terms of the MIT license

Rust library for low-level abstraction of MIPS32 processors

A pure Rust library for reading/writing Windows

A pure Rust library for reading/writing License

A pure Rust library for reading/writing Windows
Facebook Instagram Twitter GitHub Dribbble
Privacy