Merge pull request #138 from jpirnay/feat-button-handler
feat: extended button handler
This commit is contained in:
@@ -66,9 +66,7 @@ STR_SLEEP_COVER_MODE: "Рэжым вокладкі сну"
|
||||
STR_HIDE_BATTERY: "Схаваць % батарэі"
|
||||
STR_EXTRA_SPACING: "Дадат. інтэрвал абзаца"
|
||||
STR_TEXT_AA: "Згладжванне тэксту"
|
||||
STR_SHORT_PWR_BTN: "Кароткае націсканне PWR"
|
||||
STR_ORIENTATION: "Арыентацыя чытання"
|
||||
STR_SIDE_BTN_LAYOUT: "Бакавыя кнопкі"
|
||||
STR_LONG_PRESS_SKIP: "Доўгае націсканне - змена раздзела"
|
||||
STR_FONT_FAMILY: "Шрыфт чытання"
|
||||
STR_FONT_SIZE: "Памер шрыфту інтэрфейсу"
|
||||
@@ -119,15 +117,10 @@ STR_CROP: "Абрэзаць"
|
||||
STR_NEVER: "Ніколі"
|
||||
STR_IN_READER: "У рэжыме чытання"
|
||||
STR_ALWAYS: "Заўсёды"
|
||||
STR_IGNORE: "Ігнараваць"
|
||||
STR_SLEEP: "Сон"
|
||||
STR_PAGE_TURN: "Перагортванне"
|
||||
STR_PORTRAIT: "Партрэт"
|
||||
STR_LANDSCAPE_CW: "Ландшафт (CW)"
|
||||
STR_INVERTED: "Інверсія"
|
||||
STR_LANDSCAPE_CCW: "Ландшафт (CCW)"
|
||||
STR_PREV_NEXT: "Назад/Наперад"
|
||||
STR_NEXT_PREV: "Наперад/Назад"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -70,9 +70,7 @@ STR_IMAGES: "Imatges"
|
||||
STR_IMAGES_DISPLAY: "Mostrar"
|
||||
STR_IMAGES_PLACEHOLDER: "Text de mostra"
|
||||
STR_IMAGES_SUPPRESS: "Suprimir"
|
||||
STR_SHORT_PWR_BTN: "Clic curt del botó d'engegada"
|
||||
STR_ORIENTATION: "Orientació de lectura"
|
||||
STR_SIDE_BTN_LAYOUT: "Disposició botons laterals"
|
||||
STR_LONG_PRESS_SKIP: "Pressió llarga omet el capítol"
|
||||
STR_FONT_FAMILY: "Tipus de lletra"
|
||||
STR_FONT_SIZE: "Mida de la lletra (UI)"
|
||||
@@ -124,15 +122,10 @@ STR_CROP: "Retallar"
|
||||
STR_NEVER: "Mai"
|
||||
STR_IN_READER: "Al lector"
|
||||
STR_ALWAYS: "Sempre"
|
||||
STR_IGNORE: "Ignora"
|
||||
STR_SLEEP: "Dormir"
|
||||
STR_PAGE_TURN: "Canvi de pàgina"
|
||||
STR_PORTRAIT: "Vertical"
|
||||
STR_LANDSCAPE_CW: "Horitzontal horari"
|
||||
STR_INVERTED: "Invertit"
|
||||
STR_LANDSCAPE_CCW: "Horitzontal antihorari"
|
||||
STR_PREV_NEXT: "Anterior/Següent"
|
||||
STR_NEXT_PREV: "Següent/Anterior"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -66,9 +66,7 @@ STR_SLEEP_COVER_MODE: "Obrazovka spánku Režim krytu"
|
||||
STR_HIDE_BATTERY: "Skrýt baterii %"
|
||||
STR_EXTRA_SPACING: "Extra mezery mezi odstavci"
|
||||
STR_TEXT_AA: "Vyhlazování textu"
|
||||
STR_SHORT_PWR_BTN: "Krátké stisknutí tlačítka napájení"
|
||||
STR_ORIENTATION: "Orientace čtení"
|
||||
STR_SIDE_BTN_LAYOUT: "Rozvržení bočních tlačítek (čtečka)"
|
||||
STR_LONG_PRESS_SKIP: "Dlouhé stisknutí Přeskočit kapitolu"
|
||||
STR_FONT_FAMILY: "Rodina písem čtečky"
|
||||
STR_FONT_SIZE: "Velikost písma rozhraní"
|
||||
@@ -119,15 +117,10 @@ STR_CROP: "Oříznout"
|
||||
STR_NEVER: "Nikdy"
|
||||
STR_IN_READER: "Ve čtečce"
|
||||
STR_ALWAYS: "Vždy"
|
||||
STR_IGNORE: "Ignorovat"
|
||||
STR_SLEEP: "Spánek"
|
||||
STR_PAGE_TURN: "Otáčení stránek"
|
||||
STR_PORTRAIT: "Na výšku"
|
||||
STR_LANDSCAPE_CW: "Na šířku po směru hod. ručiček"
|
||||
STR_INVERTED: "Invertovaný"
|
||||
STR_LANDSCAPE_CCW: "Na šířku proti směru hod. ručiček"
|
||||
STR_PREV_NEXT: "Předchozí/Další"
|
||||
STR_NEXT_PREV: "Další/Předchozí"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -70,9 +70,7 @@ STR_IMAGES: "Billeder"
|
||||
STR_IMAGES_DISPLAY: "Vis"
|
||||
STR_IMAGES_PLACEHOLDER: "Pladsholder"
|
||||
STR_IMAGES_SUPPRESS: "Skjul"
|
||||
STR_SHORT_PWR_BTN: "Kort tryk på tænd/sluk-knap"
|
||||
STR_ORIENTATION: "Læseretning"
|
||||
STR_SIDE_BTN_LAYOUT: "Knaplayout på siden (læser)"
|
||||
STR_LONG_PRESS_SKIP: "Langt tryk spring kapitel over"
|
||||
STR_FONT_FAMILY: "Læser skrifttype"
|
||||
STR_FONT_SIZE: "Læser skriftstørrelse"
|
||||
@@ -124,15 +122,10 @@ STR_CROP: "Beskær"
|
||||
STR_NEVER: "Aldrig"
|
||||
STR_IN_READER: "I læseren"
|
||||
STR_ALWAYS: "Altid"
|
||||
STR_IGNORE: "Ignorer"
|
||||
STR_SLEEP: "Hvile"
|
||||
STR_PAGE_TURN: "Sideskift"
|
||||
STR_PORTRAIT: "Portræt"
|
||||
STR_LANDSCAPE_CW: "Liggende med uret"
|
||||
STR_INVERTED: "Inverteret"
|
||||
STR_LANDSCAPE_CCW: "Liggende mod uret"
|
||||
STR_PREV_NEXT: "Forrige/Næste"
|
||||
STR_NEXT_PREV: "Næste/Forrige"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -96,9 +96,7 @@ STR_IMAGE_DITHER_BAYER: "Bayer"
|
||||
STR_IMAGE_DITHER_ATKINSON: "Atkinson"
|
||||
STR_IMAGE_DITHER_DIFFUSED_BAYER: "Gediffuseerde Bayer"
|
||||
STR_CREATE_FALLBACK_FOR_INVALID_TOC: "Maak fallback voor ongeldige inhoudsopgave"
|
||||
STR_SHORT_PWR_BTN: "Korte klik aan/uit-knop"
|
||||
STR_ORIENTATION: "Leesstand"
|
||||
STR_SIDE_BTN_LAYOUT: "Indeling zijknoppen (lezer)"
|
||||
STR_LONG_PRESS_SKIP: "Hoofdstuk overslaan (lang indrukken)"
|
||||
STR_FONT_FAMILY: "Lettertype lezer"
|
||||
STR_FONT_SIZE: "Lettergrootte lezer"
|
||||
@@ -199,15 +197,10 @@ STR_CROP: "Bijsnijden"
|
||||
STR_NEVER: "Nooit"
|
||||
STR_IN_READER: "In lezer"
|
||||
STR_ALWAYS: "Altijd"
|
||||
STR_IGNORE: "Negeren"
|
||||
STR_SLEEP: "Slaap"
|
||||
STR_PAGE_TURN: "Pagina omslaan"
|
||||
STR_PORTRAIT: "Staand"
|
||||
STR_LANDSCAPE_CW: "Liggend (rechtsom)"
|
||||
STR_INVERTED: "Omgekeerd"
|
||||
STR_LANDSCAPE_CCW: "Liggend (linksom)"
|
||||
STR_PREV_NEXT: "Vorige/Volgende"
|
||||
STR_NEXT_PREV: "Volgende/Vorige"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -96,9 +96,7 @@ STR_IMAGE_DITHER_BAYER: "Bayer"
|
||||
STR_IMAGE_DITHER_ATKINSON: "Atkinson"
|
||||
STR_IMAGE_DITHER_DIFFUSED_BAYER: "Diffused Bayer"
|
||||
STR_CREATE_FALLBACK_FOR_INVALID_TOC: "Create fallback for invalid TOC"
|
||||
STR_SHORT_PWR_BTN: "Short Power Button Click"
|
||||
STR_ORIENTATION: "Reading Orientation"
|
||||
STR_SIDE_BTN_LAYOUT: "Side Button Layout (reader)"
|
||||
STR_LONG_PRESS_SKIP: "Long-press Chapter Skip"
|
||||
STR_FONT_FAMILY: "Reader Font Family"
|
||||
STR_FONT_SIZE: "Reader Font Size"
|
||||
@@ -199,15 +197,10 @@ STR_CROP: "Crop"
|
||||
STR_NEVER: "Never"
|
||||
STR_IN_READER: "In Reader"
|
||||
STR_ALWAYS: "Always"
|
||||
STR_IGNORE: "Ignore"
|
||||
STR_SLEEP: "Sleep"
|
||||
STR_PAGE_TURN: "Page Turn"
|
||||
STR_PORTRAIT: "Portrait"
|
||||
STR_LANDSCAPE_CW: "Landscape CW"
|
||||
STR_INVERTED: "Inverted"
|
||||
STR_LANDSCAPE_CCW: "Landscape CCW"
|
||||
STR_PREV_NEXT: "Prev/Next"
|
||||
STR_NEXT_PREV: "Next/Prev"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
@@ -547,3 +540,42 @@ STR_CAPTIVE_PORTAL_DETECTED: "Login Required"
|
||||
STR_CAPTIVE_PORTAL_HINT_1: "Network requires browser login. On another device,"
|
||||
STR_CAPTIVE_PORTAL_HINT_2: "visit the URL below to authorize, then press OK."
|
||||
STR_CAPTIVE_PORTAL_DONE: "I'm authorized"
|
||||
STR_MENU_BTN_ACTIONS: "Button Actions"
|
||||
STR_MENU_BTN_PHYSICAL: "Physical Buttons"
|
||||
STR_BTN_SHORT_PRESS: "Short Press"
|
||||
STR_BTN_DOUBLE_PRESS: "Double Press"
|
||||
STR_BTN_LONG_PRESS: "Long Press"
|
||||
STR_BTN_BACK: "Back Button"
|
||||
STR_BTN_CONFIRM: "Confirm Button"
|
||||
STR_BTN_LEFT: "Left Button"
|
||||
STR_BTN_RIGHT: "Right Button"
|
||||
STR_BTN_PAGE_BACK: "Page Back Button"
|
||||
STR_BTN_PAGE_FORWARD: "Page Forward Button"
|
||||
STR_BTN_POWER: "Power Button"
|
||||
STR_BTN_ACT_DEFAULT: "Default"
|
||||
STR_BTN_DEF_IGNORE: "Default (ignore)"
|
||||
STR_BTN_DEF_EXIT_READER: "Default (exit reader)"
|
||||
STR_BTN_DEF_GO_HOME: "Default (go home)"
|
||||
STR_BTN_DEF_READER_MENU: "Default (reader menu)"
|
||||
STR_BTN_DEF_KOREADER_SYNC: "Default (KOReader sync)"
|
||||
STR_BTN_DEF_PREV_PAGE: "Default (previous page)"
|
||||
STR_BTN_DEF_NEXT_PAGE: "Default (next page)"
|
||||
STR_BTN_DEF_CHAPTER_BACK: "Default (chapter back)"
|
||||
STR_BTN_DEF_CHAPTER_FORWARD: "Default (chapter forward)"
|
||||
STR_BTN_DEF_SLEEP: "Default (sleep)"
|
||||
STR_BTN_ACT_PAGE_FORWARD: "Next Page"
|
||||
STR_BTN_ACT_PAGE_BACK: "Previous Page"
|
||||
STR_BTN_ACT_PAGE_FORWARD_10: "Skip 10 Pages Forward"
|
||||
STR_BTN_ACT_PAGE_BACK_10: "Skip 10 Pages Back"
|
||||
STR_BTN_ACT_GO_HOME: "Go Home"
|
||||
STR_BTN_ACT_SLEEP: "Sleep"
|
||||
STR_BTN_ACT_FORCE_REFRESH: "Refresh Screen"
|
||||
STR_BTN_ACT_OPEN_TOC: "Open Table of Contents"
|
||||
STR_BTN_ACT_OPEN_BOOKMARKS: "Open Bookmarks"
|
||||
STR_BTN_ACT_STAR_PAGE: "Star Page"
|
||||
STR_BTN_ACT_FOOTNOTES: "Footnotes"
|
||||
STR_BTN_ACT_NEXT_SECTION: "Next Section / Chapter"
|
||||
STR_BTN_ACT_PREV_SECTION: "Previous Section / Chapter"
|
||||
STR_BTN_ACT_EXIT_READER: "Exit Reader"
|
||||
STR_BTN_ACT_READER_MENU: "Reader Menu"
|
||||
STR_BTN_ACT_KOREADER_SYNC: "KOReader Sync"
|
||||
|
||||
@@ -66,9 +66,7 @@ STR_SLEEP_COVER_MODE: "Lepotilanäytön kansitila"
|
||||
STR_HIDE_BATTERY: "Piilota akun %"
|
||||
STR_EXTRA_SPACING: "Kappaleiden lisäväli"
|
||||
STR_TEXT_AA: "Tekstin reunanpehmennys"
|
||||
STR_SHORT_PWR_BTN: "Lyhyt virtapainikkeen painallus"
|
||||
STR_ORIENTATION: "Lukusuunta"
|
||||
STR_SIDE_BTN_LAYOUT: "Sivupainikkeiden asettelu (lukija)"
|
||||
STR_LONG_PRESS_SKIP: "Pitkä painallus: lukuhyppy"
|
||||
STR_FONT_FAMILY: "Lukijan fonttiperhe"
|
||||
STR_FONT_SIZE: "Käyttöliittymän fonttikoko"
|
||||
@@ -119,15 +117,10 @@ STR_CROP: "Rajaa"
|
||||
STR_NEVER: "Ei koskaan"
|
||||
STR_IN_READER: "Lukijassa"
|
||||
STR_ALWAYS: "Aina"
|
||||
STR_IGNORE: "Ohita"
|
||||
STR_SLEEP: "Lepotila"
|
||||
STR_PAGE_TURN: "Sivunkääntö"
|
||||
STR_PORTRAIT: "Pysty"
|
||||
STR_LANDSCAPE_CW: "Vaaka myötäpäivään"
|
||||
STR_INVERTED: "Käännetty"
|
||||
STR_LANDSCAPE_CCW: "Vaaka vastapäivään"
|
||||
STR_PREV_NEXT: "Edell/Seur"
|
||||
STR_NEXT_PREV: "Seur/Edell"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -91,9 +91,7 @@ STR_IMAGES: "Images"
|
||||
STR_IMAGES_DISPLAY: "Affichage"
|
||||
STR_IMAGES_PLACEHOLDER: "Espace réservé"
|
||||
STR_IMAGES_SUPPRESS: "Masquer"
|
||||
STR_SHORT_PWR_BTN: "Appui court alim."
|
||||
STR_ORIENTATION: "Orientation de lecture"
|
||||
STR_SIDE_BTN_LAYOUT: "Boutons latéraux"
|
||||
STR_LONG_PRESS_SKIP: "Appui long saut de chapitre"
|
||||
STR_FONT_FAMILY: "Police de caractères du lecteur"
|
||||
STR_FONT_SIZE: "Taille texte interface"
|
||||
@@ -147,15 +145,10 @@ STR_CROP: "Rogné"
|
||||
STR_NEVER: "Jamais"
|
||||
STR_IN_READER: "Dans le lecteur"
|
||||
STR_ALWAYS: "Toujours"
|
||||
STR_IGNORE: "Ignorer"
|
||||
STR_SLEEP: "Mise en veille"
|
||||
STR_PAGE_TURN: "Page suivante"
|
||||
STR_PORTRAIT: "Portrait"
|
||||
STR_LANDSCAPE_CW: "Paysage"
|
||||
STR_INVERTED: "Inversé"
|
||||
STR_LANDSCAPE_CCW: "Paysage inversé"
|
||||
STR_PREV_NEXT: "Préc/Suiv"
|
||||
STR_NEXT_PREV: "Suiv/Préc"
|
||||
STR_ABC: "abc"
|
||||
STR_FORCE_REFRESH: "Actualiser l'écran"
|
||||
STR_NEXT: "Suiv"
|
||||
|
||||
@@ -79,9 +79,7 @@ STR_IMAGE_DITHERING: "Bild-Dithering"
|
||||
STR_IMAGE_DITHER_BAYER: "Bayer"
|
||||
STR_IMAGE_DITHER_ATKINSON: "Atkinson"
|
||||
STR_IMAGE_DITHER_DIFFUSED_BAYER: "Diffundiertes Bayer"
|
||||
STR_SHORT_PWR_BTN: "An-Taste kurz drücken"
|
||||
STR_ORIENTATION: "Leseausrichtung"
|
||||
STR_SIDE_BTN_LAYOUT: "Seitliche Tasten (Lesen)"
|
||||
STR_LONG_PRESS_SKIP: "Langes Drücken springt Kap."
|
||||
STR_FONT_FAMILY: "Lese-Schriftfamilie"
|
||||
STR_FONT_SIZE: "Schriftgröße"
|
||||
@@ -138,15 +136,10 @@ STR_CROP: "Zuschnitt"
|
||||
STR_NEVER: "Nie"
|
||||
STR_IN_READER: "Beim Lesen"
|
||||
STR_ALWAYS: "Immer"
|
||||
STR_IGNORE: "Ignorieren"
|
||||
STR_SLEEP: "Standby"
|
||||
STR_PAGE_TURN: "Umblättern"
|
||||
STR_PORTRAIT: "Hochformat"
|
||||
STR_LANDSCAPE_CW: "Querformat rechts"
|
||||
STR_INVERTED: "Invertiert"
|
||||
STR_LANDSCAPE_CCW: "Querformat links"
|
||||
STR_PREV_NEXT: "Zurück/Weiter"
|
||||
STR_NEXT_PREV: "Weiter/Zurück"
|
||||
STR_ABC: "abc"
|
||||
STR_FORCE_REFRESH: "Bildschirm aktualisieren"
|
||||
STR_NEXT: "Weiter"
|
||||
|
||||
@@ -70,9 +70,7 @@ STR_IMAGES: "Képek"
|
||||
STR_IMAGES_DISPLAY: "Megjelenítés"
|
||||
STR_IMAGES_PLACEHOLDER: "Helyőrző"
|
||||
STR_IMAGES_SUPPRESS: "Elnyomás"
|
||||
STR_SHORT_PWR_BTN: "Rövid bekapcsológomb nyomás"
|
||||
STR_ORIENTATION: "Olvasási irány"
|
||||
STR_SIDE_BTN_LAYOUT: "Oldalsó gomb elrendezés (olvasó)"
|
||||
STR_LONG_PRESS_SKIP: "Hosszú nyomás - fejezet ugrás"
|
||||
STR_FONT_FAMILY: "Olvasó betűkészlet"
|
||||
STR_FONT_SIZE: "Olvasó betűméret"
|
||||
@@ -124,15 +122,10 @@ STR_CROP: "Körbevágás"
|
||||
STR_NEVER: "Soha"
|
||||
STR_IN_READER: "Olvasóban"
|
||||
STR_ALWAYS: "Mindig"
|
||||
STR_IGNORE: "Mellőzés"
|
||||
STR_SLEEP: "Alvás"
|
||||
STR_PAGE_TURN: "Lapozás"
|
||||
STR_PORTRAIT: "Álló"
|
||||
STR_LANDSCAPE_CW: "Fekvő jobbra"
|
||||
STR_INVERTED: "Fordított"
|
||||
STR_LANDSCAPE_CCW: "Fekvő balra"
|
||||
STR_PREV_NEXT: "Előző/Következő"
|
||||
STR_NEXT_PREV: "Következő/Előző"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -91,9 +91,7 @@ STR_IMAGES: "Immagini"
|
||||
STR_IMAGES_DISPLAY: "Visualizza"
|
||||
STR_IMAGES_PLACEHOLDER: "Segnaposto"
|
||||
STR_IMAGES_SUPPRESS: "Nascondi"
|
||||
STR_SHORT_PWR_BTN: "Pressione breve tasto accensione"
|
||||
STR_ORIENTATION: "Orientamento lettura"
|
||||
STR_SIDE_BTN_LAYOUT: "Pulsanti laterali (lettore)"
|
||||
STR_LONG_PRESS_SKIP: "Pressione lunga: salta capitolo"
|
||||
STR_FONT_FAMILY: "Font lettore"
|
||||
STR_FONT_SIZE: "Dimensione font lettore"
|
||||
@@ -147,15 +145,10 @@ STR_CROP: "Ritaglia"
|
||||
STR_NEVER: "Mai"
|
||||
STR_IN_READER: "Nel lettore"
|
||||
STR_ALWAYS: "Sempre"
|
||||
STR_IGNORE: "Ignora"
|
||||
STR_SLEEP: "Sospendi"
|
||||
STR_PAGE_TURN: "Cambio pagina"
|
||||
STR_PORTRAIT: "Verticale"
|
||||
STR_LANDSCAPE_CW: "Orizzontale ↻"
|
||||
STR_INVERTED: "Invertito"
|
||||
STR_LANDSCAPE_CCW: "Orizzontale ↺"
|
||||
STR_PREV_NEXT: "Prec/Succ"
|
||||
STR_NEXT_PREV: "Succ/Prec"
|
||||
STR_ABC: "abc"
|
||||
STR_FORCE_REFRESH: "Aggiorna schermo"
|
||||
STR_NEXT: "Succ"
|
||||
|
||||
@@ -65,9 +65,7 @@ STR_SLEEP_COVER_MODE: "Ұйқы экраны мұқаба режимі"
|
||||
STR_HIDE_BATTERY: "Батарея % жасыру"
|
||||
STR_EXTRA_SPACING: "Қосымша абзац аралығы"
|
||||
STR_TEXT_AA: "Мәтін сырғытпасы"
|
||||
STR_SHORT_PWR_BTN: "Қуат түймесін қысқа басу"
|
||||
STR_ORIENTATION: "Оқу бағдары"
|
||||
STR_SIDE_BTN_LAYOUT: "Бүйірлік түймелер орналасуы (оқырман)"
|
||||
STR_LONG_PRESS_SKIP: "Ұзақ басу арқылы тарау өткізу"
|
||||
STR_FONT_FAMILY: "Оқырман қаріп тобы"
|
||||
STR_FONT_SIZE: "Интерфейс қаріп өлшемі"
|
||||
@@ -118,15 +116,10 @@ STR_CROP: "Кесу"
|
||||
STR_NEVER: "Ешқашан"
|
||||
STR_IN_READER: "Оқырманда"
|
||||
STR_ALWAYS: "Әрқашан"
|
||||
STR_IGNORE: "Елемеу"
|
||||
STR_SLEEP: "Ұйқы"
|
||||
STR_PAGE_TURN: "Бет аудару"
|
||||
STR_PORTRAIT: "Тік бағдар"
|
||||
STR_LANDSCAPE_CW: "Көлденең (сағат бағытымен)"
|
||||
STR_INVERTED: "Төңкерілген"
|
||||
STR_LANDSCAPE_CCW: "Көлденең (сағат тіліне қарсы)"
|
||||
STR_PREV_NEXT: "Алдыңғы/Келесі"
|
||||
STR_NEXT_PREV: "Келесі/Алдыңғы"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -70,9 +70,7 @@ STR_IMAGES: "Paveikslėliai"
|
||||
STR_IMAGES_DISPLAY: "Rodyti"
|
||||
STR_IMAGES_PLACEHOLDER: "Vietaženklis"
|
||||
STR_IMAGES_SUPPRESS: "Slėpti"
|
||||
STR_SHORT_PWR_BTN: "Trumpas įjungimo pasp."
|
||||
STR_ORIENTATION: "Orientacija"
|
||||
STR_SIDE_BTN_LAYOUT: "Šoniniai mygtukai"
|
||||
STR_LONG_PRESS_SKIP: "Praleisti skyrių (ilgai)"
|
||||
STR_FONT_FAMILY: "Šriftas"
|
||||
STR_FONT_SIZE: "Šrifto dydis"
|
||||
@@ -124,15 +122,10 @@ STR_CROP: "Kirpti"
|
||||
STR_NEVER: "Niekada"
|
||||
STR_IN_READER: "Skaitytuve"
|
||||
STR_ALWAYS: "Visada"
|
||||
STR_IGNORE: "Nepaisyti"
|
||||
STR_SLEEP: "Miegas"
|
||||
STR_PAGE_TURN: "Versti psl."
|
||||
STR_PORTRAIT: "Stačias"
|
||||
STR_LANDSCAPE_CW: "Gulsčias (P)"
|
||||
STR_INVERTED: "Apverstas"
|
||||
STR_LANDSCAPE_CCW: "Gulsčias (A)"
|
||||
STR_PREV_NEXT: "Atgal/Pirmyn"
|
||||
STR_NEXT_PREV: "Pirmyn/Atgal"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "O. Dyslexic"
|
||||
|
||||
@@ -96,9 +96,7 @@ STR_IMAGE_DITHER_BAYER: "Bayer"
|
||||
STR_IMAGE_DITHER_ATKINSON: "Atkinson"
|
||||
STR_IMAGE_DITHER_DIFFUSED_BAYER: "Dyfundowany Bayer"
|
||||
STR_CREATE_FALLBACK_FOR_INVALID_TOC: "Utwórz fallback dla nieprawidłowego spisu treści"
|
||||
STR_SHORT_PWR_BTN: "Krótkie naciśnięcie zasilania"
|
||||
STR_ORIENTATION: "Układ czytania"
|
||||
STR_SIDE_BTN_LAYOUT: "Układ przycisków bocznych"
|
||||
STR_LONG_PRESS_SKIP: "Przytrzymaj aby przeskoczyć rozdział"
|
||||
STR_FONT_FAMILY: "Czcionka"
|
||||
STR_FONT_SIZE: "Rozmiar czcionki"
|
||||
@@ -199,15 +197,10 @@ STR_CROP: "Przytnij"
|
||||
STR_NEVER: "Nigdy"
|
||||
STR_IN_READER: "W czytniku"
|
||||
STR_ALWAYS: "Zawsze"
|
||||
STR_IGNORE: "Ignoruj"
|
||||
STR_SLEEP: "Uśpienie"
|
||||
STR_PAGE_TURN: "Nast. str."
|
||||
STR_PORTRAIT: "Pionowo"
|
||||
STR_LANDSCAPE_CW: "Poziomo P"
|
||||
STR_INVERTED: "Odwrócony"
|
||||
STR_LANDSCAPE_CCW: "Poziomo L"
|
||||
STR_PREV_NEXT: "Poprz./Nast."
|
||||
STR_NEXT_PREV: "Nast./Poprz."
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -95,9 +95,7 @@ STR_IMAGE_DITHERING: "Dithering de imagem"
|
||||
STR_IMAGE_DITHER_BAYER: "Bayer"
|
||||
STR_IMAGE_DITHER_ATKINSON: "Atkinson"
|
||||
STR_IMAGE_DITHER_DIFFUSED_BAYER: "Bayer difuso"
|
||||
STR_SHORT_PWR_BTN: "Clique curto no botão de ligar"
|
||||
STR_ORIENTATION: "Orientação de leitura"
|
||||
STR_SIDE_BTN_LAYOUT: "Disposição dos botões laterais"
|
||||
STR_LONG_PRESS_SKIP: "Pular capítulo com pressão longa"
|
||||
STR_FONT_FAMILY: "Fonte do leitor"
|
||||
STR_FONT_SIZE: "Tam. da fonte da UI"
|
||||
@@ -151,15 +149,10 @@ STR_CROP: "Recortar"
|
||||
STR_NEVER: "Nunca"
|
||||
STR_IN_READER: "No leitor"
|
||||
STR_ALWAYS: "Sempre"
|
||||
STR_IGNORE: "Ignorar"
|
||||
STR_SLEEP: "Repouso"
|
||||
STR_PAGE_TURN: "Virar página"
|
||||
STR_PORTRAIT: "Retrato"
|
||||
STR_LANDSCAPE_CW: "Paisagem H"
|
||||
STR_INVERTED: "Invertido"
|
||||
STR_LANDSCAPE_CCW: "Paisagem AH"
|
||||
STR_PREV_NEXT: "Ant/Próx"
|
||||
STR_NEXT_PREV: "Próx/Ant"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -87,9 +87,7 @@ STR_TEXT_AA: "Suavização do texto"
|
||||
STR_TEXT_DARKNESS: "Escuridão do texto"
|
||||
STR_EXTRA_DARK: "Extra escuro"
|
||||
STR_MAX_DARK: "Máximo"
|
||||
STR_SHORT_PWR_BTN: "Pressão curta do botão de energia"
|
||||
STR_ORIENTATION: "Orientação de leitura"
|
||||
STR_SIDE_BTN_LAYOUT: "Disposição dos botões laterais"
|
||||
STR_LONG_PRESS_SKIP: "Saltar capítulo com pressão longa"
|
||||
STR_FONT_FAMILY: "Tipo de letra do leitor"
|
||||
STR_FONT_SIZE: "Tamanho da letra do leitor"
|
||||
@@ -146,15 +144,10 @@ STR_CROP: "Recortar"
|
||||
STR_NEVER: "Nunca"
|
||||
STR_IN_READER: "No leitor"
|
||||
STR_ALWAYS: "Sempre"
|
||||
STR_IGNORE: "Ignorar"
|
||||
STR_SLEEP: "Repouso"
|
||||
STR_PAGE_TURN: "Virar página"
|
||||
STR_PORTRAIT: "Retrato"
|
||||
STR_LANDSCAPE_CW: "Paisagem H"
|
||||
STR_INVERTED: "Invertido"
|
||||
STR_LANDSCAPE_CCW: "Paisagem AH"
|
||||
STR_PREV_NEXT: "Ant./Próx."
|
||||
STR_NEXT_PREV: "Próx./Ant."
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -70,9 +70,7 @@ STR_IMAGES: "Imagini"
|
||||
STR_IMAGES_DISPLAY: "Afişare"
|
||||
STR_IMAGES_PLACEHOLDER: "Substituent"
|
||||
STR_IMAGES_SUPPRESS: "Suprimare"
|
||||
STR_SHORT_PWR_BTN: "Apăsare scurtă întrerupător"
|
||||
STR_ORIENTATION: "Orientare lectură"
|
||||
STR_SIDE_BTN_LAYOUT: "Aspect butoane laterale (lectură)"
|
||||
STR_LONG_PRESS_SKIP: "Sărire capitol la apăsare lungă"
|
||||
STR_FONT_FAMILY: "Familie font lectură"
|
||||
STR_FONT_SIZE: "Dimensiune font"
|
||||
@@ -124,15 +122,10 @@ STR_CROP: "Decupat"
|
||||
STR_NEVER: "Niciodată"
|
||||
STR_IN_READER: "În lectură"
|
||||
STR_ALWAYS: "Întotdeauna"
|
||||
STR_IGNORE: "Ignoră"
|
||||
STR_SLEEP: "Repaus"
|
||||
STR_PAGE_TURN: "Răsfoire pagină"
|
||||
STR_PORTRAIT: "Vertical"
|
||||
STR_LANDSCAPE_CW: "Orizontal dreapta"
|
||||
STR_INVERTED: "Invers"
|
||||
STR_LANDSCAPE_CCW: "Orizontal stânga"
|
||||
STR_PREV_NEXT: "Înainte/Înapoi"
|
||||
STR_NEXT_PREV: "Înapoi/Înainte"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -88,9 +88,7 @@ STR_IMAGES: "Изображения"
|
||||
STR_IMAGES_DISPLAY: "Показать"
|
||||
STR_IMAGES_PLACEHOLDER: "Заглушки"
|
||||
STR_IMAGES_SUPPRESS: "Скрыть"
|
||||
STR_SHORT_PWR_BTN: "Короткое нажатие PWR"
|
||||
STR_ORIENTATION: "Ориентация чтения"
|
||||
STR_SIDE_BTN_LAYOUT: "Боковые кнопки"
|
||||
STR_LONG_PRESS_SKIP: "Долгое нажатие - смена главы"
|
||||
STR_FONT_FAMILY: "Шрифт чтения"
|
||||
STR_FONT_SIZE: "Размер шрифта интерфейса"
|
||||
@@ -144,15 +142,10 @@ STR_CROP: "Обрезать"
|
||||
STR_NEVER: "Никогда"
|
||||
STR_IN_READER: "В режиме чтения"
|
||||
STR_ALWAYS: "Всегда"
|
||||
STR_IGNORE: "Игнорировать"
|
||||
STR_SLEEP: "Сон"
|
||||
STR_PAGE_TURN: "Перелистывание"
|
||||
STR_PORTRAIT: "Портрет"
|
||||
STR_LANDSCAPE_CW: "Ландшафт (CW)"
|
||||
STR_INVERTED: "Инверсия"
|
||||
STR_LANDSCAPE_CCW: "Ландшафт (CCW)"
|
||||
STR_PREV_NEXT: "Назад/Вперёд"
|
||||
STR_NEXT_PREV: "Вперёд/Назад"
|
||||
STR_ABC: "abc"
|
||||
STR_FORCE_REFRESH: "Обновить экран"
|
||||
STR_NEXT: "Далее"
|
||||
|
||||
@@ -84,9 +84,7 @@ STR_IMAGE_DITHER_BAYER: "Bayer"
|
||||
STR_IMAGE_DITHER_ATKINSON: "Atkinson"
|
||||
STR_IMAGE_DITHER_DIFFUSED_BAYER: "Difuzni Bayer"
|
||||
STR_CREATE_FALLBACK_FOR_INVALID_TOC: "Ustvari rezervo za neveljavno kazalo"
|
||||
STR_SHORT_PWR_BTN: "Kratek pritisk na gumb za vklop"
|
||||
STR_ORIENTATION: "Orientacija branja"
|
||||
STR_SIDE_BTN_LAYOUT: "Razpored stranskih gumbov"
|
||||
STR_LONG_PRESS_SKIP: "Dolgi pritisk za preskok poglavja"
|
||||
STR_FONT_FAMILY: "Pisava bralnika"
|
||||
STR_FONT_SIZE: "Velikost pisave"
|
||||
@@ -181,15 +179,10 @@ STR_CROP: "Obreži"
|
||||
STR_NEVER: "Nikoli"
|
||||
STR_IN_READER: "V bralniku"
|
||||
STR_ALWAYS: "Vedno"
|
||||
STR_IGNORE: "Prezri"
|
||||
STR_SLEEP: "Spanje"
|
||||
STR_PAGE_TURN: "Obračanje strani"
|
||||
STR_PORTRAIT: "Pokončno"
|
||||
STR_LANDSCAPE_CW: "Ležeče (v smeri urinega kazalca)"
|
||||
STR_INVERTED: "Obrnjeno"
|
||||
STR_LANDSCAPE_CCW: "Ležeče (proti smeri urinega kazalca)"
|
||||
STR_PREV_NEXT: "Nazaj/Naprej"
|
||||
STR_NEXT_PREV: "Naprej/Nazaj"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -85,9 +85,7 @@ STR_IMAGES: "Imágenes"
|
||||
STR_IMAGES_DISPLAY: "Mostrar"
|
||||
STR_IMAGES_PLACEHOLDER: "Reemplazar"
|
||||
STR_IMAGES_SUPPRESS: "Ocultar"
|
||||
STR_SHORT_PWR_BTN: "Toque corto botón encendido"
|
||||
STR_ORIENTATION: "Orientación"
|
||||
STR_SIDE_BTN_LAYOUT: "Función botones laterales (lector)"
|
||||
STR_LONG_PRESS_SKIP: "Saltar capítulo (pulsación larga)"
|
||||
STR_FONT_FAMILY: "Tipografía"
|
||||
STR_FONT_SIZE: "Tamaño"
|
||||
@@ -141,15 +139,10 @@ STR_CROP: "Recortar"
|
||||
STR_NEVER: "Nunca"
|
||||
STR_IN_READER: "En el lector"
|
||||
STR_ALWAYS: "Siempre"
|
||||
STR_IGNORE: "Ignorar"
|
||||
STR_SLEEP: "Suspender"
|
||||
STR_PAGE_TURN: "Pasar página"
|
||||
STR_PORTRAIT: "Vertical"
|
||||
STR_LANDSCAPE_CW: "Horizontal (horario)"
|
||||
STR_INVERTED: "Invertido"
|
||||
STR_LANDSCAPE_CCW: "Horizontal (antihorario)"
|
||||
STR_PREV_NEXT: "Ant./Sig."
|
||||
STR_NEXT_PREV: "Sig./Ant."
|
||||
STR_ABC: "abc"
|
||||
STR_FORCE_REFRESH: "Actualizar pantalla"
|
||||
STR_NEXT: "Sig"
|
||||
|
||||
@@ -96,9 +96,7 @@ STR_IMAGE_DITHER_BAYER: "Bayer"
|
||||
STR_IMAGE_DITHER_ATKINSON: "Atkinson"
|
||||
STR_IMAGE_DITHER_DIFFUSED_BAYER: "Diffus Bayer"
|
||||
STR_CREATE_FALLBACK_FOR_INVALID_TOC: "Skapa fallback för ogiltig innehållsförteckning"
|
||||
STR_SHORT_PWR_BTN: "Kort strömknappsklick"
|
||||
STR_ORIENTATION: "Läsrikting"
|
||||
STR_SIDE_BTN_LAYOUT: "Sidoknappslayout (Läsare)"
|
||||
STR_LONG_PRESS_SKIP: "Lång-tryck Kapitelskippning"
|
||||
STR_FONT_FAMILY: "Eboksläsarens typsnittsfamilj"
|
||||
STR_FONT_SIZE: "Eboksläsarens typsnittsstorlek"
|
||||
@@ -199,15 +197,10 @@ STR_CROP: "Beskär"
|
||||
STR_NEVER: "Aldrig"
|
||||
STR_IN_READER: "I Eboksläsare"
|
||||
STR_ALWAYS: "Alltid"
|
||||
STR_IGNORE: "Ignorera"
|
||||
STR_SLEEP: "Vila"
|
||||
STR_PAGE_TURN: "Sidvändning"
|
||||
STR_PORTRAIT: "Porträtt"
|
||||
STR_LANDSCAPE_CW: "Landskap medurs"
|
||||
STR_INVERTED: "Inverterad"
|
||||
STR_LANDSCAPE_CCW: "Landskap moturs"
|
||||
STR_PREV_NEXT: "Förra/Nästa"
|
||||
STR_NEXT_PREV: "Nästa/Förra"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Öppen Dyslexic"
|
||||
|
||||
@@ -65,9 +65,7 @@ STR_SLEEP_COVER_MODE: "Uyku Ekranı Kapak Modu"
|
||||
STR_HIDE_BATTERY: "Pil Yüzdesini Gizle"
|
||||
STR_EXTRA_SPACING: "Ekstra Paragraf Boşluğu"
|
||||
STR_TEXT_AA: "Metin Yumuşatma (AA)"
|
||||
STR_SHORT_PWR_BTN: "Kısa Güç Tuşu Tıklaması"
|
||||
STR_ORIENTATION: "Okuma Yönü"
|
||||
STR_SIDE_BTN_LAYOUT: "Yan Tuş Dizilimi (okuyucu)"
|
||||
STR_LONG_PRESS_SKIP: "Uzun Basışla Bölüm Atla"
|
||||
STR_FONT_FAMILY: "Okuyucu Yazı Tipi Ailesi"
|
||||
STR_FONT_SIZE: "Arayüz Yazı Boyutu"
|
||||
@@ -120,15 +118,10 @@ STR_CROP: "Kırp"
|
||||
STR_NEVER: "Asla"
|
||||
STR_IN_READER: "Okuyucuda"
|
||||
STR_ALWAYS: "Her Zaman"
|
||||
STR_IGNORE: "Yoksay"
|
||||
STR_SLEEP: "Uyku"
|
||||
STR_PAGE_TURN: "Sayfa Çevirme"
|
||||
STR_PORTRAIT: "Dikey"
|
||||
STR_LANDSCAPE_CW: "Yatay (Saat Yönü)"
|
||||
STR_INVERTED: "Ters"
|
||||
STR_LANDSCAPE_CCW: "Yatay (Saat Yönü Tersi)"
|
||||
STR_PREV_NEXT: "Önceki/Sonraki"
|
||||
STR_NEXT_PREV: "Sonraki/Önceki"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -95,9 +95,7 @@ STR_IMAGE_DITHERING: "Дітеринг зображення"
|
||||
STR_IMAGE_DITHER_BAYER: "Bayer"
|
||||
STR_IMAGE_DITHER_ATKINSON: "Atkinson"
|
||||
STR_IMAGE_DITHER_DIFFUSED_BAYER: "Дифузний Bayer"
|
||||
STR_SHORT_PWR_BTN: "Коротке натискання кнопки живлення"
|
||||
STR_ORIENTATION: "Орієнтація читання"
|
||||
STR_SIDE_BTN_LAYOUT: "Розташування бічних кнопок (читач)"
|
||||
STR_LONG_PRESS_SKIP: "Пропуск розділу при довгому натисканні"
|
||||
STR_FONT_FAMILY: "Сімейство шрифтів"
|
||||
STR_FONT_SIZE: "Розмір шрифту інтерфейсу"
|
||||
@@ -151,15 +149,10 @@ STR_CROP: "Обрізати"
|
||||
STR_NEVER: "Ніколи"
|
||||
STR_IN_READER: "В читачі"
|
||||
STR_ALWAYS: "Завжди"
|
||||
STR_IGNORE: "Ігнорувати"
|
||||
STR_SLEEP: "Сон"
|
||||
STR_PAGE_TURN: "Перегортання сторінки"
|
||||
STR_PORTRAIT: "Портрет"
|
||||
STR_LANDSCAPE_CW: "Альбомний за годинниковою"
|
||||
STR_INVERTED: "Перевернутий"
|
||||
STR_LANDSCAPE_CCW: "Альбомний проти годинникової"
|
||||
STR_PREV_NEXT: "Попер/Наст"
|
||||
STR_NEXT_PREV: "Наст/Попер"
|
||||
STR_BOOKERLY: "Bookerly"
|
||||
STR_NOTO_SANS: "Noto Sans"
|
||||
STR_OPEN_DYSLEXIC: "Open Dyslexic"
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
#include "ButtonEventManager.h"
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
|
||||
// Required for constexpr array out-of-class definition (C++14).
|
||||
constexpr ButtonEventManager::Button ButtonEventManager::ALL_BUTTONS[ButtonEventManager::NUM_BUTTONS];
|
||||
|
||||
bool ButtonEventManager::hasDoubleAction(const Button button) {
|
||||
using BA = CrossPointSettings::BUTTON_ACTION;
|
||||
switch (button) {
|
||||
case Button::Back:
|
||||
return SETTINGS.btnDoubleBack != BA::BTN_DEFAULT;
|
||||
case Button::Confirm:
|
||||
return SETTINGS.btnDoubleConfirm != BA::BTN_DEFAULT;
|
||||
case Button::Left:
|
||||
return SETTINGS.btnDoubleLeft != BA::BTN_DEFAULT;
|
||||
case Button::Right:
|
||||
return SETTINGS.btnDoubleRight != BA::BTN_DEFAULT;
|
||||
case Button::PageBack:
|
||||
return SETTINGS.btnDoublePageBack != BA::BTN_DEFAULT;
|
||||
case Button::PageForward:
|
||||
return SETTINGS.btnDoublePageForward != BA::BTN_DEFAULT;
|
||||
case Button::Power:
|
||||
return SETTINGS.btnDoublePower != BA::BTN_DEFAULT;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ButtonEventManager::pushEvent(const Button button, const PressType type) {
|
||||
const int next = (eventTail + 1) % EVENT_BUF;
|
||||
if (next == eventHead) return; // buffer full, drop oldest not possible — just drop newest
|
||||
eventBuf[eventTail] = {button, type};
|
||||
eventTail = next;
|
||||
}
|
||||
|
||||
bool ButtonEventManager::consumeEvent(ButtonEvent& out) {
|
||||
if (eventHead == eventTail) return false;
|
||||
out = eventBuf[eventHead];
|
||||
eventHead = (eventHead + 1) % EVENT_BUF;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ButtonEventManager::drain() {
|
||||
for (auto& b : buttons) {
|
||||
b.state = State::Idle;
|
||||
b.pressDownTime = 0;
|
||||
b.releaseTime = 0;
|
||||
}
|
||||
eventHead = eventTail = 0;
|
||||
}
|
||||
|
||||
void ButtonEventManager::processButton(const int idx, const Button btn) {
|
||||
PerButton& s = buttons[idx];
|
||||
const unsigned long now = millis();
|
||||
const bool pressed = input.wasPressed(btn);
|
||||
const bool released = input.wasReleased(btn);
|
||||
const bool held = input.isPressed(btn);
|
||||
|
||||
switch (s.state) {
|
||||
case State::Idle:
|
||||
if (pressed) {
|
||||
s.state = State::Pressed;
|
||||
s.pressDownTime = now;
|
||||
}
|
||||
break;
|
||||
|
||||
case State::Pressed:
|
||||
if (released) {
|
||||
const unsigned long heldMs = now - s.pressDownTime;
|
||||
if (heldMs >= LONG_PRESS_MS) {
|
||||
pushEvent(btn, PressType::Long);
|
||||
s.state = State::Idle;
|
||||
} else if (hasDoubleAction(btn)) {
|
||||
// Delay short-press decision until double-click window expires
|
||||
s.releaseTime = now;
|
||||
s.state = State::ReleasedOnce;
|
||||
} else {
|
||||
// No double action configured — fire immediately
|
||||
pushEvent(btn, PressType::Short);
|
||||
s.state = State::Idle;
|
||||
}
|
||||
} else if (!held) {
|
||||
// Button disappeared without wasReleased edge (e.g. after drain) — reset
|
||||
s.state = State::Idle;
|
||||
}
|
||||
break;
|
||||
|
||||
case State::ReleasedOnce:
|
||||
if (pressed) {
|
||||
// Second press within window — start tracking it
|
||||
s.state = State::DoublePressed;
|
||||
s.pressDownTime = now;
|
||||
} else if (now - s.releaseTime >= DOUBLE_WINDOW_MS) {
|
||||
// Window expired without a second press — it was a short press
|
||||
pushEvent(btn, PressType::Short);
|
||||
s.state = State::Idle;
|
||||
}
|
||||
break;
|
||||
|
||||
case State::DoublePressed:
|
||||
if (released) {
|
||||
pushEvent(btn, PressType::Double);
|
||||
s.state = State::Idle;
|
||||
} else if (!held) {
|
||||
// Disappeared without edge — treat as double anyway
|
||||
pushEvent(btn, PressType::Double);
|
||||
s.state = State::Idle;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonEventManager::update() {
|
||||
for (int i = 0; i < NUM_BUTTONS; i++) {
|
||||
processButton(i, ALL_BUTTONS[i]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include "MappedInputManager.h"
|
||||
|
||||
// Forward declaration for the global accessor used by Activity.h.
|
||||
// Defined in main.cpp alongside the ButtonEventManager instance.
|
||||
class ButtonEventManager;
|
||||
ButtonEventManager& globalButtonEvents();
|
||||
|
||||
// Classifies raw button edges into Short, Double, and Long press events.
|
||||
//
|
||||
// Per-button state machines run each loop() tick. The key latency rule:
|
||||
// - If no double-click action is configured for a button, Short fires immediately
|
||||
// on release (zero extra wait).
|
||||
// - If a double-click action IS configured, Short is delayed by DOUBLE_WINDOW_MS
|
||||
// to allow disambiguation.
|
||||
// - Long fires on release once hold time >= LONG_PRESS_MS (no extra wait).
|
||||
// - Double fires on the second release within DOUBLE_WINDOW_MS.
|
||||
//
|
||||
// Activities query consumeEvent() each loop tick to receive pending events.
|
||||
// drain() resets all state machines — call it on activity transitions.
|
||||
|
||||
class ButtonEventManager {
|
||||
public:
|
||||
using Button = MappedInputManager::Button;
|
||||
|
||||
enum class PressType { Short, Double, Long };
|
||||
|
||||
struct ButtonEvent {
|
||||
Button button;
|
||||
PressType type;
|
||||
};
|
||||
|
||||
// Timing constants (milliseconds)
|
||||
static constexpr unsigned long LONG_PRESS_MS = 600;
|
||||
static constexpr unsigned long DOUBLE_WINDOW_MS = 300;
|
||||
|
||||
explicit ButtonEventManager(MappedInputManager& input) : input(input) {}
|
||||
|
||||
// Call once per main loop tick, after MappedInputManager::update().
|
||||
void update();
|
||||
|
||||
// Returns the next pending event, or false if none. Call repeatedly until
|
||||
// false to drain all events for this tick.
|
||||
bool consumeEvent(ButtonEvent& out);
|
||||
|
||||
// Reset all per-button FSMs. Call on activity transitions to prevent bleed-through.
|
||||
void drain();
|
||||
|
||||
// Returns true if a double-click action is configured for this button.
|
||||
// ButtonEventManager queries CrossPointSettings internally.
|
||||
static bool hasDoubleAction(Button button);
|
||||
|
||||
private:
|
||||
static constexpr int NUM_BUTTONS = 7;
|
||||
static constexpr Button ALL_BUTTONS[NUM_BUTTONS] = {
|
||||
Button::Back, Button::Confirm, Button::Left, Button::Right, Button::PageBack, Button::PageForward, Button::Power,
|
||||
};
|
||||
|
||||
enum class State { Idle, Pressed, ReleasedOnce, DoublePressed };
|
||||
|
||||
struct PerButton {
|
||||
State state = State::Idle;
|
||||
unsigned long pressDownTime = 0; // when the current (or first) press started
|
||||
unsigned long releaseTime = 0; // when the first release happened (for double-click window)
|
||||
};
|
||||
|
||||
PerButton buttons[NUM_BUTTONS];
|
||||
|
||||
// Pending events ring buffer (small — at most one event per button per tick)
|
||||
static constexpr int EVENT_BUF = 16;
|
||||
ButtonEvent eventBuf[EVENT_BUF] = {};
|
||||
int eventHead = 0;
|
||||
int eventTail = 0;
|
||||
|
||||
MappedInputManager& input;
|
||||
|
||||
void pushEvent(Button button, PressType type);
|
||||
void processButton(int idx, Button btn);
|
||||
};
|
||||
@@ -140,7 +140,10 @@ bool CrossPointSettings::loadFromBinaryFile() {
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
serialization::readPod(inputFile, extraParagraphSpacing);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
readAndValidate(inputFile, shortPwrBtn, SHORT_PWRBTN_COUNT);
|
||||
{
|
||||
uint8_t ignored;
|
||||
serialization::readPod(inputFile, ignored);
|
||||
} // legacy shortPwrBtn field
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
readAndValidate(inputFile, statusBar, STATUS_BAR_MODE_COUNT); // legacy
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
@@ -148,7 +151,10 @@ bool CrossPointSettings::loadFromBinaryFile() {
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
readAndValidate(inputFile, frontButtonLayout, FRONT_BUTTON_LAYOUT_COUNT);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
readAndValidate(inputFile, sideButtonLayout, SIDE_BUTTON_LAYOUT_COUNT);
|
||||
{
|
||||
uint8_t ignored;
|
||||
serialization::readPod(inputFile, ignored);
|
||||
} // legacy sideButtonLayout field
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
readAndValidate(inputFile, fontFamily, FONT_FAMILY_COUNT);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
@@ -177,7 +183,10 @@ bool CrossPointSettings::loadFromBinaryFile() {
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
readAndValidate(inputFile, hideBatteryPercentage, HIDE_BATTERY_PERCENTAGE_COUNT);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
serialization::readPod(inputFile, longPressChapterSkip);
|
||||
{
|
||||
uint8_t ignored;
|
||||
serialization::readPod(inputFile, ignored);
|
||||
} // was longPressChapterSkip
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
serialization::readPod(inputFile, hyphenationEnabled);
|
||||
if (++settingsRead >= fileSettingsCount) break;
|
||||
|
||||
+51
-24
@@ -88,11 +88,6 @@ class CrossPointSettings {
|
||||
FRONT_BUTTON_HARDWARE_COUNT
|
||||
};
|
||||
|
||||
// Side button layout options
|
||||
// Default: Previous, Next
|
||||
// Swapped: Next, Previous
|
||||
enum SIDE_BUTTON_LAYOUT { PREV_NEXT = 0, NEXT_PREV = 1, SIDE_BUTTON_LAYOUT_COUNT };
|
||||
|
||||
// Font family options
|
||||
enum FONT_FAMILY { BOOKERLY = 0, NOTOSANS = 1, OPENDYSLEXIC = 2, FONT_FAMILY_COUNT };
|
||||
// Font size options
|
||||
@@ -127,17 +122,6 @@ class CrossPointSettings {
|
||||
REFRESH_FREQUENCY_COUNT
|
||||
};
|
||||
|
||||
// Short power button press actions
|
||||
enum SHORT_PWRBTN {
|
||||
IGNORE = 0,
|
||||
SLEEP = 1,
|
||||
PAGE_TURN = 2,
|
||||
FORCE_REFRESH = 3,
|
||||
FOOTNOTES = 4,
|
||||
STAR_PAGE = 5,
|
||||
SHORT_PWRBTN_COUNT
|
||||
};
|
||||
|
||||
// Hide battery percentage
|
||||
enum HIDE_BATTERY_PERCENTAGE { HIDE_NEVER = 0, HIDE_READER = 1, HIDE_ALWAYS = 2, HIDE_BATTERY_PERCENTAGE_COUNT };
|
||||
|
||||
@@ -214,14 +198,11 @@ class CrossPointSettings {
|
||||
// Text darkness (0 = normal, 1 = dark, 2 = extra dark). Default 1 preserves
|
||||
// historical AA rendering (both grayscale shades drawn in the MSB pass).
|
||||
uint8_t textDarkness = DARKNESS_DARK;
|
||||
// Short power button click behaviour
|
||||
uint8_t shortPwrBtn = IGNORE;
|
||||
// EPUB reading orientation settings
|
||||
// 0 = portrait (default), 1 = landscape clockwise, 2 = inverted, 3 = landscape counter-clockwise
|
||||
uint8_t orientation = PORTRAIT;
|
||||
// Button layouts (front layout retained for migration only)
|
||||
uint8_t frontButtonLayout = BACK_CONFIRM_LEFT_RIGHT;
|
||||
uint8_t sideButtonLayout = PREV_NEXT;
|
||||
// Front button remap (logical -> hardware)
|
||||
// Used by MappedInputManager to translate logical buttons into physical front buttons.
|
||||
uint8_t frontButtonBack = FRONT_HW_BACK;
|
||||
@@ -249,8 +230,6 @@ class CrossPointSettings {
|
||||
char opdsPassword[64] = "";
|
||||
// Hide battery percentage
|
||||
uint8_t hideBatteryPercentage = HIDE_NEVER;
|
||||
// Long-press chapter skip on side buttons
|
||||
uint8_t longPressChapterSkip = 1;
|
||||
// UI Theme
|
||||
uint8_t uiTheme = LYRA;
|
||||
// Sunlight fading compensation
|
||||
@@ -279,14 +258,62 @@ class CrossPointSettings {
|
||||
// Show the Weather home screen menu item (1 = enabled, 0 = hidden)
|
||||
uint8_t useWeather = 1;
|
||||
|
||||
// Configurable actions for short / double / long press on each logical button.
|
||||
// BTN_DEFAULT means "use the button's normal built-in behaviour".
|
||||
enum BUTTON_ACTION {
|
||||
BTN_DEFAULT = 0,
|
||||
BTN_PAGE_FORWARD,
|
||||
BTN_PAGE_BACK,
|
||||
BTN_PAGE_FORWARD_10,
|
||||
BTN_PAGE_BACK_10,
|
||||
BTN_GO_HOME,
|
||||
BTN_SLEEP,
|
||||
BTN_FORCE_REFRESH,
|
||||
BTN_OPEN_TOC,
|
||||
BTN_OPEN_BOOKMARKS,
|
||||
BTN_STAR_PAGE,
|
||||
BTN_FOOTNOTES,
|
||||
BTN_NEXT_SECTION,
|
||||
BTN_PREV_SECTION,
|
||||
BTN_EXIT_READER,
|
||||
BTN_READER_MENU,
|
||||
BTN_KOREADER_SYNC,
|
||||
BUTTON_ACTION_COUNT
|
||||
};
|
||||
|
||||
// Short-press actions (default: built-in)
|
||||
uint8_t btnShortBack = BTN_DEFAULT;
|
||||
uint8_t btnShortConfirm = BTN_DEFAULT;
|
||||
uint8_t btnShortLeft = BTN_DEFAULT;
|
||||
uint8_t btnShortRight = BTN_DEFAULT;
|
||||
uint8_t btnShortPageBack = BTN_DEFAULT;
|
||||
uint8_t btnShortPageForward = BTN_DEFAULT;
|
||||
uint8_t btnShortPower = BTN_DEFAULT;
|
||||
|
||||
// Double-press actions (default: BTN_DEFAULT = disabled, no disambiguation wait)
|
||||
uint8_t btnDoubleBack = BTN_DEFAULT;
|
||||
uint8_t btnDoubleConfirm = BTN_DEFAULT;
|
||||
uint8_t btnDoubleLeft = BTN_DEFAULT;
|
||||
uint8_t btnDoubleRight = BTN_DEFAULT;
|
||||
uint8_t btnDoublePageBack = BTN_DEFAULT;
|
||||
uint8_t btnDoublePageForward = BTN_DEFAULT;
|
||||
uint8_t btnDoublePower = BTN_DEFAULT;
|
||||
|
||||
// Long-press actions (default: built-in)
|
||||
uint8_t btnLongBack = BTN_DEFAULT;
|
||||
uint8_t btnLongConfirm = BTN_DEFAULT;
|
||||
uint8_t btnLongLeft = BTN_DEFAULT;
|
||||
uint8_t btnLongRight = BTN_DEFAULT;
|
||||
uint8_t btnLongPageBack = BTN_DEFAULT;
|
||||
uint8_t btnLongPageForward = BTN_DEFAULT;
|
||||
uint8_t btnLongPower = BTN_DEFAULT;
|
||||
|
||||
~CrossPointSettings() = default;
|
||||
|
||||
// Get singleton instance
|
||||
static CrossPointSettings& getInstance() { return instance; }
|
||||
|
||||
uint16_t getPowerButtonDuration() const {
|
||||
return (shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::SLEEP) ? 10 : 400;
|
||||
}
|
||||
static constexpr uint16_t getPowerButtonDuration() { return 400; }
|
||||
int getReaderFontId() const;
|
||||
|
||||
// If count_only is true, returns the number of settings items that would be written.
|
||||
|
||||
@@ -2,55 +2,27 @@
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
|
||||
namespace {
|
||||
using ButtonIndex = uint8_t;
|
||||
|
||||
struct SideLayoutMap {
|
||||
ButtonIndex pageBack;
|
||||
ButtonIndex pageForward;
|
||||
};
|
||||
|
||||
// Order matches CrossPointSettings::SIDE_BUTTON_LAYOUT.
|
||||
constexpr SideLayoutMap kSideLayouts[] = {
|
||||
{HalGPIO::BTN_UP, HalGPIO::BTN_DOWN},
|
||||
{HalGPIO::BTN_DOWN, HalGPIO::BTN_UP},
|
||||
};
|
||||
} // namespace
|
||||
|
||||
bool MappedInputManager::mapButton(const Button button, bool (HalGPIO::*fn)(uint8_t) const) const {
|
||||
const auto sideLayout = static_cast<CrossPointSettings::SIDE_BUTTON_LAYOUT>(SETTINGS.sideButtonLayout);
|
||||
const auto& side = kSideLayouts[sideLayout];
|
||||
|
||||
switch (button) {
|
||||
case Button::Back:
|
||||
// Logical Back maps to user-configured front button.
|
||||
return (gpio.*fn)(SETTINGS.frontButtonBack);
|
||||
case Button::Confirm:
|
||||
// Logical Confirm maps to user-configured front button.
|
||||
return (gpio.*fn)(SETTINGS.frontButtonConfirm);
|
||||
case Button::Left:
|
||||
// Logical Left maps to user-configured front button.
|
||||
return (gpio.*fn)(SETTINGS.frontButtonLeft);
|
||||
case Button::Right:
|
||||
// Logical Right maps to user-configured front button.
|
||||
return (gpio.*fn)(SETTINGS.frontButtonRight);
|
||||
case Button::Up:
|
||||
// Side buttons remain fixed for Up/Down.
|
||||
return (gpio.*fn)(HalGPIO::BTN_UP);
|
||||
case Button::Down:
|
||||
// Side buttons remain fixed for Up/Down.
|
||||
return (gpio.*fn)(HalGPIO::BTN_DOWN);
|
||||
case Button::Power:
|
||||
// Power button bypasses remapping.
|
||||
return (gpio.*fn)(HalGPIO::BTN_POWER);
|
||||
case Button::PageBack:
|
||||
// Reader page navigation uses side buttons and can be swapped via settings.
|
||||
return (gpio.*fn)(side.pageBack);
|
||||
return (gpio.*fn)(HalGPIO::BTN_UP);
|
||||
case Button::PageForward:
|
||||
// Reader page navigation uses side buttons and can be swapped via settings.
|
||||
return (gpio.*fn)(side.pageForward);
|
||||
return (gpio.*fn)(HalGPIO::BTN_DOWN);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+87
-9
@@ -130,15 +130,93 @@ inline const std::vector<SettingInfo> list = {
|
||||
"syntheticTocFallback", StrId::STR_CAT_READER)
|
||||
.withSubcategory(StrId::STR_MENU_READER_TWEAKS),
|
||||
|
||||
// --- Controls ---
|
||||
SettingInfo::Enum(StrId::STR_SIDE_BTN_LAYOUT, &CrossPointSettings::sideButtonLayout,
|
||||
{StrId::STR_PREV_NEXT, StrId::STR_NEXT_PREV}, "sideButtonLayout", StrId::STR_CAT_CONTROLS),
|
||||
SettingInfo::Toggle(StrId::STR_LONG_PRESS_SKIP, &CrossPointSettings::longPressChapterSkip, "longPressChapterSkip",
|
||||
StrId::STR_CAT_CONTROLS),
|
||||
SettingInfo::Enum(StrId::STR_SHORT_PWR_BTN, &CrossPointSettings::shortPwrBtn,
|
||||
{StrId::STR_IGNORE, StrId::STR_SLEEP, StrId::STR_PAGE_TURN, StrId::STR_FORCE_REFRESH,
|
||||
StrId::STR_FOOTNOTES, StrId::STR_STAR_PAGE},
|
||||
"shortPwrBtn", StrId::STR_CAT_CONTROLS),
|
||||
// --- Controls ---
|
||||
// --- Button Actions (short / double / long press per logical button) ---
|
||||
// All entries share the same ordered action-label list; the submenu groups them behind
|
||||
// a single placeholder row in the device UI.
|
||||
// Shared action options (everything except the first "default" entry).
|
||||
#define BTN_ACT_OPTIONS \
|
||||
StrId::STR_BTN_ACT_PAGE_FORWARD, StrId::STR_BTN_ACT_PAGE_BACK, StrId::STR_BTN_ACT_PAGE_FORWARD_10, \
|
||||
StrId::STR_BTN_ACT_PAGE_BACK_10, StrId::STR_BTN_ACT_GO_HOME, StrId::STR_BTN_ACT_SLEEP, \
|
||||
StrId::STR_BTN_ACT_FORCE_REFRESH, StrId::STR_BTN_ACT_OPEN_TOC, StrId::STR_BTN_ACT_OPEN_BOOKMARKS, \
|
||||
StrId::STR_BTN_ACT_STAR_PAGE, StrId::STR_BTN_ACT_FOOTNOTES, StrId::STR_BTN_ACT_NEXT_SECTION, \
|
||||
StrId::STR_BTN_ACT_PREV_SECTION, StrId::STR_BTN_ACT_EXIT_READER, StrId::STR_BTN_ACT_READER_MENU, \
|
||||
StrId::STR_BTN_ACT_KOREADER_SYNC
|
||||
|
||||
// Back button: short=exit reader, double=ignore, long=go home
|
||||
SettingInfo::Enum(StrId::STR_BTN_SHORT_PRESS, &CrossPointSettings::btnShortBack,
|
||||
{StrId::STR_BTN_DEF_EXIT_READER, BTN_ACT_OPTIONS}, "btnShortBack", StrId::STR_CAT_CONTROLS)
|
||||
.withSubcategory(StrId::STR_MENU_BTN_ACTIONS)
|
||||
.withSubmenu(StrId::STR_BTN_BACK),
|
||||
SettingInfo::Enum(StrId::STR_BTN_DOUBLE_PRESS, &CrossPointSettings::btnDoubleBack,
|
||||
{StrId::STR_BTN_DEF_IGNORE, BTN_ACT_OPTIONS}, "btnDoubleBack", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_BACK),
|
||||
SettingInfo::Enum(StrId::STR_BTN_LONG_PRESS, &CrossPointSettings::btnLongBack,
|
||||
{StrId::STR_BTN_DEF_GO_HOME, BTN_ACT_OPTIONS}, "btnLongBack", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_BACK),
|
||||
// Confirm button: short=reader menu, double=ignore, long=KOReader sync
|
||||
SettingInfo::Enum(StrId::STR_BTN_SHORT_PRESS, &CrossPointSettings::btnShortConfirm,
|
||||
{StrId::STR_BTN_DEF_READER_MENU, BTN_ACT_OPTIONS}, "btnShortConfirm", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_CONFIRM),
|
||||
SettingInfo::Enum(StrId::STR_BTN_DOUBLE_PRESS, &CrossPointSettings::btnDoubleConfirm,
|
||||
{StrId::STR_BTN_DEF_IGNORE, BTN_ACT_OPTIONS}, "btnDoubleConfirm", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_CONFIRM),
|
||||
SettingInfo::Enum(StrId::STR_BTN_LONG_PRESS, &CrossPointSettings::btnLongConfirm,
|
||||
{StrId::STR_BTN_DEF_KOREADER_SYNC, BTN_ACT_OPTIONS}, "btnLongConfirm", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_CONFIRM),
|
||||
// Left button: short=previous page, double=ignore, long=chapter back
|
||||
SettingInfo::Enum(StrId::STR_BTN_SHORT_PRESS, &CrossPointSettings::btnShortLeft,
|
||||
{StrId::STR_BTN_DEF_PREV_PAGE, BTN_ACT_OPTIONS}, "btnShortLeft", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_LEFT),
|
||||
SettingInfo::Enum(StrId::STR_BTN_DOUBLE_PRESS, &CrossPointSettings::btnDoubleLeft,
|
||||
{StrId::STR_BTN_DEF_IGNORE, BTN_ACT_OPTIONS}, "btnDoubleLeft", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_LEFT),
|
||||
SettingInfo::Enum(StrId::STR_BTN_LONG_PRESS, &CrossPointSettings::btnLongLeft,
|
||||
{StrId::STR_BTN_DEF_CHAPTER_BACK, BTN_ACT_OPTIONS}, "btnLongLeft", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_LEFT),
|
||||
// Right button: short=next page, double=ignore, long=chapter forward
|
||||
SettingInfo::Enum(StrId::STR_BTN_SHORT_PRESS, &CrossPointSettings::btnShortRight,
|
||||
{StrId::STR_BTN_DEF_NEXT_PAGE, BTN_ACT_OPTIONS}, "btnShortRight", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_RIGHT),
|
||||
SettingInfo::Enum(StrId::STR_BTN_DOUBLE_PRESS, &CrossPointSettings::btnDoubleRight,
|
||||
{StrId::STR_BTN_DEF_IGNORE, BTN_ACT_OPTIONS}, "btnDoubleRight", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_RIGHT),
|
||||
SettingInfo::Enum(StrId::STR_BTN_LONG_PRESS, &CrossPointSettings::btnLongRight,
|
||||
{StrId::STR_BTN_DEF_CHAPTER_FORWARD, BTN_ACT_OPTIONS}, "btnLongRight", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_RIGHT),
|
||||
// Page Back button: short=previous page, double=ignore, long=chapter back
|
||||
SettingInfo::Enum(StrId::STR_BTN_SHORT_PRESS, &CrossPointSettings::btnShortPageBack,
|
||||
{StrId::STR_BTN_DEF_PREV_PAGE, BTN_ACT_OPTIONS}, "btnShortPageBack", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_PAGE_BACK),
|
||||
SettingInfo::Enum(StrId::STR_BTN_DOUBLE_PRESS, &CrossPointSettings::btnDoublePageBack,
|
||||
{StrId::STR_BTN_DEF_IGNORE, BTN_ACT_OPTIONS}, "btnDoublePageBack", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_PAGE_BACK),
|
||||
SettingInfo::Enum(StrId::STR_BTN_LONG_PRESS, &CrossPointSettings::btnLongPageBack,
|
||||
{StrId::STR_BTN_DEF_CHAPTER_BACK, BTN_ACT_OPTIONS}, "btnLongPageBack", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_PAGE_BACK),
|
||||
// Page Forward button: short=next page, double=ignore, long=chapter forward
|
||||
SettingInfo::Enum(StrId::STR_BTN_SHORT_PRESS, &CrossPointSettings::btnShortPageForward,
|
||||
{StrId::STR_BTN_DEF_NEXT_PAGE, BTN_ACT_OPTIONS}, "btnShortPageForward", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_PAGE_FORWARD),
|
||||
SettingInfo::Enum(StrId::STR_BTN_DOUBLE_PRESS, &CrossPointSettings::btnDoublePageForward,
|
||||
{StrId::STR_BTN_DEF_IGNORE, BTN_ACT_OPTIONS}, "btnDoublePageForward", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_PAGE_FORWARD),
|
||||
SettingInfo::Enum(StrId::STR_BTN_LONG_PRESS, &CrossPointSettings::btnLongPageForward,
|
||||
{StrId::STR_BTN_DEF_CHAPTER_FORWARD, BTN_ACT_OPTIONS}, "btnLongPageForward",
|
||||
StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_PAGE_FORWARD),
|
||||
// Power button: short=ignore, double=ignore, long=sleep (via hold timer, not event system)
|
||||
SettingInfo::Enum(StrId::STR_BTN_SHORT_PRESS, &CrossPointSettings::btnShortPower,
|
||||
{StrId::STR_BTN_DEF_IGNORE, BTN_ACT_OPTIONS}, "btnShortPower", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_POWER),
|
||||
SettingInfo::Enum(StrId::STR_BTN_DOUBLE_PRESS, &CrossPointSettings::btnDoublePower,
|
||||
{StrId::STR_BTN_DEF_IGNORE, BTN_ACT_OPTIONS}, "btnDoublePower", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_POWER),
|
||||
SettingInfo::Enum(StrId::STR_BTN_LONG_PRESS, &CrossPointSettings::btnLongPower, {StrId::STR_BTN_DEF_SLEEP},
|
||||
"btnLongPower", StrId::STR_CAT_CONTROLS)
|
||||
.withSubmenu(StrId::STR_BTN_POWER),
|
||||
|
||||
#undef BTN_ACT_OPTIONS
|
||||
|
||||
// --- System ---
|
||||
SettingInfo::Toggle(StrId::STR_SHOW_HIDDEN_FILES, &CrossPointSettings::showHiddenFiles, "showHiddenFiles",
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "ActivityManager.h" // for using the ActivityManager singleton
|
||||
#include "ActivityResult.h"
|
||||
#include "ButtonEventManager.h"
|
||||
#include "GfxRenderer.h"
|
||||
#include "MappedInputManager.h"
|
||||
#include "RenderLock.h"
|
||||
@@ -19,13 +20,14 @@ class Activity {
|
||||
std::string name;
|
||||
GfxRenderer& renderer;
|
||||
MappedInputManager& mappedInput;
|
||||
ButtonEventManager& buttonEvents;
|
||||
|
||||
ActivityResultHandler resultHandler;
|
||||
ActivityResult result;
|
||||
|
||||
public:
|
||||
explicit Activity(std::string name, GfxRenderer& renderer, MappedInputManager& mappedInput)
|
||||
: name(std::move(name)), renderer(renderer), mappedInput(mappedInput) {}
|
||||
: name(std::move(name)), renderer(renderer), mappedInput(mappedInput), buttonEvents(globalButtonEvents()) {}
|
||||
virtual ~Activity() = default;
|
||||
const std::string& getName() const { return name; }
|
||||
virtual void onEnter();
|
||||
@@ -45,6 +47,11 @@ class Activity {
|
||||
virtual bool preventAutoSleep() { return false; }
|
||||
virtual bool isReaderActivity() const { return false; }
|
||||
|
||||
// Called by ActivityManager when a globally-configured button action targets the
|
||||
// current activity. Override in reader activities to handle reader-specific actions.
|
||||
// Non-reader activities can ignore this (default is no-op).
|
||||
virtual void onButtonAction(CrossPointSettings::BUTTON_ACTION) {}
|
||||
|
||||
// Start a new activity without destroying the current one
|
||||
// Note: requestUpdate() will be invoked automatically once resultHandler finishes
|
||||
void startActivityForResult(std::unique_ptr<Activity>&& activity, ActivityResultHandler resultHandler);
|
||||
|
||||
@@ -154,6 +154,7 @@ void ActivityManager::loop() {
|
||||
// Arm input drain so the button that triggered the pop doesn't bleed into the
|
||||
// restored activity (or into a new activity the handler just pushed).
|
||||
drainInput = true;
|
||||
buttonEvents.drain();
|
||||
|
||||
// Request an update to ensure the popped activity gets re-rendered
|
||||
if (pendingAction == PendingAction::None) {
|
||||
@@ -204,6 +205,7 @@ void ActivityManager::loop() {
|
||||
// Arm input drain so the button that triggered the transition doesn't bleed
|
||||
// into the new activity.
|
||||
drainInput = true;
|
||||
buttonEvents.drain();
|
||||
|
||||
// onEnter may request another pending action, we will handle it in the next loop iteration
|
||||
continue;
|
||||
@@ -387,6 +389,12 @@ bool ActivityManager::isReaderActivity() const { return currentActivity && curre
|
||||
|
||||
bool ActivityManager::skipLoopDelay() const { return currentActivity && currentActivity->skipLoopDelay(); }
|
||||
|
||||
void ActivityManager::dispatchButtonAction(const CrossPointSettings::BUTTON_ACTION action) {
|
||||
if (currentActivity && currentActivity->isReaderActivity()) {
|
||||
currentActivity->onButtonAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
void ActivityManager::requestUpdate(bool immediate) {
|
||||
if (immediate) {
|
||||
if (renderTaskHandle) {
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ButtonEventManager.h"
|
||||
#include "CrossPointSettings.h"
|
||||
#include "GfxRenderer.h"
|
||||
#include "MappedInputManager.h"
|
||||
|
||||
@@ -52,6 +54,7 @@ class ActivityManager {
|
||||
protected:
|
||||
GfxRenderer& renderer;
|
||||
MappedInputManager& mappedInput;
|
||||
ButtonEventManager& buttonEvents;
|
||||
std::vector<std::unique_ptr<Activity>> stackActivities;
|
||||
std::unique_ptr<Activity> currentActivity;
|
||||
|
||||
@@ -96,7 +99,10 @@ class ActivityManager {
|
||||
|
||||
public:
|
||||
explicit ActivityManager(GfxRenderer& renderer, MappedInputManager& mappedInput)
|
||||
: renderer(renderer), mappedInput(mappedInput), renderingMutex(xSemaphoreCreateMutex()) {
|
||||
: renderer(renderer),
|
||||
mappedInput(mappedInput),
|
||||
buttonEvents(globalButtonEvents()),
|
||||
renderingMutex(xSemaphoreCreateMutex()) {
|
||||
assert(renderingMutex != nullptr && "Failed to create rendering mutex");
|
||||
stackActivities.reserve(10);
|
||||
}
|
||||
@@ -160,6 +166,11 @@ class ActivityManager {
|
||||
bool isReaderActivity() const;
|
||||
bool skipLoopDelay() const;
|
||||
|
||||
// Dispatch a globally-configured button action to the current activity.
|
||||
// Reader-specific actions (page navigation, TOC, bookmarks, footnotes) are forwarded
|
||||
// only when the current activity is a reader; others are no-ops in other contexts.
|
||||
void dispatchButtonAction(CrossPointSettings::BUTTON_ACTION action);
|
||||
|
||||
// If immediate is true, the update will be triggered immediately.
|
||||
// Otherwise, it will be deferred until the end of the current loop iteration.
|
||||
void requestUpdate(bool immediate = false);
|
||||
|
||||
@@ -295,37 +295,6 @@ void EpubReaderActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool screenshotChordReleased = gpio.wasReleased(HalGPIO::BTN_POWER) && gpio.wasReleased(HalGPIO::BTN_DOWN);
|
||||
|
||||
// Handle short power button press for footnotes
|
||||
if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::FOOTNOTES &&
|
||||
mappedInput.wasReleased(MappedInputManager::Button::Power) && !screenshotChordReleased) {
|
||||
if (currentPageFootnotes.size() == 1) {
|
||||
navigateToHref(currentPageFootnotes[0].href, true);
|
||||
} else if (currentPageFootnotes.size() > 1) {
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
startActivityForResult(std::make_unique<EpubReaderFootnotesActivity>(renderer, mappedInput, currentPageFootnotes),
|
||||
[this](const ActivityResult& result) {
|
||||
if (!result.isCancelled) {
|
||||
const auto& footnoteResult = std::get<FootnoteResult>(result.data);
|
||||
navigateToHref(footnoteResult.href, true);
|
||||
}
|
||||
requestUpdate();
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Star page toggle via short power button press
|
||||
if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::STAR_PAGE &&
|
||||
mappedInput.wasReleased(MappedInputManager::Button::Power)) {
|
||||
if (section && section->currentPage >= 0 && section->currentPage < section->pageCount) {
|
||||
bookmarkStore.toggle(static_cast<uint16_t>(currentSpineIndex), static_cast<uint16_t>(section->currentPage));
|
||||
requestUpdate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
auto [prevTriggered, nextTriggered] = ReaderUtils::detectPageTurn(mappedInput);
|
||||
if (!prevTriggered && !nextTriggered) {
|
||||
return;
|
||||
@@ -343,7 +312,7 @@ void EpubReaderActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool skipChapter = SETTINGS.longPressChapterSkip && mappedInput.getHeldTime() > skipChapterMs;
|
||||
const bool skipChapter = mappedInput.getHeldTime() > skipChapterMs;
|
||||
|
||||
// Chapter skip navigates by TOC entries, not spine boundaries.
|
||||
// Spine items without their own TOC entry inherit the previous spine's tocIndex
|
||||
@@ -1795,3 +1764,160 @@ bool EpubReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gf
|
||||
// No displayBuffer call — caller (SleepActivity) handles that after compositing the overlay
|
||||
return true;
|
||||
}
|
||||
|
||||
void EpubReaderActivity::onButtonAction(const CrossPointSettings::BUTTON_ACTION action) {
|
||||
using BA = CrossPointSettings::BUTTON_ACTION;
|
||||
switch (action) {
|
||||
case BA::BTN_PAGE_FORWARD:
|
||||
pageTurn(true);
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK:
|
||||
pageTurn(false);
|
||||
break;
|
||||
case BA::BTN_PAGE_FORWARD_10:
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!stepPageState(true)) break;
|
||||
}
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK_10:
|
||||
for (int i = 0; i < 10; i++) {
|
||||
if (!stepPageState(false)) break;
|
||||
}
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_STAR_PAGE:
|
||||
if (section) {
|
||||
bookmarkStore.toggle(static_cast<uint16_t>(currentSpineIndex), static_cast<uint16_t>(section->currentPage));
|
||||
requestUpdate();
|
||||
}
|
||||
break;
|
||||
case BA::BTN_FOOTNOTES:
|
||||
if (!currentPageFootnotes.empty()) {
|
||||
if (currentPageFootnotes.size() == 1) {
|
||||
navigateToHref(currentPageFootnotes[0].href, true);
|
||||
} else {
|
||||
startActivityForResult(
|
||||
std::make_unique<EpubReaderFootnotesActivity>(renderer, mappedInput, currentPageFootnotes),
|
||||
[this](const ActivityResult& result) {
|
||||
if (!result.isCancelled) {
|
||||
const auto& footnoteResult = std::get<FootnoteResult>(result.data);
|
||||
navigateToHref(footnoteResult.href, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BA::BTN_OPEN_TOC:
|
||||
if (epub) {
|
||||
const int spineIdx = currentSpineIndex;
|
||||
const int tocIdx = section ? section->getTocIndexForPage(section->currentPage)
|
||||
: epub->getTocIndexForSpineIndex(currentSpineIndex);
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
startActivityForResult(std::make_unique<EpubReaderChapterSelectionActivity>(renderer, mappedInput, epub,
|
||||
epub->getPath(), spineIdx, tocIdx),
|
||||
[this](const ActivityResult& result) {
|
||||
if (result.isCancelled) return;
|
||||
RenderLock lock(*this);
|
||||
const auto& chapter = std::get<ChapterResult>(result.data);
|
||||
auto resolvedPage =
|
||||
(chapter.tocIndex && chapter.spineIndex == currentSpineIndex && section)
|
||||
? section->getPageForTocIndex(*chapter.tocIndex)
|
||||
: std::nullopt;
|
||||
if (resolvedPage) {
|
||||
section->currentPage = *resolvedPage;
|
||||
} else {
|
||||
pendingTocIndex = chapter.tocIndex;
|
||||
currentSpineIndex = chapter.spineIndex;
|
||||
nextPageNumber = 0;
|
||||
section.reset();
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case BA::BTN_NEXT_SECTION:
|
||||
case BA::BTN_PREV_SECTION: {
|
||||
const bool forward = (action == BA::BTN_NEXT_SECTION);
|
||||
{
|
||||
RenderLock lock(*this);
|
||||
if (section && section->pageCount > 0) {
|
||||
const int curTocIndex = section->getTocIndexForPage(section->currentPage);
|
||||
const int nextTocIndex = forward ? curTocIndex + 1 : curTocIndex - 1;
|
||||
if (curTocIndex < 0) {
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = forward ? currentSpineIndex + 1 : currentSpineIndex - 1;
|
||||
section.reset();
|
||||
} else if (nextTocIndex >= 0 && nextTocIndex < epub->getTocItemsCount()) {
|
||||
const int newSpineIndex = epub->getSpineIndexForTocIndex(nextTocIndex);
|
||||
if (newSpineIndex == currentSpineIndex) {
|
||||
if (const auto resolvedPage = section->getPageForTocIndex(nextTocIndex)) {
|
||||
section->currentPage = *resolvedPage;
|
||||
}
|
||||
} else {
|
||||
pendingTocIndex = nextTocIndex;
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = newSpineIndex;
|
||||
section.reset();
|
||||
}
|
||||
} else if (forward) {
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = epub->getSpineItemsCount();
|
||||
section.reset();
|
||||
} else {
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = epub->getTocItem(curTocIndex).spineIndex - 1;
|
||||
section.reset();
|
||||
}
|
||||
} else {
|
||||
nextPageNumber = 0;
|
||||
currentSpineIndex = forward ? currentSpineIndex + 1 : currentSpineIndex - 1;
|
||||
section.reset();
|
||||
}
|
||||
}
|
||||
requestUpdate();
|
||||
break;
|
||||
}
|
||||
case BA::BTN_EXIT_READER:
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
finish();
|
||||
break;
|
||||
case BA::BTN_READER_MENU:
|
||||
if (epub) {
|
||||
const int currentPage = section ? section->currentPage + 1 : 0;
|
||||
const int totalPages = section ? section->pageCount : 0;
|
||||
float bookProgress = 0.0f;
|
||||
if (epub->getBookSize() > 0 && section && section->pageCount > 0) {
|
||||
const float chapterProgress =
|
||||
static_cast<float>(section->currentPage) / static_cast<float>(section->pageCount);
|
||||
bookProgress = epub->calculateProgress(currentSpineIndex, chapterProgress) * 100.0f;
|
||||
}
|
||||
const int bookProgressPercent = clampPercent(static_cast<int>(bookProgress + 0.5f));
|
||||
const bool isCurrentPageStarred = section && bookmarkStore.has(static_cast<uint16_t>(currentSpineIndex),
|
||||
static_cast<uint16_t>(section->currentPage));
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
startActivityForResult(
|
||||
std::make_unique<EpubReaderMenuActivity>(
|
||||
renderer, mappedInput, epub->getTitle(), currentPage, totalPages, bookProgressPercent,
|
||||
SETTINGS.orientation, !currentPageFootnotes.empty(), bookEmbeddedStyleOverride,
|
||||
bookImageRenderingOverride, bookFontFamilyOverride, bookFontSizeOverride, SETTINGS.textDarkness,
|
||||
!bookmarkStore.isEmpty(), isCurrentPageStarred),
|
||||
[this](const ActivityResult& result) {
|
||||
const auto& menu = std::get<MenuResult>(result.data);
|
||||
applyOrientation(menu.orientation);
|
||||
applyTextDarkness(menu.textDarkness);
|
||||
toggleAutoPageTurn(menu.pageTurnOption);
|
||||
applyBookReaderOverrides(menu.embeddedStyleOverride, menu.imageRenderingOverride, menu.fontFamilyOverride,
|
||||
menu.fontSizeOverride);
|
||||
if (!result.isCancelled) {
|
||||
onReaderMenuConfirm(static_cast<EpubReaderMenuActivity::MenuAction>(menu.action));
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case BA::BTN_KOREADER_SYNC:
|
||||
launchKOReaderSync(SyncLaunchMode::COMPARE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,6 +188,7 @@ class EpubReaderActivity final : public Activity {
|
||||
void loop() override;
|
||||
void render(RenderLock&& lock) override;
|
||||
bool isReaderActivity() const override { return true; }
|
||||
void onButtonAction(CrossPointSettings::BUTTON_ACTION action) override;
|
||||
|
||||
// Renders the last saved page to the frame buffer without flushing to display.
|
||||
// Used by SleepActivity to prepare the background for the overlay sleep mode.
|
||||
|
||||
@@ -253,7 +253,7 @@ void MdReaderActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool headingSkip = SETTINGS.longPressChapterSkip && mappedInput.getHeldTime() > HEADING_SKIP_MS;
|
||||
const bool headingSkip = mappedInput.getHeldTime() > HEADING_SKIP_MS;
|
||||
if (headingSkip && !headings.empty()) {
|
||||
jumpToHeading(nextTriggered);
|
||||
return;
|
||||
@@ -892,4 +892,70 @@ void MdReaderActivity::savePageIndexCache() const {
|
||||
}
|
||||
|
||||
LOG_DBG("MDR", "Saved page index cache: %d pages", totalPages);
|
||||
}
|
||||
}
|
||||
|
||||
void MdReaderActivity::onButtonAction(const CrossPointSettings::BUTTON_ACTION action) {
|
||||
using BA = CrossPointSettings::BUTTON_ACTION;
|
||||
auto clampPage = [this]() {
|
||||
if (totalPages == 0) {
|
||||
currentPage = 0;
|
||||
return;
|
||||
}
|
||||
if (currentPage < 0) currentPage = 0;
|
||||
if (currentPage >= totalPages) currentPage = totalPages - 1;
|
||||
};
|
||||
switch (action) {
|
||||
case BA::BTN_PAGE_FORWARD:
|
||||
if (currentPage < totalPages - 1) {
|
||||
currentPage++;
|
||||
currentHeadingIndex = pageOffsets.empty() ? -1 : getHeadingIndexForOffset(pageOffsets[currentPage]);
|
||||
requestUpdate();
|
||||
}
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK:
|
||||
if (currentPage > 0) {
|
||||
currentPage--;
|
||||
currentHeadingIndex = pageOffsets.empty() ? -1 : getHeadingIndexForOffset(pageOffsets[currentPage]);
|
||||
requestUpdate();
|
||||
}
|
||||
break;
|
||||
case BA::BTN_PAGE_FORWARD_10:
|
||||
currentPage += 10;
|
||||
clampPage();
|
||||
currentHeadingIndex = pageOffsets.empty() ? -1 : getHeadingIndexForOffset(pageOffsets[currentPage]);
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK_10:
|
||||
currentPage -= 10;
|
||||
clampPage();
|
||||
currentHeadingIndex = pageOffsets.empty() ? -1 : getHeadingIndexForOffset(pageOffsets[currentPage]);
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_NEXT_SECTION:
|
||||
jumpToHeading(true);
|
||||
break;
|
||||
case BA::BTN_PREV_SECTION:
|
||||
jumpToHeading(false);
|
||||
break;
|
||||
case BA::BTN_OPEN_TOC:
|
||||
if (!headings.empty()) {
|
||||
currentHeadingIndex = pageOffsets.empty() ? -1 : getHeadingIndexForOffset(pageOffsets[currentPage]);
|
||||
startActivityForResult(
|
||||
std::make_unique<MdReaderTocSelectionActivity>(renderer, mappedInput, headings, currentHeadingIndex),
|
||||
[this](const ActivityResult& result) {
|
||||
if (!result.isCancelled) {
|
||||
currentPage = std::get<PageResult>(result.data).page;
|
||||
currentHeadingIndex = pageOffsets.empty() ? -1 : getHeadingIndexForOffset(pageOffsets[currentPage]);
|
||||
requestUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case BA::BTN_EXIT_READER:
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
finish();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,4 +89,5 @@ class MdReaderActivity final : public Activity {
|
||||
void loop() override;
|
||||
void render(RenderLock&&) override;
|
||||
bool isReaderActivity() const override { return true; }
|
||||
void onButtonAction(CrossPointSettings::BUTTON_ACTION action) override;
|
||||
};
|
||||
@@ -31,8 +31,8 @@ inline void applyOrientation(GfxRenderer& renderer, const uint8_t orientation) {
|
||||
|
||||
// Suppresses input processing on activity entry until the user has released all buttons and a
|
||||
// clean frame (no pending press/release events) has been observed. Without this, the power-button
|
||||
// hold used to wake the device leaks into detectPageTurn() and triggers a page turn or, with
|
||||
// longPressChapterSkip enabled, a chapter skip (the wake-hold easily exceeds skipChapterMs).
|
||||
// hold used to wake the device leaks into detectPageTurn() and triggers a page turn or chapter
|
||||
// skip (the wake-hold easily exceeds skipChapterMs).
|
||||
// Each reader holds an instance, calls arm() in onEnter(), and calls shouldDrain() at the top
|
||||
// of loop() — returning early when it returns true.
|
||||
struct InputDrainGuard {
|
||||
@@ -62,17 +62,16 @@ struct PageTurnResult {
|
||||
};
|
||||
|
||||
inline PageTurnResult detectPageTurn(const MappedInputManager& input) {
|
||||
const bool usePress = !SETTINGS.longPressChapterSkip;
|
||||
const bool prev = usePress ? (input.wasPressed(MappedInputManager::Button::PageBack) ||
|
||||
input.wasPressed(MappedInputManager::Button::Left))
|
||||
: (input.wasReleased(MappedInputManager::Button::PageBack) ||
|
||||
input.wasReleased(MappedInputManager::Button::Left));
|
||||
const bool powerTurn = SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN &&
|
||||
input.wasReleased(MappedInputManager::Button::Power);
|
||||
const bool next = usePress ? (input.wasPressed(MappedInputManager::Button::PageForward) || powerTurn ||
|
||||
input.wasPressed(MappedInputManager::Button::Right))
|
||||
: (input.wasReleased(MappedInputManager::Button::PageForward) || powerTurn ||
|
||||
input.wasReleased(MappedInputManager::Button::Right));
|
||||
// Only treat wasReleased as a page turn when the button's short-press action is default.
|
||||
// Non-default short-press actions are dispatched by the global dispatcher in main.cpp;
|
||||
// counting wasReleased as well would double-fire the action.
|
||||
using BA = CrossPointSettings::BUTTON_ACTION;
|
||||
const bool prev =
|
||||
(SETTINGS.btnShortPageBack == BA::BTN_DEFAULT && input.wasReleased(MappedInputManager::Button::PageBack)) ||
|
||||
(SETTINGS.btnShortLeft == BA::BTN_DEFAULT && input.wasReleased(MappedInputManager::Button::Left));
|
||||
const bool next =
|
||||
(SETTINGS.btnShortPageForward == BA::BTN_DEFAULT && input.wasReleased(MappedInputManager::Button::PageForward)) ||
|
||||
(SETTINGS.btnShortRight == BA::BTN_DEFAULT && input.wasReleased(MappedInputManager::Button::Right));
|
||||
return {prev, next};
|
||||
}
|
||||
|
||||
|
||||
@@ -155,16 +155,6 @@ void TxtReaderActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Star page toggle via short power button press
|
||||
if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::STAR_PAGE &&
|
||||
mappedInput.wasReleased(MappedInputManager::Button::Power)) {
|
||||
if (currentPage >= 0) {
|
||||
bookmarkStore.toggle(0, static_cast<uint16_t>(currentPage));
|
||||
}
|
||||
requestUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
// Open starred pages list via Confirm button
|
||||
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm) && !bookmarkStore.isEmpty()) {
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
@@ -782,3 +772,62 @@ bool TxtReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gfx
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TxtReaderActivity::onButtonAction(const CrossPointSettings::BUTTON_ACTION action) {
|
||||
using BA = CrossPointSettings::BUTTON_ACTION;
|
||||
auto clampPage = [this]() {
|
||||
if (currentPage < 0) currentPage = 0;
|
||||
if (currentPage >= totalPages) currentPage = totalPages - 1;
|
||||
};
|
||||
switch (action) {
|
||||
case BA::BTN_PAGE_FORWARD:
|
||||
if (currentPage < totalPages - 1) {
|
||||
currentPage++;
|
||||
requestUpdate();
|
||||
}
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK:
|
||||
if (currentPage > 0) {
|
||||
currentPage--;
|
||||
requestUpdate();
|
||||
}
|
||||
break;
|
||||
case BA::BTN_PAGE_FORWARD_10:
|
||||
currentPage += 10;
|
||||
clampPage();
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK_10:
|
||||
currentPage -= 10;
|
||||
clampPage();
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_STAR_PAGE:
|
||||
bookmarkStore.toggle(0, static_cast<uint16_t>(currentPage));
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_OPEN_BOOKMARKS:
|
||||
if (!bookmarkStore.isEmpty()) {
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
startActivityForResult(std::make_unique<StarredPagesActivity>(renderer, mappedInput, bookmarkStore),
|
||||
[this](const ActivityResult& result) {
|
||||
if (!result.isCancelled) {
|
||||
const auto& starred = std::get<StarredPageResult>(result.data);
|
||||
currentPage = starred.pageNumber;
|
||||
requestUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case BA::BTN_NEXT_SECTION:
|
||||
case BA::BTN_PREV_SECTION:
|
||||
// TXT files have no headings/chapters; treat as unsupported (no-op).
|
||||
break;
|
||||
case BA::BTN_EXIT_READER:
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
finish();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ class TxtReaderActivity final : public Activity {
|
||||
void loop() override;
|
||||
void render(RenderLock&&) override;
|
||||
bool isReaderActivity() const override { return true; }
|
||||
void onButtonAction(CrossPointSettings::BUTTON_ACTION action) override;
|
||||
|
||||
// Renders the last saved page to the frame buffer without flushing to display.
|
||||
// Used by SleepActivity to prepare the background for the overlay sleep mode.
|
||||
|
||||
@@ -92,19 +92,10 @@ void XtcReaderActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
// When long-press chapter skip is disabled, turn pages on press instead of release.
|
||||
const bool usePressForPageTurn = !SETTINGS.longPressChapterSkip;
|
||||
const bool prevTriggered = usePressForPageTurn ? (mappedInput.wasPressed(MappedInputManager::Button::PageBack) ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Left))
|
||||
: (mappedInput.wasReleased(MappedInputManager::Button::PageBack) ||
|
||||
mappedInput.wasReleased(MappedInputManager::Button::Left));
|
||||
const bool powerPageTurn = SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::PAGE_TURN &&
|
||||
mappedInput.wasReleased(MappedInputManager::Button::Power);
|
||||
const bool nextTriggered = usePressForPageTurn
|
||||
? (mappedInput.wasPressed(MappedInputManager::Button::PageForward) || powerPageTurn ||
|
||||
mappedInput.wasPressed(MappedInputManager::Button::Right))
|
||||
: (mappedInput.wasReleased(MappedInputManager::Button::PageForward) || powerPageTurn ||
|
||||
mappedInput.wasReleased(MappedInputManager::Button::Right));
|
||||
const bool prevTriggered = mappedInput.wasReleased(MappedInputManager::Button::PageBack) ||
|
||||
mappedInput.wasReleased(MappedInputManager::Button::Left);
|
||||
const bool nextTriggered = mappedInput.wasReleased(MappedInputManager::Button::PageForward) ||
|
||||
mappedInput.wasReleased(MappedInputManager::Button::Right);
|
||||
|
||||
if (!prevTriggered && !nextTriggered) {
|
||||
return;
|
||||
@@ -121,7 +112,7 @@ void XtcReaderActivity::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool skipPages = SETTINGS.longPressChapterSkip && mappedInput.getHeldTime() > skipPageMs;
|
||||
const bool skipPages = mappedInput.getHeldTime() > skipPageMs;
|
||||
const int skipAmount = skipPages ? 10 : 1;
|
||||
|
||||
if (prevTriggered) {
|
||||
@@ -442,3 +433,61 @@ bool XtcReaderActivity::drawCurrentPageToBuffer(const std::string& filePath, Gfx
|
||||
free(pageBuffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void XtcReaderActivity::onButtonAction(const CrossPointSettings::BUTTON_ACTION action) {
|
||||
using BA = CrossPointSettings::BUTTON_ACTION;
|
||||
if (!xtc) return;
|
||||
const uint32_t pageCount = xtc->getPageCount();
|
||||
switch (action) {
|
||||
case BA::BTN_PAGE_FORWARD:
|
||||
if (currentPage + 1 < pageCount) {
|
||||
currentPage++;
|
||||
requestUpdate();
|
||||
}
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK:
|
||||
if (currentPage > 0) {
|
||||
currentPage--;
|
||||
requestUpdate();
|
||||
}
|
||||
break;
|
||||
case BA::BTN_PAGE_FORWARD_10:
|
||||
currentPage = (currentPage + 10 < pageCount) ? currentPage + 10 : pageCount - 1;
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK_10:
|
||||
currentPage = (currentPage >= 10) ? currentPage - 10 : 0;
|
||||
requestUpdate();
|
||||
break;
|
||||
case BA::BTN_NEXT_SECTION:
|
||||
if (xtc->hasChapters()) {
|
||||
const auto& chapters = xtc->getChapters();
|
||||
for (const auto& ch : chapters) {
|
||||
if (ch.startPage > currentPage) {
|
||||
currentPage = ch.startPage;
|
||||
requestUpdate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BA::BTN_PREV_SECTION:
|
||||
if (xtc->hasChapters()) {
|
||||
const auto& chapters = xtc->getChapters();
|
||||
for (int i = static_cast<int>(chapters.size()) - 1; i >= 0; i--) {
|
||||
if (chapters[i].startPage < currentPage) {
|
||||
currentPage = chapters[i].startPage;
|
||||
requestUpdate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case BA::BTN_EXIT_READER:
|
||||
ReaderUtils::enforceExitFullRefresh(renderer);
|
||||
finish();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class XtcReaderActivity final : public Activity {
|
||||
void loop() override;
|
||||
void render(RenderLock&&) override;
|
||||
bool isReaderActivity() const override { return true; }
|
||||
void onButtonAction(CrossPointSettings::BUTTON_ACTION action) override;
|
||||
|
||||
// Renders the last saved page to the frame buffer without flushing to display.
|
||||
// Used by SleepActivity to prepare the background for the overlay sleep mode.
|
||||
|
||||
@@ -264,7 +264,9 @@ inline void SettingInfo::prepareSubmenus(std::vector<SettingInfo>& items,
|
||||
auto it = std::find_if(preparedSubmenus.begin(), preparedSubmenus.end(),
|
||||
[&item](const SubmenuData& d) { return d.id == item.submenu; });
|
||||
if (it == preparedSubmenus.end()) {
|
||||
preparedItems.push_back(SettingInfo::SubmenuEntry(item.submenu));
|
||||
auto placeholder = SettingInfo::SubmenuEntry(item.submenu);
|
||||
placeholder.subcategory = item.subcategory; // inherit so addTo inserts the separator
|
||||
preparedItems.push_back(std::move(placeholder));
|
||||
preparedSubmenus.push_back({item.submenu, {}});
|
||||
it = preparedSubmenus.end() - 1;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <HalClock.h>
|
||||
#include <HalDisplay.h>
|
||||
#include <HalGPIO.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
@@ -21,6 +23,7 @@ bool SettingsActivity::isListItemSelectable(int settingIdx) const {
|
||||
|
||||
void SettingsActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
needsHalfRefresh = true;
|
||||
|
||||
// Build per-category vectors from the shared settings list.
|
||||
// addTo tracks the last subcategory per vector and automatically inserts a separator
|
||||
@@ -78,6 +81,7 @@ void SettingsActivity::onEnter() {
|
||||
// Device-only ACTION items — subcategory drives separator insertion automatically.
|
||||
controlsSettings.insert(controlsSettings.begin(),
|
||||
SettingInfo::Action(StrId::STR_REMAP_FRONT_BUTTONS, SettingAction::RemapFrontButtons));
|
||||
controlsSettings.insert(controlsSettings.begin(), SettingInfo::Separator(StrId::STR_MENU_BTN_PHYSICAL));
|
||||
|
||||
addToMoved(readerSettings, lastReaderSub,
|
||||
SettingInfo::Action(StrId::STR_CUSTOMISE_STATUS_BAR, SettingAction::CustomiseStatusBar));
|
||||
@@ -215,11 +219,15 @@ void SettingsActivity::toggleCurrentSetting() {
|
||||
if (setting.type == SettingType::ACTION) {
|
||||
auto resultHandler = [this](const ActivityResult& result) {
|
||||
SETTINGS.saveToFile();
|
||||
needsHalfRefresh = true;
|
||||
const auto* menuResult = std::get_if<MenuResult>(&result.data);
|
||||
if (menuResult && menuResult->action != -1) {
|
||||
auto activity = createActivityForAction(static_cast<SettingAction>(menuResult->action), renderer, mappedInput);
|
||||
if (activity) {
|
||||
startActivityForResult(std::move(activity), [this](const ActivityResult&) { SETTINGS.saveToFile(); });
|
||||
startActivityForResult(std::move(activity), [this](const ActivityResult&) {
|
||||
SETTINGS.saveToFile();
|
||||
needsHalfRefresh = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -277,6 +285,7 @@ void SettingsActivity::render(RenderLock&&) {
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), confirmLabel, tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
// Always use standard refresh for settings screen
|
||||
renderer.displayBuffer();
|
||||
const bool halfRefresh = gpio.deviceIsX3() && needsHalfRefresh;
|
||||
needsHalfRefresh = false;
|
||||
renderer.displayBuffer(halfRefresh ? HalDisplay::HALF_REFRESH : HalDisplay::FAST_REFRESH);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ class SettingsActivity final : public Activity {
|
||||
static const StrId categoryNames[categoryCount];
|
||||
|
||||
std::vector<SettingInfo::SubmenuData> submenuData;
|
||||
bool needsHalfRefresh = false;
|
||||
|
||||
void enterCategory(int categoryIndex);
|
||||
void toggleCurrentSetting();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "SettingsSubmenuActivity.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <HalDisplay.h>
|
||||
#include <HalGPIO.h>
|
||||
#include <I18n.h>
|
||||
|
||||
#include "CrossPointSettings.h"
|
||||
@@ -11,6 +13,7 @@
|
||||
|
||||
void SettingsSubmenuActivity::onEnter() {
|
||||
Activity::onEnter();
|
||||
needsHalfRefresh = true;
|
||||
initMenuList();
|
||||
requestUpdate();
|
||||
}
|
||||
@@ -63,5 +66,7 @@ void SettingsSubmenuActivity::render(RenderLock&&) {
|
||||
const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN));
|
||||
GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4);
|
||||
|
||||
renderer.displayBuffer();
|
||||
const bool halfRefresh = gpio.deviceIsX3() && needsHalfRefresh;
|
||||
needsHalfRefresh = false;
|
||||
renderer.displayBuffer(halfRefresh ? HalDisplay::HALF_REFRESH : HalDisplay::FAST_REFRESH);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
class SettingsSubmenuActivity final : public MenuListActivity {
|
||||
StrId titleId;
|
||||
std::function<std::string(const SettingInfo&)> itemValueStringOverride;
|
||||
bool needsHalfRefresh = false;
|
||||
|
||||
// MenuListActivity overrides
|
||||
void onEnter() override;
|
||||
|
||||
+151
-8
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "ButtonEventManager.h"
|
||||
#include "CrossPointSettings.h"
|
||||
#include "CrossPointState.h"
|
||||
#include "GlobalBookmarkIndex.h"
|
||||
@@ -33,6 +34,8 @@
|
||||
#include "util/ScreenshotUtil.h"
|
||||
|
||||
MappedInputManager mappedInputManager(gpio);
|
||||
ButtonEventManager buttonEventManager(mappedInputManager);
|
||||
ButtonEventManager& globalButtonEvents() { return buttonEventManager; }
|
||||
GfxRenderer renderer(display);
|
||||
ActivityManager activityManager(renderer, mappedInputManager);
|
||||
FontDecompressor fontDecompressor;
|
||||
@@ -284,6 +287,7 @@ void loop() {
|
||||
static unsigned long lastMemPrint = 0;
|
||||
|
||||
gpio.update();
|
||||
buttonEventManager.update();
|
||||
HalClock::updatePeriodic();
|
||||
|
||||
renderer.setFadingFix(SETTINGS.fadingFix);
|
||||
@@ -346,6 +350,8 @@ void loop() {
|
||||
// Track power button hold for sleep. We require a fresh press edge (wasPressed)
|
||||
// before starting to measure hold time, so that a hold carried over from boot
|
||||
// (wake-up press) is never misinterpreted as a "go to sleep" press.
|
||||
// The power button long-press is not user-remappable, so this path always owns it.
|
||||
// Sleep mapped to other buttons is handled by the dispatcher's BTN_SLEEP case below.
|
||||
static unsigned long powerHoldStart = 0;
|
||||
if (gpio.wasPressed(HalGPIO::BTN_POWER)) {
|
||||
powerHoldStart = millis();
|
||||
@@ -366,14 +372,6 @@ void loop() {
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh screen when power button is short-pressed with FORCE_REFRESH setting.
|
||||
if (SETTINGS.shortPwrBtn == CrossPointSettings::SHORT_PWRBTN::FORCE_REFRESH &&
|
||||
mappedInputManager.wasReleased(MappedInputManager::Button::Power)) {
|
||||
LOG_DBG("MAIN", "Manual screen refresh triggered");
|
||||
RenderLock lock;
|
||||
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
|
||||
}
|
||||
|
||||
if (!gpio.isPressed(HalGPIO::BTN_POWER)) {
|
||||
powerHoldStart = 0;
|
||||
}
|
||||
@@ -384,6 +382,151 @@ void loop() {
|
||||
activityManager.requestUpdate();
|
||||
}
|
||||
|
||||
// Dispatch globally-configured button actions before handing control to the activity.
|
||||
// Only non-Default actions are intercepted here; Default falls through to the activity.
|
||||
{
|
||||
using BA = CrossPointSettings::BUTTON_ACTION;
|
||||
using B = MappedInputManager::Button;
|
||||
ButtonEventManager::ButtonEvent ev;
|
||||
while (buttonEventManager.consumeEvent(ev)) {
|
||||
auto actionFor = [&](B btn) -> uint8_t {
|
||||
switch (btn) {
|
||||
case B::Back:
|
||||
switch (ev.type) {
|
||||
case ButtonEventManager::PressType::Short:
|
||||
return SETTINGS.btnShortBack;
|
||||
case ButtonEventManager::PressType::Double:
|
||||
return SETTINGS.btnDoubleBack;
|
||||
case ButtonEventManager::PressType::Long:
|
||||
return SETTINGS.btnLongBack;
|
||||
}
|
||||
break;
|
||||
case B::Confirm:
|
||||
switch (ev.type) {
|
||||
case ButtonEventManager::PressType::Short:
|
||||
return SETTINGS.btnShortConfirm;
|
||||
case ButtonEventManager::PressType::Double:
|
||||
return SETTINGS.btnDoubleConfirm;
|
||||
case ButtonEventManager::PressType::Long:
|
||||
return SETTINGS.btnLongConfirm;
|
||||
}
|
||||
break;
|
||||
case B::Left:
|
||||
switch (ev.type) {
|
||||
case ButtonEventManager::PressType::Short:
|
||||
return SETTINGS.btnShortLeft;
|
||||
case ButtonEventManager::PressType::Double:
|
||||
return SETTINGS.btnDoubleLeft;
|
||||
case ButtonEventManager::PressType::Long:
|
||||
return SETTINGS.btnLongLeft;
|
||||
}
|
||||
break;
|
||||
case B::Right:
|
||||
switch (ev.type) {
|
||||
case ButtonEventManager::PressType::Short:
|
||||
return SETTINGS.btnShortRight;
|
||||
case ButtonEventManager::PressType::Double:
|
||||
return SETTINGS.btnDoubleRight;
|
||||
case ButtonEventManager::PressType::Long:
|
||||
return SETTINGS.btnLongRight;
|
||||
}
|
||||
break;
|
||||
case B::PageBack:
|
||||
switch (ev.type) {
|
||||
case ButtonEventManager::PressType::Short:
|
||||
return SETTINGS.btnShortPageBack;
|
||||
case ButtonEventManager::PressType::Double:
|
||||
return SETTINGS.btnDoublePageBack;
|
||||
case ButtonEventManager::PressType::Long:
|
||||
return SETTINGS.btnLongPageBack;
|
||||
}
|
||||
break;
|
||||
case B::PageForward:
|
||||
switch (ev.type) {
|
||||
case ButtonEventManager::PressType::Short:
|
||||
return SETTINGS.btnShortPageForward;
|
||||
case ButtonEventManager::PressType::Double:
|
||||
return SETTINGS.btnDoublePageForward;
|
||||
case ButtonEventManager::PressType::Long:
|
||||
return SETTINGS.btnLongPageForward;
|
||||
}
|
||||
break;
|
||||
case B::Power:
|
||||
switch (ev.type) {
|
||||
case ButtonEventManager::PressType::Short:
|
||||
return SETTINGS.btnShortPower;
|
||||
case ButtonEventManager::PressType::Double:
|
||||
return SETTINGS.btnDoublePower;
|
||||
case ButtonEventManager::PressType::Long:
|
||||
return SETTINGS.btnLongPower;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break; // Up/Down have no FSMs — ButtonEventManager never emits these
|
||||
}
|
||||
return BA::BTN_DEFAULT;
|
||||
};
|
||||
|
||||
const uint8_t action = actionFor(ev.button);
|
||||
if (action == BA::BTN_DEFAULT) continue;
|
||||
|
||||
switch (static_cast<BA>(action)) {
|
||||
case BA::BTN_PAGE_FORWARD:
|
||||
activityManager.dispatchButtonAction(BA::BTN_PAGE_FORWARD);
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK:
|
||||
activityManager.dispatchButtonAction(BA::BTN_PAGE_BACK);
|
||||
break;
|
||||
case BA::BTN_PAGE_FORWARD_10:
|
||||
activityManager.dispatchButtonAction(BA::BTN_PAGE_FORWARD_10);
|
||||
break;
|
||||
case BA::BTN_PAGE_BACK_10:
|
||||
activityManager.dispatchButtonAction(BA::BTN_PAGE_BACK_10);
|
||||
break;
|
||||
case BA::BTN_GO_HOME:
|
||||
activityManager.goHome();
|
||||
break;
|
||||
case BA::BTN_SLEEP:
|
||||
activityManager.goToSleep();
|
||||
break;
|
||||
case BA::BTN_FORCE_REFRESH: {
|
||||
RenderLock lock;
|
||||
renderer.displayBuffer(HalDisplay::HALF_REFRESH);
|
||||
break;
|
||||
}
|
||||
case BA::BTN_OPEN_TOC:
|
||||
activityManager.dispatchButtonAction(BA::BTN_OPEN_TOC);
|
||||
break;
|
||||
case BA::BTN_OPEN_BOOKMARKS:
|
||||
activityManager.goToGlobalBookmarks();
|
||||
break;
|
||||
case BA::BTN_STAR_PAGE:
|
||||
activityManager.dispatchButtonAction(BA::BTN_STAR_PAGE);
|
||||
break;
|
||||
case BA::BTN_FOOTNOTES:
|
||||
activityManager.dispatchButtonAction(BA::BTN_FOOTNOTES);
|
||||
break;
|
||||
case BA::BTN_NEXT_SECTION:
|
||||
activityManager.dispatchButtonAction(BA::BTN_NEXT_SECTION);
|
||||
break;
|
||||
case BA::BTN_PREV_SECTION:
|
||||
activityManager.dispatchButtonAction(BA::BTN_PREV_SECTION);
|
||||
break;
|
||||
case BA::BTN_EXIT_READER:
|
||||
activityManager.dispatchButtonAction(BA::BTN_EXIT_READER);
|
||||
break;
|
||||
case BA::BTN_READER_MENU:
|
||||
activityManager.dispatchButtonAction(BA::BTN_READER_MENU);
|
||||
break;
|
||||
case BA::BTN_KOREADER_SYNC:
|
||||
activityManager.dispatchButtonAction(BA::BTN_KOREADER_SYNC);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned long activityStartTime = millis();
|
||||
activityManager.loop();
|
||||
const unsigned long activityDuration = millis() - activityStartTime;
|
||||
|
||||
Reference in New Issue
Block a user