File: screen_buffer.rs

package info (click to toggle)
rust-crossterm-winapi 0.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, sid, trixie
  • size: 204 kB
  • sloc: makefile: 4
file content (134 lines) | stat: -rwxr-xr-x 4,236 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! This contains the logic for working with the console buffer.

use std::io::{Error, Result};
use std::mem::size_of;

use winapi::{
    shared::minwindef::TRUE,
    shared::ntdef::NULL,
    um::{
        minwinbase::SECURITY_ATTRIBUTES,
        wincon::{
            CreateConsoleScreenBuffer, GetConsoleScreenBufferInfo, SetConsoleActiveScreenBuffer,
            SetConsoleScreenBufferSize, CONSOLE_TEXTMODE_BUFFER, COORD,
        },
        winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE},
    },
};

use super::{is_true, Handle, HandleType, ScreenBufferInfo};

#[derive(Clone, Debug)]
pub struct ScreenBuffer {
    handle: Handle,
}

impl ScreenBuffer {
    pub fn new(handle: Handle) -> Self {
        Self { handle }
    }

    /// Create an instance of `ScreenBuffer` where the `HANDLE`, used for the functions this type wraps, is the current output handle.
    pub fn current() -> Result<ScreenBuffer> {
        Ok(ScreenBuffer {
            handle: Handle::new(HandleType::CurrentOutputHandle)?,
        })
    }

    /// Create new console screen buffer.
    ///
    /// Wraps the underlying function call: [CreateConsoleScreenBuffer]
    /// link: [https://docs.microsoft.com/en-us/windows/console/createconsolescreenbuffer]
    pub fn create() -> ScreenBuffer {
        let mut security_attr: SECURITY_ATTRIBUTES = SECURITY_ATTRIBUTES {
            nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
            lpSecurityDescriptor: NULL,
            bInheritHandle: TRUE,
        };

        unsafe {
            let new_screen_buffer = CreateConsoleScreenBuffer(
                GENERIC_READ |           // read/write access
                    GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE, // shared
                &mut security_attr,                 // default security attributes
                CONSOLE_TEXTMODE_BUFFER,            // must be TEXTMODE
                NULL,
            );
            ScreenBuffer {
                handle: Handle::from_raw(new_screen_buffer),
            }
        }
    }

    /// This will make this `ScreenBuffer` the active one.
    ///
    /// Wraps the underlying function call: [SetConsoleActiveScreenBuffer]
    /// link: [https://docs.microsoft.com/en-us/windows/console/setconsoleactivescreenbuffer]
    pub fn show(&self) -> Result<()> {
        unsafe {
            if !is_true(SetConsoleActiveScreenBuffer(*self.handle)) {
                return Err(Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Get the screen buffer information like terminal size, cursor position, buffer size.
    ///
    /// Wraps the underlying function call: [GetConsoleScreenBufferInfo]
    /// link: [https://docs.microsoft.com/en-us/windows/console/getconsolescreenbufferinfo]
    pub fn info(&self) -> Result<ScreenBufferInfo> {
        let mut csbi = ScreenBufferInfo::new();

        unsafe {
            if !is_true(GetConsoleScreenBufferInfo(*self.handle, &mut csbi.0)) {
                return Err(Error::last_os_error());
            }
        }

        Ok(csbi)
    }

    /// Set the console screen buffer size to the given size.
    ///
    /// Wraps the underlying function call: [SetConsoleScreenBufferSize]
    /// link: [https://docs.microsoft.com/en-us/windows/console/setconsolescreenbuffersize]
    pub fn set_size(&self, x: i16, y: i16) -> Result<()> {
        unsafe {
            if !is_true(SetConsoleScreenBufferSize(
                *self.handle,
                COORD { X: x, Y: y },
            )) {
                return Err(Error::last_os_error());
            }
        }
        Ok(())
    }

    /// Get the underlining raw `HANDLE` used by this type to execute whit.
    pub fn handle(&self) -> &Handle {
        return &self.handle;
    }
}

impl From<Handle> for ScreenBuffer {
    fn from(handle: Handle) -> Self {
        ScreenBuffer { handle }
    }
}

#[cfg(test)]
mod tests {
    use super::ScreenBuffer;

    #[test]
    fn test_screen_buffer_info() {
        let buffer = ScreenBuffer::current().unwrap();
        let info = buffer.info().unwrap();
        info.terminal_size();
        info.terminal_window();
        info.attributes();
        info.cursor_pos();
    }
}