From 3386f20be80aead45a78d6b4314e5089de859902 Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 25 Jun 2019 16:48:55 -0400 Subject: [PATCH 1/9] updated for cursorcontrol, added dynamic UI resizing for smaller displays such as the pygamer, switched font from user-defined to the built-in system font --- adafruit_pyoa.py | 83 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/adafruit_pyoa.py b/adafruit_pyoa.py index c982404..8cfbb8a 100644 --- a/adafruit_pyoa.py +++ b/adafruit_pyoa.py @@ -51,10 +51,12 @@ from digitalio import DigitalInOut import displayio import adafruit_touchscreen +from adafruit_cursorcontrol.cursorcontrol import Cursor +from adafruit_cursorcontrol.cursorcontrol_cursormanager import CursorManager import audioio from adafruit_display_text.label import Label -from adafruit_bitmap_font import bitmap_font from adafruit_button import Button +import terminalio __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_PYOA.git" @@ -74,7 +76,12 @@ def __init__(self): self._speaker_enable = DigitalInOut(board.SPEAKER_ENABLE) self._speaker_enable.switch_to_output(False) - self.audio = audioio.AudioOut(board.AUDIO_OUT) + if hasattr(board, 'AUDIO_OUT'): + self.audio = audioio.AudioOut(board.AUDIO_OUT) + elif hasattr(board, 'SPEAKER'): + self.audio = audioio.AudioOut(board.SPEAKER) + else: + raise AttributeError('Board does not have an Audio output!') self._background_file = None self._wavfile = None @@ -82,12 +89,18 @@ def __init__(self): board.DISPLAY.auto_brightness = False self.backlight_fade(0) board.DISPLAY.show(self.root_group) - - self.touchscreen = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR, - board.TOUCH_YD, board.TOUCH_YU, - calibration=((5200, 59000), - (5800, 57000)), - size=(320, 240)) + self.touchscreen = None + if hasattr(board, 'TOUCH_XL'): + self.touchscreen = adafruit_touchscreen.Touchscreen(board.TOUCH_XL, board.TOUCH_XR, + board.TOUCH_YD, board.TOUCH_YU, + calibration=((5200, 59000), + (5800, 57000)), + size=(320, 240)) + elif hasattr(board, 'BUTTON_CLOCK'): + self.mouse_cursor = Cursor(board.DISPLAY, display_group=self.root_group, cursor_speed=12) + self.cursor = CursorManager(self.mouse_cursor) + else: + raise AttributeError('Board does not have a valid input method!') self._gamedirectory = None self._gamefilename = None self._game = None @@ -106,9 +119,7 @@ def load_game(self, game_directory): """ self._gamedirectory = game_directory - - self._text_font = bitmap_font.load_font(game_directory+"/fonts/Arial-Bold-12.bdf") - #self._text_font = fontio.BuiltinFont + self._text_font = terminalio.FONT try: glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-!,. "\'?!' print("Preloading font glyphs:", glyphs) @@ -116,16 +127,31 @@ def load_game(self, game_directory): except AttributeError: pass # normal for built in font - self._left_button = Button(x=10, y=195, width=120, height=40, + button_x = 10 + button_y = 195 + button_width = 120 + button_height = 40 + if board.DISPLAY.height < 200: # for small displays + button_y /= 2 + button_y += 5 + button_width /= 2 + button_height /= 2 + + self._left_button = Button(x=button_x, y=int(button_y), width=int(button_width), height=int(button_height), label="Left", label_font=self._text_font, style=Button.SHADOWROUNDRECT) - self._right_button = Button(x=190, y=195, width=120, height=40, + self._right_button = Button(x=int(button_x+180/2), y=int(button_y), width=int(button_width), height=int(button_height), label="Right", label_font=self._text_font, style=Button.SHADOWROUNDRECT) - self._middle_button = Button(x=100, y=195, width=120, height=40, + self._middle_button = Button(x=button_x+90, y=int(button_y), width=int(button_width), height=int(button_height), label="Middle", label_font=self._text_font, style=Button.SHADOWROUNDRECT) - + """ + if board.DISPLAY.height < 200: + self._left_button.x = int(self._left_button.x/2) + self._right_button.x = int(self._right_button.x/2) + self._middle_button.x = int(self._middle_button.x/2) + """ self._gamefilename = game_directory+"/cyoa.json" try: @@ -137,12 +163,14 @@ def load_game(self, game_directory): def _fade_to_black(self): """Turn down the lights.""" + self.mouse_cursor.is_hidden = True self.backlight_fade(0) # turn off background so we can render the text self.set_background(None, with_fade=False) self.set_text(None, None) for _ in range(len(self._button_group)): self._button_group.pop() + self.mouse_cursor.is_hidden = False def _display_buttons(self, card): """Display the buttons of a card. @@ -207,9 +235,15 @@ def _wait_for_press(self, card): """ button01_text = card.get('button01_text', None) button02_text = card.get('button02_text', None) + point_touched = None while True: - point_touched = self.touchscreen.touch_point - if point_touched: + self.cursor.update() + if self.touchscreen is not None: + point_touched = self.touchscreen.touch_point + if self.cursor.is_clicked is True: + print('click!') + point_touched = self.mouse_cursor.x, self.mouse_cursor.y + if point_touched is not None: print("touch: ", point_touched) if button01_text and not button02_text: # showing only middle button @@ -223,6 +257,7 @@ def _wait_for_press(self, card): if self._right_button.contains(point_touched): print("Right button") return card.get('button02_goto_card_id', None) + time.sleep(0.2) def display_card(self, card_num): """Display and handle input on a card. @@ -309,13 +344,21 @@ def set_text(self, text, color): self._text_group.pop() if not text or not color: return # nothing to do! - text = self.wrap_nicely(text, 37) + text_wrap = 37 + if board.DISPLAY.height < 130: + text_wrap = 23 + text = self.wrap_nicely(text, text_wrap) text = '\n'.join(text) print("Set text to", text, "with color", hex(color)) + text_x = 10 + text_y = 100 + if board.DISPLAY.height < 130: # smaller displays + text_y = 35 + text_x = 5 if text: self._text = Label(self._text_font, text=str(text)) - self._text.x = 10 - self._text.y = 100 + self._text.x = text_x + self._text.y = text_y self._text.color = color self._text_group.append(self._text) From c5dcec126cb6ad94b10354ea6fe72ba7a7aeb150 Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 25 Jun 2019 18:19:25 -0400 Subject: [PATCH 2/9] fix dynamic button rescaling for pygamer, fix text wrap, speed up the cursor --- adafruit_pyoa.py | 66 ++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/adafruit_pyoa.py b/adafruit_pyoa.py index 8cfbb8a..36c6971 100644 --- a/adafruit_pyoa.py +++ b/adafruit_pyoa.py @@ -97,7 +97,7 @@ def __init__(self): (5800, 57000)), size=(320, 240)) elif hasattr(board, 'BUTTON_CLOCK'): - self.mouse_cursor = Cursor(board.DISPLAY, display_group=self.root_group, cursor_speed=12) + self.mouse_cursor = Cursor(board.DISPLAY, display_group=self.root_group, cursor_speed=8) self.cursor = CursorManager(self.mouse_cursor) else: raise AttributeError('Board does not have a valid input method!') @@ -116,43 +116,32 @@ def load_game(self, game_directory): """Load a game. :param game_directory: where the game files are stored - """ self._gamedirectory = game_directory self._text_font = terminalio.FONT - try: - glyphs = b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-!,. "\'?!' - print("Preloading font glyphs:", glyphs) - self._text_font.load_glyphs(glyphs) - except AttributeError: - pass # normal for built in font - - button_x = 10 + # Button Attributes + btn_left = 10 + btn_right = btn_left+180 + btn_mid = btn_left+90 button_y = 195 button_width = 120 button_height = 40 - if board.DISPLAY.height < 200: # for small displays + if board.DISPLAY.height < 200: button_y /= 2 - button_y += 5 + button_y += 10 button_width /= 2 button_height /= 2 - - self._left_button = Button(x=button_x, y=int(button_y), width=int(button_width), height=int(button_height), + btn_right = int(btn_left+180/2) + btn_mid = int(btn_left+90/2) + self._left_button = Button(x=btn_left, y=int(button_y), width=int(button_width), height=int(button_height), label="Left", label_font=self._text_font, style=Button.SHADOWROUNDRECT) - self._right_button = Button(x=int(button_x+180/2), y=int(button_y), width=int(button_width), height=int(button_height), + self._right_button = Button(x=btn_right, y=int(button_y), width=int(button_width), height=int(button_height), label="Right", label_font=self._text_font, style=Button.SHADOWROUNDRECT) - self._middle_button = Button(x=button_x+90, y=int(button_y), width=int(button_width), height=int(button_height), + self._middle_button = Button(x=btn_mid, y=int(button_y), width=int(button_width), height=int(button_height), label="Middle", label_font=self._text_font, style=Button.SHADOWROUNDRECT) - """ - if board.DISPLAY.height < 200: - self._left_button.x = int(self._left_button.x/2) - self._right_button.x = int(self._right_button.x/2) - self._middle_button.x = int(self._middle_button.x/2) - """ - self._gamefilename = game_directory+"/cyoa.json" try: game_file = open(self._gamefilename, "r") @@ -176,7 +165,6 @@ def _display_buttons(self, card): """Display the buttons of a card. :param card: The active card - """ button01_text = card.get('button01_text', None) button02_text = card.get('button02_text', None) @@ -194,7 +182,6 @@ def _display_background_for(self, card): """If there's a background on card, display it. :param card: The active card - """ self.set_background(card.get('background_image', None), with_fade=False) @@ -202,7 +189,6 @@ def _display_text_for(self, card): """Display the main text of a card. :param card: The active card - """ text = card.get('text', None) text_color = card.get('text_color', 0x0) # default to black @@ -217,7 +203,6 @@ def _play_sound_for(self, card): """If there's a sound, start playing it. :param card: The active card - """ sound = card.get('sound', None) loop = card.get('sound_repeat', False) @@ -237,14 +222,14 @@ def _wait_for_press(self, card): button02_text = card.get('button02_text', None) point_touched = None while True: - self.cursor.update() if self.touchscreen is not None: point_touched = self.touchscreen.touch_point - if self.cursor.is_clicked is True: - print('click!') - point_touched = self.mouse_cursor.x, self.mouse_cursor.y + else: + self.cursor.update() + if self.cursor.is_clicked is True: + point_touched = self.mouse_cursor.x, self.mouse_cursor.y if point_touched is not None: - print("touch: ", point_touched) + #print("touch: ", point_touched) if button01_text and not button02_text: # showing only middle button if self._middle_button.contains(point_touched): @@ -257,13 +242,12 @@ def _wait_for_press(self, card): if self._right_button.contains(point_touched): print("Right button") return card.get('button02_goto_card_id', None) - time.sleep(0.2) + time.sleep(0.1) def display_card(self, card_num): """Display and handle input on a card. :param card_num: the index of the card to process - """ card = self._game[card_num] print(card) @@ -304,7 +288,6 @@ def play_sound(self, filename, *, wait_to_finish=True, loop=False): :param filename: The filename of the sound to play :param wait_to_finish: Whether playing the sound should block :param loop: Whether the sound should loop - """ self._speaker_enable.value = False self.audio.stop() @@ -346,15 +329,15 @@ def set_text(self, text, color): return # nothing to do! text_wrap = 37 if board.DISPLAY.height < 130: - text_wrap = 23 + text_wrap = 25 text = self.wrap_nicely(text, text_wrap) text = '\n'.join(text) print("Set text to", text, "with color", hex(color)) - text_x = 10 - text_y = 100 - if board.DISPLAY.height < 130: # smaller displays - text_y = 35 - text_x = 5 + text_x = 8 + text_y = 95 + if board.DISPLAY.height < 130: + text_y = 38 + text_x = 3 if text: self._text = Label(self._text_font, text=str(text)) self._text.x = text_x @@ -366,7 +349,6 @@ def set_background(self, filename, *, with_fade=True): """The background image to a bitmap file. :param filename: The filename of the chosen background - """ print("Set background to", filename) if with_fade: From cf7537a4d73d2c23d879ae110798bfb8b868dcc6 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 26 Jun 2019 11:26:25 -0400 Subject: [PATCH 3/9] cleanup button scaling again --- adafruit_pyoa.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/adafruit_pyoa.py b/adafruit_pyoa.py index 36c6971..657dbd7 100644 --- a/adafruit_pyoa.py +++ b/adafruit_pyoa.py @@ -81,7 +81,7 @@ def __init__(self): elif hasattr(board, 'SPEAKER'): self.audio = audioio.AudioOut(board.SPEAKER) else: - raise AttributeError('Board does not have an Audio output!') + raise AttributeError('Board does not have an audio output!') self._background_file = None self._wavfile = None @@ -100,7 +100,7 @@ def __init__(self): self.mouse_cursor = Cursor(board.DISPLAY, display_group=self.root_group, cursor_speed=8) self.cursor = CursorManager(self.mouse_cursor) else: - raise AttributeError('Board does not have a valid input method!') + raise AttributeError('PYOA requires a touchscreen or cursor.') self._gamedirectory = None self._gamefilename = None self._game = None @@ -131,15 +131,15 @@ def load_game(self, game_directory): button_y += 10 button_width /= 2 button_height /= 2 - btn_right = int(btn_left+180/2) - btn_mid = int(btn_left+90/2) - self._left_button = Button(x=btn_left, y=int(button_y), width=int(button_width), height=int(button_height), + btn_right /= 2 + btn_mid /= 2 + self._left_button = Button(x=int(btn_left), y=int(button_y), width=int(button_width), height=int(button_height), label="Left", label_font=self._text_font, style=Button.SHADOWROUNDRECT) - self._right_button = Button(x=btn_right, y=int(button_y), width=int(button_width), height=int(button_height), + self._right_button = Button(x=int(btn_right), y=int(button_y), width=int(button_width), height=int(button_height), label="Right", label_font=self._text_font, style=Button.SHADOWROUNDRECT) - self._middle_button = Button(x=btn_mid, y=int(button_y), width=int(button_width), height=int(button_height), + self._middle_button = Button(x=int(btn_mid), y=int(button_y), width=int(button_width), height=int(button_height), label="Middle", label_font=self._text_font, style=Button.SHADOWROUNDRECT) self._gamefilename = game_directory+"/cyoa.json" From 2482c738be39eaf0ada176ec3bb141cf016bad5a Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 26 Jun 2019 12:50:13 -0400 Subject: [PATCH 4/9] fix spacin --- adafruit_pyoa.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_pyoa.py b/adafruit_pyoa.py index 657dbd7..f3d967e 100644 --- a/adafruit_pyoa.py +++ b/adafruit_pyoa.py @@ -229,7 +229,7 @@ def _wait_for_press(self, card): if self.cursor.is_clicked is True: point_touched = self.mouse_cursor.x, self.mouse_cursor.y if point_touched is not None: - #print("touch: ", point_touched) + print("touch: ", point_touched) if button01_text and not button02_text: # showing only middle button if self._middle_button.contains(point_touched): From edba595368be0bcd0cb9a6efb4283b19f07ff168 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 26 Jun 2019 13:01:45 -0400 Subject: [PATCH 5/9] add cursorcontrol to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index edf9394..702f7ac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ Adafruit-Blinka +adafruit_cursorcontrol \ No newline at end of file From 82c76274e277566bb9bf550e152214e0d7d3d891 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 26 Jun 2019 13:03:59 -0400 Subject: [PATCH 6/9] add cursorcontrol to .txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 702f7ac..1e9e531 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ Adafruit-Blinka -adafruit_cursorcontrol \ No newline at end of file +adafruit-circuitpython-cursorcontrol \ No newline at end of file From 4d5b737753e81098e14a5266058047306d9a75e9 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 26 Jun 2019 16:29:43 -0400 Subject: [PATCH 7/9] adding modified CYOA.json to make cave example playable on smaller screens like the pygamer --- examples/cave/cyoa.json | 66 ++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/examples/cave/cyoa.json b/examples/cave/cyoa.json index 00efef7..30fb04a 100644 --- a/examples/cave/cyoa.json +++ b/examples/cave/cyoa.json @@ -5,7 +5,7 @@ "text": "Welcome adventurer. Your adventure begins, as many do, in Ye Olde Inn.", "text_color": "0x000001", "button01_text": "Continue", - "button01_goto_card_id": "inn", + "button01_goto_card_id": "inn" }, { "card_id": "inn", @@ -14,10 +14,10 @@ "sound_repeat": "True", "text": "This is a peaceful, happy inn with plentiful drink, tasty food, and friendly staff.", "text_color": "0x000001", - "button01_text": "Stay here", + "button01_text": "Stay", "button01_goto_card_id": "inn", - "button02_text": "Adventure!", - "button02_goto_card_id": "cave entrance", + "button02_text": "Go!", + "button02_goto_card_id": "cave entrance" }, { "card_id": "cave entrance", @@ -26,9 +26,9 @@ "text_color": "0x000001", "sound": "cave.wav", "sound_repeat": "True", - "button01_text": "Go inside", + "button01_text": "Enter", "button01_goto_card_id": "entry", - "button02_text": "Run away", + "button02_text": "Run", "button02_goto_card_id": "inn" }, { @@ -39,7 +39,7 @@ "text": "You are in a dark, narrow tunnel.", "text_color": "0x000001", "button01_text": "Next", - "button01_goto_card_id": "side opening", + "button01_goto_card_id": "side opening" }, { "card_id": "side opening", @@ -50,8 +50,8 @@ "text_color": "0x000001", "button01_text": "Continue", "button01_goto_card_id": "skeleton room", - "button02_text": "Side Tunnel", - "button02_goto_card_id": "treasure room", + "button02_text": "Side T.", + "button02_goto_card_id": "treasure room" }, { "card_id": "treasure room", @@ -61,7 +61,7 @@ "text": "There is a pile of treasure here. Congratulations!", "text_color": "0x000001", "button01_text": "Next", - "button01_goto_card_id": "maze 1", + "button01_goto_card_id": "maze 1" }, { "card_id": "skeleton room", @@ -71,7 +71,7 @@ "text": "There is a skeleton on the floor. From the items around it, it seems to be that of an unfortunate adventurer.", "text_color": "0x000001", "button01_text": "Next", - "button01_goto_card_id": "maze 2", + "button01_goto_card_id": "maze 2" }, { "card_id": "maze 1", @@ -95,7 +95,7 @@ "button01_text": "Left", "button01_goto_card_id": "maze 1", "button02_text": "Right", - "button02_goto_card_id": "maze 4", + "button02_goto_card_id": "maze 4" }, { "card_id": "maze 3", @@ -107,7 +107,7 @@ "button01_text": "Left", "button01_goto_card_id": "maze 5", "button02_text": "Right", - "button02_goto_card_id": "maze 2", + "button02_goto_card_id": "maze 2" }, { "card_id": "maze 4", @@ -119,7 +119,7 @@ "button01_text": "Left", "button01_goto_card_id": "maze 1", "button02_text": "Right", - "button02_goto_card_id": "maze 6", + "button02_goto_card_id": "maze 6" }, { "card_id": "maze 5", @@ -131,7 +131,7 @@ "button01_text": "Left", "button01_goto_card_id": "maze 4", "button02_text": "Right", - "button02_goto_card_id": "creaking", + "button02_goto_card_id": "creaking" }, { "card_id": "maze 6", @@ -143,7 +143,7 @@ "button01_text": "Left", "button01_goto_card_id": "creaking", "button02_text": "Right", - "button02_goto_card_id": "maze 3", + "button02_goto_card_id": "maze 3" }, { "card_id": "creaking", @@ -152,23 +152,35 @@ "sound_repeat": "True", "text": "You hear an ominuous creaking from around the corner", "text_color": "0x000001", - "button01_text": "Continue", - "button01_goto_card_id": "bridge room", - "button02_text": "Turn back", - "button02_goto_card_id": "inn", + "button01_text": "Cont.", + "button01_goto_card_id": "bridge room 1", + "button02_text": "Go back", + "button02_goto_card_id": "inn" }, { - "card_id": "bridge room", + "card_id": "bridge room 1", "background_image": "page01.bmp", "sound": "creak.wav", "sound_repeat": "True", - "text": "There is a creaking, rickity wooded bridge leading across a gaping chasm. At the other end is a large treasure chest. There is also a short tunnel with daylight at the end.", + "text": "There is a creaking, rickity wooded bridge leading across a gaping chasm.", "text_color": "0x000001", - "button01_text": "Treasure!", - "button01_goto_card_id": "die", - "button02_text": "Leave", - "button02_goto_card_id": "inn", + "button01_text": "Cont.", + "button01_goto_card_id": "bridge room 2" + }, + + { + "card_id": "bridge room 2", + "background_image": "page01.bmp", + "sound": "creak.wav", + "sound_repeat": "True", + "text": "At the other end is a large treasure chest. There is also a short tunnel with daylight at the end.", + "text_color": "0x000001", + "button01_text": "Treasure!", + "button01_goto_card_id": "die", + "button02_text": "Leave", + "button02_goto_card_id": "inn" }, + { "card_id": "die", "background_image": "page01.bmp", @@ -176,6 +188,6 @@ "text": "The bridge gives way and you fall to a painful death.", "text_color": "0x000001", "button01_text": "Next", - "button01_goto_card_id": "inn", + "button01_goto_card_id": "inn" } ] From 29470699b0620bbb1b642c252990fc53ffde103d Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 26 Jun 2019 16:33:24 -0400 Subject: [PATCH 8/9] add cursorcontrol, terminalio into the mock_imports for autodoc --- docs/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 3e1d6a0..30789fd 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -23,7 +23,8 @@ autodoc_mock_imports = ["rtc", "supervisor", "pulseio", "audioio", "displayio", "neopixel", "microcontroller", "adafruit_touchscreen", "adafruit_bitmap_font", "adafruit_display_text", "adafruit_esp32spi", "secrets", - "adafruit_sdcard", "storage", "adafruit_io", "adafruit_button"] + "adafruit_sdcard", "storage", "adafruit_io", "adafruit_button", "adafruit_cursorcontrol", + "terminalio"] intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None),'CircuitPython': ('https://circuitpython.readthedocs.io/en/latest/', None)} From 2ef73d439d44ff7e9311319a8f7113c5ebb5fc08 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 26 Jun 2019 16:36:11 -0400 Subject: [PATCH 9/9] remove cursorcontrol dep. from requirements, moved to mock_imports --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1e9e531..edf9394 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ Adafruit-Blinka -adafruit-circuitpython-cursorcontrol \ No newline at end of file