1 #pragma once
2 
3 
4 #include <utility>
5 #include <memory>
6 #include <uv.h>
7 #include "stream.hpp"
8 #include "util.hpp"
9 
10 
11 namespace uvw {
12 
13 
14 namespace details {
15 
16 
17 struct ResetModeMemo {
~ResetModeMemouvw::details::ResetModeMemo18     ~ResetModeMemo() {
19         uv_tty_reset_mode();
20     }
21 };
22 
23 
24 enum class UVTTYModeT: std::underlying_type_t<uv_tty_mode_t> {
25     NORMAL = UV_TTY_MODE_NORMAL,
26     RAW = UV_TTY_MODE_RAW,
27     IO = UV_TTY_MODE_IO
28 };
29 
30 
31 }
32 
33 
34 /**
35  * @brief The TTYHandle handle.
36  *
37  * TTY handles represent a stream for the console.
38  *
39  * To create a `TTYHandle` through a `Loop`, arguments follow:
40  *
41  * * A valid FileHandle. Usually the file descriptor will be:
42  *     * `uvw::StdIN` or `0` for `stdin`
43  *     * `uvw::StdOUT` or `1` for `stdout`
44  *     * `uvw::StdERR` or `2` for `stderr`
45  * * A boolean value that specifies the plan on calling `read()` with this
46  * stream. Remember that `stdin` is readable, `stdout` is not.
47  *
48  * See the official
49  * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_init)
50  * for further details.
51  */
52 class TTYHandle final: public StreamHandle<TTYHandle, uv_tty_t> {
resetModeMemo()53     static auto resetModeMemo() {
54         static std::weak_ptr<details::ResetModeMemo> weak;
55         auto shared = weak.lock();
56         if(!shared) { weak = shared = std::make_shared<details::ResetModeMemo>(); }
57         return shared;
58     }
59 
60 public:
61     using Mode = details::UVTTYModeT;
62 
TTYHandle(ConstructorAccess ca,std::shared_ptr<Loop> ref,FileHandle desc,bool readable)63     explicit TTYHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref, FileHandle desc, bool readable)
64         : StreamHandle{ca, std::move(ref)},
65           memo{resetModeMemo()},
66           fd{desc},
67           rw{readable}
68     {}
69 
70     /**
71      * @brief Initializes the handle.
72      * @return True in case of success, false otherwise.
73      */
init()74     bool init() {
75         return initialize(&uv_tty_init, fd, rw);
76     }
77 
78     /**
79      * @brief Sets the TTY using the specified terminal mode.
80      *
81      * Available modes are:
82      *
83      * * `TTY::Mode::NORMAL`
84      * * `TTY::Mode::RAW`
85      * * `TTY::Mode::IO`
86      *
87      * See the official
88      * [documentation](http://docs.libuv.org/en/v1.x/tty.html#c.uv_tty_mode_t)
89      * for further details.
90      *
91      * @param m The mode to be set.
92      * @return True in case of success, false otherwise.
93      */
mode(Mode m)94     bool mode(Mode m) {
95         return (0 == uv_tty_set_mode(get(), static_cast<std::underlying_type_t<Mode>>(m)));
96     }
97 
98     /**
99      * @brief Resets TTY settings to default values.
100      * @return True in case of success, false otherwise.
101      */
reset()102     bool reset() noexcept {
103         return (0 == uv_tty_reset_mode());
104     }
105 
106     /**
107      * @brief Gets the current Window size.
108      * @return The current Window size or `{-1, -1}` in case of errors.
109      */
getWinSize()110     WinSize getWinSize() {
111         WinSize size;
112 
113         if(0 != uv_tty_get_winsize(get(), &size.width, &size.height)) {
114             size.width = -1;
115             size.height = -1;
116         }
117 
118         return size;
119     }
120 
121 private:
122     std::shared_ptr<details::ResetModeMemo> memo;
123     FileHandle::Type fd;
124     int rw;
125 };
126 
127 
128 }
129