Skip to content

Commit 34460ee

Browse files
committed
Merge pull request #9 from techtonik/termbox
Termbox API
2 parents d75fca3 + cc4dde2 commit 34460ee

File tree

3 files changed

+478
-0
lines changed

3 files changed

+478
-0
lines changed

examples/termbox/README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
API of `termbox` Python module implemented in `tld`.
2+
3+
The code here are modified files from
4+
[termbox repository](https://github.com/nsf/termbox/), so please consult
5+
it for the license and other info.
6+
7+
8+
The code consists of two part - `termbox.py` module with API, translation
9+
of official binding form the description below into `tld`:
10+
11+
https://github.com/nsf/termbox/blob/b20c0a11/src/python/termboxmodule.pyx
12+
13+
And the example `termboxtest.py` which is copied verbatim from:
14+
15+
https://github.com/nsf/termbox/blob/b20c0a11/test_termboxmodule.py
16+
17+
18+
### API Mapping Notes
19+
20+
Notes taken while mapping the Termbox class:
21+
22+
tb_init() // initialization console = tdl.init(132, 60)
23+
tb_shutdown() // shutdown
24+
25+
tb_width() // width of the terminal screen console.width
26+
tb_height() // height of the terminal screen console.height
27+
28+
tb_clear() // clear buffer console.clear()
29+
tb_present() // sync internal buffer with terminal tdl.flush()
30+
31+
tb_put_cell()
32+
tb_change_cell() console.draw_char(x, y, ch, fg, bg)
33+
tb_blit() // drawing functions
34+
35+
tb_select_input_mode() // change input mode
36+
tb_peek_event() // peek a keyboard event
37+
tb_poll_event() // wait for a keyboard event * tdl.event.get()
38+
39+
40+
* - means the translation is not direct
41+
42+
43+
44+
init...
45+
tdl doesn't allow to resize window (or rather libtcod)
46+
tb works in existing terminal window and queries it rather than making own
47+
48+
colors...
49+
tdl uses RGB values
50+
tb uses it own constants
51+
52+
event...
53+
tb returns event one by one
54+
tdl return an event iterator
55+
56+
57+
tb Event tdl Event
58+
.type .type
59+
EVENT_KEY KEYDOWN

examples/termbox/termbox.py

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
"""
2+
Implementation of Termbox Python API in tdl.
3+
4+
See README.md for details.
5+
"""
6+
7+
import tdl
8+
9+
"""
10+
Implementation status:
11+
[ ] tdl.init() needs a window, made 132x60
12+
[ ] Termbox.close() is not implemented, does nothing
13+
[ ] poll_event needs review, because it does not
14+
completely follows the original logic
15+
[ ] peek is stubbed, but not implemented
16+
[ ] not all keys/events are mapped
17+
"""
18+
19+
class TermboxException(Exception):
20+
def __init__(self, msg):
21+
self.msg = msg
22+
def __str__(self):
23+
return self.msg
24+
25+
_instance = None
26+
27+
# keys ----------------------------------
28+
KEY_F1 = (0xFFFF-0)
29+
KEY_F2 = (0xFFFF-1)
30+
KEY_F3 = (0xFFFF-2)
31+
KEY_F4 = (0xFFFF-3)
32+
KEY_F5 = (0xFFFF-4)
33+
KEY_F6 = (0xFFFF-5)
34+
KEY_F7 = (0xFFFF-6)
35+
KEY_F8 = (0xFFFF-7)
36+
KEY_F9 = (0xFFFF-8)
37+
KEY_F10 = (0xFFFF-9)
38+
KEY_F11 = (0xFFFF-10)
39+
KEY_F12 = (0xFFFF-11)
40+
KEY_INSERT = (0xFFFF-12)
41+
KEY_DELETE = (0xFFFF-13)
42+
43+
KEY_PGUP = (0xFFFF-16)
44+
KEY_PGDN = (0xFFFF-17)
45+
46+
KEY_MOUSE_LEFT =(0xFFFF-22)
47+
KEY_MOUSE_RIGHT =(0xFFFF-23)
48+
KEY_MOUSE_MIDDLE =(0xFFFF-24)
49+
KEY_MOUSE_RELEASE =(0xFFFF-25)
50+
KEY_MOUSE_WHEEL_UP =(0xFFFF-26)
51+
KEY_MOUSE_WHEEL_DOWN =(0xFFFF-27)
52+
53+
KEY_CTRL_TILDE = 0x00
54+
KEY_CTRL_2 = 0x00
55+
KEY_CTRL_A = 0x01
56+
KEY_CTRL_B = 0x02
57+
KEY_CTRL_C = 0x03
58+
KEY_CTRL_D = 0x04
59+
KEY_CTRL_E = 0x05
60+
KEY_CTRL_F = 0x06
61+
KEY_CTRL_G = 0x07
62+
KEY_BACKSPACE = 0x08
63+
KEY_CTRL_H = 0x08
64+
KEY_TAB = 0x09
65+
KEY_CTRL_I = 0x09
66+
KEY_CTRL_J = 0x0A
67+
KEY_CTRL_K = 0x0B
68+
KEY_CTRL_L = 0x0C
69+
KEY_ENTER = 0x0D
70+
KEY_CTRL_M = 0x0D
71+
KEY_CTRL_N = 0x0E
72+
KEY_CTRL_O = 0x0F
73+
KEY_CTRL_P = 0x10
74+
KEY_CTRL_Q = 0x11
75+
KEY_CTRL_R = 0x12
76+
KEY_CTRL_S = 0x13
77+
KEY_CTRL_T = 0x14
78+
KEY_CTRL_U = 0x15
79+
KEY_CTRL_V = 0x16
80+
KEY_CTRL_W = 0x17
81+
KEY_CTRL_X = 0x18
82+
KEY_CTRL_Y = 0x19
83+
KEY_CTRL_Z = 0x1A
84+
85+
86+
# -- mapped to tdl
87+
KEY_HOME = 'HOME'
88+
KEY_END = 'END'
89+
KEY_ARROW_UP = 'UP'
90+
KEY_ARROW_DOWN = 'DOWN'
91+
KEY_ARROW_LEFT = 'LEFT'
92+
KEY_ARROW_RIGHT = 'RIGHT'
93+
KEY_ESC = 'ESCAPE'
94+
# /--
95+
96+
97+
KEY_CTRL_LSQ_BRACKET = 0x1B
98+
KEY_CTRL_3 = 0x1B
99+
KEY_CTRL_4 = 0x1C
100+
KEY_CTRL_BACKSLASH = 0x1C
101+
KEY_CTRL_5 = 0x1D
102+
KEY_CTRL_RSQ_BRACKET = 0x1D
103+
KEY_CTRL_6 = 0x1E
104+
KEY_CTRL_7 = 0x1F
105+
KEY_CTRL_SLASH = 0x1F
106+
KEY_CTRL_UNDERSCORE = 0x1F
107+
KEY_SPACE = 0x20
108+
KEY_BACKSPACE2 = 0x7F
109+
KEY_CTRL_8 = 0x7F
110+
111+
MOD_ALT = 0x01
112+
113+
# attributes ----------------------
114+
115+
#-- mapped to tdl
116+
DEFAULT = Ellipsis
117+
118+
BLACK = 0x000000
119+
RED = 0xFF0000
120+
GREEN = 0x00FF00
121+
YELLOW = 0xFFFF00
122+
BLUE = 0x0000FF
123+
MAGENTA = 0xFF00FF
124+
CYAN = 0x00FFFF
125+
WHITE = 0xFFFFFF
126+
#/--
127+
128+
BOLD = 0x10
129+
UNDERLINE = 0x20
130+
REVERSE = 0x40
131+
132+
# misc ----------------------------
133+
134+
HIDE_CURSOR = -1
135+
INPUT_CURRENT = 0
136+
INPUT_ESC = 1
137+
INPUT_ALT = 2
138+
OUTPUT_CURRENT = 0
139+
OUTPUT_NORMAL = 1
140+
OUTPUT_256 = 2
141+
OUTPUT_216 = 3
142+
OUTPUT_GRAYSCALE = 4
143+
144+
145+
# -- mapped to tdl
146+
EVENT_KEY = 'KEYDOWN'
147+
# /--
148+
EVENT_RESIZE = 2
149+
EVENT_MOUSE = 3
150+
151+
class Event:
152+
""" Aggregate for Termbox Event structure """
153+
type = None
154+
ch = None
155+
key = None
156+
mod = None
157+
width = None
158+
height = None
159+
mousex = None
160+
mousey = None
161+
162+
def gettuple(self):
163+
return (self.type, self.ch, self.key, self.mod, self.width, self.height, self.mousex, self.mousey)
164+
165+
class Termbox:
166+
def __init__(self, width=132, height=60):
167+
global _instance
168+
if _instance:
169+
raise TermboxException("It is possible to create only one instance of Termbox")
170+
171+
try:
172+
self.console = tdl.init(width, height)
173+
except tdl.TDLException as e:
174+
raise TermboxException(e)
175+
176+
self.e = Event() # cache for event data
177+
178+
_instance = self
179+
180+
def __del__(self):
181+
self.close()
182+
183+
def __exit__(self, *args):#t, value, traceback):
184+
self.close()
185+
186+
def __enter__(self):
187+
return self
188+
189+
def close(self):
190+
global _instance
191+
# tb_shutdown()
192+
_instance = None
193+
# TBD, does nothing
194+
195+
def present(self):
196+
"""Sync state of the internal cell buffer with the terminal.
197+
"""
198+
tdl.flush()
199+
200+
def change_cell(self, x, y, ch, fg, bg):
201+
"""Change cell in position (x;y).
202+
"""
203+
self.console.draw_char(x, y, ch, fg, bg)
204+
205+
def width(self):
206+
"""Returns width of the terminal screen.
207+
"""
208+
return self.console.width
209+
210+
def height(self):
211+
"""Return height of the terminal screen.
212+
"""
213+
return self.console.height
214+
215+
def clear(self):
216+
"""Clear the internal cell buffer.
217+
"""
218+
self.console.clear()
219+
220+
def set_cursor(self, x, y):
221+
"""Set cursor position to (x;y).
222+
223+
Set both arguments to HIDE_CURSOR or use 'hide_cursor' function to hide it.
224+
"""
225+
tb_set_cursor(x, y)
226+
227+
def hide_cursor(self):
228+
"""Hide cursor.
229+
"""
230+
tb_set_cursor(-1, -1)
231+
232+
def select_input_mode(self, mode):
233+
"""Select preferred input mode: INPUT_ESC or INPUT_ALT.
234+
235+
INPUT_CURRENT returns the selected mode without changing anything.
236+
"""
237+
return int(tb_select_input_mode(mode))
238+
239+
def select_output_mode(self, mode):
240+
"""Select preferred output mode: one of OUTPUT_* constants.
241+
242+
OUTPUT_CURRENT returns the selected mode without changing anything.
243+
"""
244+
return int(tb_select_output_mode(mode))
245+
246+
def peek_event(self, timeout=0):
247+
"""Wait for an event up to 'timeout' milliseconds and return it.
248+
249+
Returns None if there was no event and timeout is expired.
250+
Returns a tuple otherwise: (type, unicode character, key, mod, width, height, mousex, mousey).
251+
"""
252+
"""
253+
cdef tb_event e
254+
with self._poll_lock:
255+
with nogil:
256+
result = tb_peek_event(&e, timeout)
257+
assert(result >= 0)
258+
if result == 0:
259+
return None
260+
if e.ch:
261+
uch = unichr(e.ch)
262+
else:
263+
uch = None
264+
"""
265+
pass #return (e.type, uch, e.key, e.mod, e.w, e.h, e.x, e.y)
266+
267+
def poll_event(self):
268+
"""Wait for an event and return it.
269+
270+
Returns a tuple: (type, unicode character, key, mod, width, height, mousex, mousey).
271+
"""
272+
"""
273+
cdef tb_event e
274+
with self._poll_lock:
275+
with nogil:
276+
result = tb_poll_event(&e)
277+
assert(result >= 0)
278+
if e.ch:
279+
uch = unichr(e.ch)
280+
else:
281+
uch = None
282+
"""
283+
for e in tdl.event.get():
284+
# [ ] not all events are passed thru
285+
self.e.type = e.type
286+
if e.type == 'KEYDOWN':
287+
self.e.key = e.key
288+
return self.e.gettuple()
289+
290+
#return (e.type, uch, e.key, e.mod, e.w, e.h, e.x, e.y)

0 commit comments

Comments
 (0)