1 | // Copyright (C) 2013-2015 ChaosForge Ltd
|
---|
2 | // http://chaosforge.org/
|
---|
3 | //
|
---|
4 | // This file is part of Nova libraries.
|
---|
5 | // For conditions of distribution and use, see copying.txt file in root folder.
|
---|
6 |
|
---|
7 | #include "nv/curses/curses_terminal.hh"
|
---|
8 |
|
---|
9 | #include "nv/core/time.hh"
|
---|
10 | #include "nv/lib/curses.hh"
|
---|
11 |
|
---|
12 | using namespace nv;
|
---|
13 |
|
---|
14 | curses_terminal::curses_terminal( dimension size ) : terminal( size )
|
---|
15 | {
|
---|
16 | load_curses_library();
|
---|
17 | m_screen = initscr();
|
---|
18 | raw();
|
---|
19 | cbreak();
|
---|
20 | noecho();
|
---|
21 |
|
---|
22 | nodelay ( static_cast<WINDOW*>( m_screen ), true );
|
---|
23 | intrflush( static_cast<WINDOW*>( m_screen ), false );
|
---|
24 | keypad ( static_cast<WINDOW*>( m_screen ), true );
|
---|
25 |
|
---|
26 | start_color();
|
---|
27 | resize_term( size.y, size.x );
|
---|
28 | PDC_save_key_modifiers( true );
|
---|
29 |
|
---|
30 | for ( short i = 0; i < 64; ++i )
|
---|
31 | init_pair( i+1, i % 8, i / 8 );
|
---|
32 |
|
---|
33 | clear();
|
---|
34 | refresh();
|
---|
35 | curs_set(1);
|
---|
36 |
|
---|
37 | m_update_needed = false;
|
---|
38 | }
|
---|
39 |
|
---|
40 | void curses_terminal::update()
|
---|
41 | {
|
---|
42 | if (m_update_needed)
|
---|
43 | {
|
---|
44 | refresh();
|
---|
45 | m_update_needed = false;
|
---|
46 | }
|
---|
47 | }
|
---|
48 |
|
---|
49 | void curses_terminal::print( position p, term_color fgcolor, term_color bgcolor, char ch )
|
---|
50 | {
|
---|
51 | uint32 fcolor = fgcolor.get_color();
|
---|
52 | uint32 bcolor = ( bgcolor.get_color() % 8 ) * 8;
|
---|
53 | m_update_needed = true;
|
---|
54 | chtype attr = static_cast<chtype>( ( fcolor > 7 ? fcolor - 7 + bcolor : fcolor + bcolor + 1 ) << 24 );
|
---|
55 | if ( fcolor > 7 ) attr = attr | 0x00800000ul;
|
---|
56 | attrset(attr);
|
---|
57 | mvaddch( p.y-1, p.x-1, chtype(ch) );
|
---|
58 | ::move( m_cursor.y-1, m_cursor.x-1 );
|
---|
59 | }
|
---|
60 |
|
---|
61 | void curses_terminal::clear( rectangle r, term_color fgcolor, term_color bgcolor )
|
---|
62 | {
|
---|
63 | uint32 fcolor = fgcolor.get_color();
|
---|
64 | uint32 bcolor = ( bgcolor.get_color() % 8 ) * 8;
|
---|
65 | chtype attr = static_cast<chtype>( ( fcolor > 7 ? fcolor - 7 + bcolor : fcolor + bcolor + 1 ) << 24 );
|
---|
66 | if ( fcolor > 7 ) attr = attr | 0x00800000ul;
|
---|
67 | attrset( attr );
|
---|
68 | for ( int x = r.ul.x-1; x <= r.lr.x-1; ++x )
|
---|
69 | for ( int y = r.ul.y-1; y <= r.lr.y-1; ++y )
|
---|
70 | mvaddch( y, x, ' ' );
|
---|
71 | }
|
---|
72 |
|
---|
73 | void curses_terminal::clear()
|
---|
74 | {
|
---|
75 | m_update_needed = true;
|
---|
76 | ::clear();
|
---|
77 | ::move( m_cursor.y-1, m_cursor.x-1 );
|
---|
78 | }
|
---|
79 |
|
---|
80 | bool curses_terminal::poll( io_event& kevent )
|
---|
81 | {
|
---|
82 | // Sleep so we don't get 100% processor usage
|
---|
83 | sleep(10);
|
---|
84 |
|
---|
85 | // Get value from curses
|
---|
86 | int result = wgetch( static_cast<WINDOW*>( m_screen ) );
|
---|
87 |
|
---|
88 | // If value is err, return none event
|
---|
89 | if ( result == -1 )
|
---|
90 | {
|
---|
91 | return false;
|
---|
92 | }
|
---|
93 |
|
---|
94 | // Zero the fields
|
---|
95 | kevent.type = EV_KEY;
|
---|
96 | kevent.key.pressed = true;
|
---|
97 | kevent.key.ascii = 0;
|
---|
98 | kevent.key.code = nv::KEY_NONE;
|
---|
99 | kevent.key.control = false;
|
---|
100 | kevent.key.shift = false;
|
---|
101 |
|
---|
102 | // if result is a typable char place it into the structure
|
---|
103 | if ( result >= 32 && result < 128 )
|
---|
104 | {
|
---|
105 | kevent.key.ascii = static_cast<nv::uchar8>(result);
|
---|
106 | }
|
---|
107 |
|
---|
108 | // Check the control and shift states
|
---|
109 | // TODO: obviously there is an ERROR here :P
|
---|
110 | kevent.key.control = (PDC_get_key_modifiers() & 2) != 0;
|
---|
111 | kevent.key.shift = (PDC_get_key_modifiers() & 2) != 0;
|
---|
112 |
|
---|
113 | // if result is a typable char from the directly transformable ranges
|
---|
114 | if ( (result >= nv::KEY_A && result <= nv::KEY_Z) ||
|
---|
115 | (result >= nv::KEY_0 && result <= nv::KEY_9) ||
|
---|
116 | result == ' ' )
|
---|
117 | {
|
---|
118 | kevent.key.code = static_cast<nv::key_code>(result);
|
---|
119 | }
|
---|
120 |
|
---|
121 | // if result is a typable char from the a..z range
|
---|
122 | if ( result >= nv::KEY_A + 32 && result <= nv::KEY_Z + 32 )
|
---|
123 | {
|
---|
124 | kevent.key.code = static_cast<nv::key_code>(result - 32);
|
---|
125 | }
|
---|
126 |
|
---|
127 | // if result is a typable char from the 0..9 range
|
---|
128 | if ( result >= nv::KEY_0 && result <= nv::KEY_9 )
|
---|
129 | {
|
---|
130 | kevent.key.code = static_cast<nv::key_code>(result);
|
---|
131 | }
|
---|
132 |
|
---|
133 | // if result is a typable char from the 0..9 range
|
---|
134 | if ( result >= 0x108 && result <= 0x108 + 12 )
|
---|
135 | {
|
---|
136 | kevent.key.code = static_cast<nv::key_code>( nv::KEY_F1 + result - 0x108 - 1 );
|
---|
137 | }
|
---|
138 |
|
---|
139 | // other recognized codes
|
---|
140 | switch ( result )
|
---|
141 | {
|
---|
142 | case 8 : kevent.key.code = nv::KEY_BACK; break;
|
---|
143 | case 9 : kevent.key.code = nv::KEY_TAB; break;
|
---|
144 | case 13 : kevent.key.code = nv::KEY_ENTER; break;
|
---|
145 | case 27 : kevent.key.code = nv::KEY_ESCAPE; break;
|
---|
146 | case 0x103 : kevent.key.code = nv::KEY_UP; break;
|
---|
147 | case 0x102 : kevent.key.code = nv::KEY_DOWN; break;
|
---|
148 | case 0x104 : kevent.key.code = nv::KEY_LEFT; break;
|
---|
149 | case 0x105 : kevent.key.code = nv::KEY_RIGHT; break;
|
---|
150 | case 0x153 : kevent.key.code = nv::KEY_PGUP; break;
|
---|
151 | case 0x152 : kevent.key.code = nv::KEY_PGDOWN; break;
|
---|
152 | case 0x106 : kevent.key.code = nv::KEY_HOME; break;
|
---|
153 | case 0x166 : kevent.key.code = nv::KEY_END; break;
|
---|
154 | }
|
---|
155 |
|
---|
156 | // If key was understood by nv, then it's valid, otherwise ignored
|
---|
157 | return kevent.key.ascii != 0 || kevent.key.code != 0;
|
---|
158 | }
|
---|
159 |
|
---|
160 | void curses_terminal::set_cursor( position p )
|
---|
161 | {
|
---|
162 | terminal::set_cursor( p );
|
---|
163 | ::move( m_cursor.y-1, m_cursor.x-1 );
|
---|
164 | }
|
---|
165 |
|
---|
166 | void curses_terminal::show_cursor()
|
---|
167 | {
|
---|
168 | curs_set(1);
|
---|
169 | }
|
---|
170 |
|
---|
171 | void curses_terminal::hide_cursor()
|
---|
172 | {
|
---|
173 | curs_set(0);
|
---|
174 | }
|
---|
175 |
|
---|
176 | curses_terminal::~curses_terminal()
|
---|
177 | {
|
---|
178 | endwin();
|
---|
179 | }
|
---|