diff --git a/src/Zemu.ts b/src/Zemu.ts index 8fde400..ac6460f 100644 --- a/src/Zemu.ts +++ b/src/Zemu.ts @@ -1,5 +1,5 @@ /** ****************************************************************************** - * (c) 2018 - 2023 Zondax AG + * (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ import { WINDOW_STAX, WINDOW_S, WINDOW_X, + WINDOW_FLEX, DEFAULT_STAX_APPROVE_KEYWORD, DEFAULT_STAX_REJECT_KEYWORD, DEFAULT_NANO_APPROVE_KEYWORD, @@ -51,7 +52,7 @@ import EmuContainer from "./emulator"; import GRPCRouter from "./grpc"; import { ClickNavigation, scheduleToNavElement, TouchNavigation } from "./actions"; -import { dummyButton, swipeContinueButton, TouchElements } from "./buttons"; +import { getTouchElement } from "./buttons"; import { ActionKind, ButtonKind, @@ -65,7 +66,7 @@ import { type ISwipeCoordinates, type TModel, } from "./types"; -import { zondaxToggleExpertMode, zondaxStaxEnableSpecialMode } from "./zondax"; +import { isTouchDevice, zondaxToggleExpertMode, zondaxTouchEnableSpecialMode } from "./zondax"; export default class Zemu { public startOptions!: IStartOptions; @@ -148,6 +149,7 @@ export default class Zemu { nanox: 0xc0de0001, nanosp: 0xc0de0001, stax: 0xc0de0001, + flex: 0xc0de0001, }; const elfApp = fs.readFileSync(elfPath); const elfInfo = elfy.parse(elfApp); @@ -161,7 +163,7 @@ export default class Zemu { this.startOptions = options; const approveWord = options.approveKeyword; const rejectWord = options.rejectKeyword; - if (options.model === "stax") { + if (isTouchDevice(options.model)) { this.startOptions.approveKeyword = approveWord.length === 0 ? DEFAULT_STAX_APPROVE_KEYWORD : approveWord; this.startOptions.rejectKeyword = rejectWord.length === 0 ? DEFAULT_STAX_REJECT_KEYWORD : rejectWord; } else { @@ -199,8 +201,9 @@ export default class Zemu { this.log(`Wait for start text`); if (this.startOptions.startText.length === 0) { - this.startOptions.startText = - this.startOptions.model === "stax" ? DEFAULT_STAX_START_TEXT : DEFAULT_NANO_START_TEXT; + this.startOptions.startText = isTouchDevice(this.startOptions.model) + ? DEFAULT_STAX_START_TEXT + : DEFAULT_NANO_START_TEXT; } const start = new Date(); let found = false; @@ -219,10 +222,9 @@ export default class Zemu { } const events = await this.getEvents(); if (!reviewPendingFound && events.some((event: IEvent) => reviewPendingRegex.test(event.text))) { - const nav = - this.startOptions.model === "stax" - ? new TouchNavigation([ButtonKind.ConfirmYesButton]) - : new ClickNavigation([0]); + const nav = isTouchDevice(this.startOptions.model) + ? new TouchNavigation(this.startOptions.model, [ButtonKind.ConfirmYesButton]) + : new ClickNavigation([0]); await this.navigate("", "", nav.schedule, true, false); reviewPendingFound = true; } @@ -309,6 +311,8 @@ export default class Zemu { return WINDOW_X; case "stax": return WINDOW_STAX; + case "flex": + return WINDOW_FLEX; default: throw new Error(`model ${this.startOptions.model} not recognized`); } @@ -444,7 +448,7 @@ export default class Zemu { async enableSpecialMode( nanoModeText: string, nanoIsSecretMode: boolean = false, - staxToggleSettingButton?: ButtonKind, + touchToggleSettingButton?: ButtonKind, path = ".", testcaseName = "", waitForScreenUpdate = true, @@ -452,7 +456,7 @@ export default class Zemu { startImgIndex = 0, timeout = DEFAULT_METHOD_TIMEOUT, ): Promise { - if (this.startOptions.model !== "stax") { + if (!isTouchDevice(this.startOptions.model)) { const expertImgIndex = await this.toggleExpertMode(testcaseName, takeSnapshots, startImgIndex); let tmpImgIndex = await this.navigateUntilText( path, @@ -479,7 +483,7 @@ export default class Zemu { timeout, ); } else { - const nav = zondaxStaxEnableSpecialMode(staxToggleSettingButton); + const nav = zondaxTouchEnableSpecialMode(this.startOptions.model, touchToggleSettingButton); return await this.navigate(path, testcaseName, nav.schedule, waitForScreenUpdate, takeSnapshots, startImgIndex); } } @@ -590,7 +594,7 @@ export default class Zemu { startImgIndex, timeout, ); - if (this.startOptions.model === "stax") { + if (isTouchDevice(this.startOptions.model)) { // Avoid taking a snapshot of the final animation await this.waitUntilScreenIs(this.mainMenuSnapshot); await this.takeSnapshotAndOverwrite(path, testcaseName, lastSnapshotIdx); @@ -606,7 +610,7 @@ export default class Zemu { timeout = DEFAULT_METHOD_TIMEOUT, ): Promise { const rejectKeyword = this.startOptions.rejectKeyword; - if (this.startOptions.model !== "stax") { + if (!isTouchDevice(this.startOptions.model)) { return await this.navigateAndCompareUntilText( path, testcaseName, @@ -618,7 +622,7 @@ export default class Zemu { } else { const takeSnapshots = true; const runLastAction = false; - // For Stax devices navigate until reject keyword --> Reject --> Confirm rejection + // For Stax/Flex devices navigate until reject keyword --> Reject --> Confirm rejection // reject keyword should be actually approve keyword (issue with OCR) const navLastIndex = await this.navigateUntilText( path, @@ -630,7 +634,10 @@ export default class Zemu { timeout, runLastAction, ); - const rejectConfirmationNav = new TouchNavigation([ButtonKind.RejectButton, ButtonKind.ConfirmYesButton]); + const rejectConfirmationNav = new TouchNavigation(this.startOptions.model, [ + ButtonKind.RejectButton, + ButtonKind.ConfirmYesButton, + ]); // Overwrite last snapshot since navigate starts taking a snapshot of the current screen const lastIndex = await this.navigate( path, @@ -673,7 +680,7 @@ export default class Zemu { let start = new Date(); let found = false; - const isTouchDevice = this.startOptions.model === "stax"; + const touchDevice = isTouchDevice(this.startOptions.model); const textRegex = new RegExp(text, "i"); @@ -693,8 +700,8 @@ export default class Zemu { if (found) break; const nav: INavElement = { - type: isTouchDevice ? ActionKind.Touch : ActionKind.RightClick, - button: swipeContinueButton, // For clicks, this will be ignored + type: touchDevice ? ActionKind.Touch : ActionKind.RightClick, + button: getTouchElement(this.startOptions.model, ButtonKind.SwipeContinueButton), // For clicks, this will be ignored }; await this.runAction(nav, filename, waitForScreenUpdate, true); start = new Date(); @@ -703,11 +710,11 @@ export default class Zemu { if (!runLastAction) return imageIndex; // do not run last action if requested // Approve can be performed with Tap or PressAndHold - const staxApproveButton = TouchElements.get(this.startOptions.approveAction); + const approveButton = getTouchElement(this.startOptions.model, this.startOptions.approveAction); const nav: INavElement = { - type: isTouchDevice ? ActionKind.Touch : ActionKind.BothClick, - button: staxApproveButton ?? dummyButton, + type: touchDevice ? ActionKind.Touch : ActionKind.BothClick, + button: approveButton, }; await this.runAction(nav, filename, waitForScreenUpdate, true); return imageIndex; @@ -872,7 +879,8 @@ export default class Zemu { waitForScreenUpdate: boolean = true, waitForEventsChange: boolean = false, ): Promise { - if (this.startOptions.model !== "stax") throw new Error("fingerTouch method can only be used with stax device"); + if (!isTouchDevice(this.startOptions.model)) + throw new Error("fingerTouch method can only be used with touchable devices"); const prevEvents = await this.getEvents(); const prevScreen = await this.snapshot(); diff --git a/src/actions.ts b/src/actions.ts index f1df488..62ae9f1 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -1,5 +1,5 @@ /** ****************************************************************************** - * (c) 2018 - 2023 Zondax AG + * (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************* */ -import { dummyButton, TouchElements } from "./buttons"; -import { ActionKind, type ButtonKind, type INavElement } from "./types"; +import { getTouchElement } from "./buttons"; +import { ActionKind, ButtonKind, type TModel, type INavElement } from "./types"; export function scheduleToNavElement(clickSchedule: Array): INavElement[] { + const dummyButton = getTouchElement("nanos", ButtonKind.QuitAppButton); const nav: INavElement[] = []; for (const click of clickSchedule) { if (typeof click !== "number") { @@ -51,10 +52,10 @@ export class ClickNavigation { export class TouchNavigation { schedule: INavElement[]; - constructor(buttonKindArray: ButtonKind[]) { + constructor(model: TModel, buttonKindArray: ButtonKind[]) { this.schedule = []; for (const buttonKind of buttonKindArray) { - const touchButton = TouchElements.get(buttonKind); + const touchButton = getTouchElement(model, buttonKind); if (touchButton == null) throw new Error("Undefined touch action"); this.schedule.push({ type: ActionKind.Touch, diff --git a/src/buttons.ts b/src/buttons.ts index ce18f8d..58abe0d 100644 --- a/src/buttons.ts +++ b/src/buttons.ts @@ -1,5 +1,5 @@ /** ****************************************************************************** - * (c) 2018 - 2023 Zondax AG + * (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,164 +13,41 @@ * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************* */ -import { ButtonKind, type IButton, SwipeDirection } from "./types"; +import { type ButtonKind, type IButton, SwipeDirection, type TModel } from "./types"; +import { stax } from "./buttons_stax"; +import { flex } from "./buttons_flex"; -export const dummyButton: IButton = { +const dummyButton: IButton = { x: 0, y: 0, delay: 0, direction: SwipeDirection.NoSwipe, }; -const infoButton: IButton = { - x: 335, - y: 65, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const quitAppButton: IButton = { - x: 0, - y: 0, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -export const tapContinueButton: IButton = { - x: 200, - y: 250, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -export const swipeContinueButton: IButton = { - x: 200, - y: 250, - delay: 0.1, - direction: SwipeDirection.SwipeLeft, -}; - -const prevPageButton: IButton = { - x: 45, - y: 45, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const toggleOption1: IButton = { - x: 350, - y: 125, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const toggleOption2: IButton = { - x: 350, - y: 200, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const toggleOption3: IButton = { - x: 350, - y: 250, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const navRightButton: IButton = { - x: 300, - y: 625, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const navLeftButton: IButton = { - x: 140, - y: 625, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const quitSettingsButton: IButton = { - x: 40, - y: 40, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const approveTapButton: IButton = { - x: 200, - y: 550, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const approveHoldButton: IButton = { - x: 335, - y: 525, - delay: 5, - direction: SwipeDirection.NoSwipe, -}; - -const rejectButton: IButton = { - x: 200, - y: 650, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const confirmYesButton: IButton = { - x: 200, - y: 550, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const confirmNoButton: IButton = { - x: 200, - y: 650, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const showQRButton: IButton = { - x: 200, - y: 300, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -const closeQRButton: IButton = { - x: 200, - y: 650, - delay: 0.25, - direction: SwipeDirection.NoSwipe, -}; - -export const TouchElements = new Map([ - [ButtonKind.InfoButton, infoButton], - [ButtonKind.QuitAppButton, quitAppButton], - - [ButtonKind.TapContinueButton, tapContinueButton], - - [ButtonKind.PrevPageButton, prevPageButton], - - [ButtonKind.ToggleSettingButton1, toggleOption1], - [ButtonKind.ToggleSettingButton2, toggleOption2], - [ButtonKind.ToggleSettingButton3, toggleOption3], +export function getTouchElement(model: TModel, buttonKind: ButtonKind): IButton { + switch (model) { + case "stax": { + const button = stax.TouchElements.get(buttonKind); + if (button != null) { + return button; + } + break; + } - [ButtonKind.NavRightButton, navRightButton], - [ButtonKind.NavLeftButton, navLeftButton], - [ButtonKind.QuitSettingsButton, quitSettingsButton], + case "flex": { + const button = flex.TouchElements.get(buttonKind); + if (button != null) { + return button; + } + break; + } - [ButtonKind.ApproveHoldButton, approveHoldButton], - [ButtonKind.ApproveTapButton, approveTapButton], - [ButtonKind.RejectButton, rejectButton], + // Add cases for other models here when they become available - [ButtonKind.ConfirmYesButton, confirmYesButton], - [ButtonKind.ConfirmNoButton, confirmNoButton], + default: + return dummyButton; + } - [ButtonKind.ShowQRButton, showQRButton], - [ButtonKind.CloseQRButton, closeQRButton], -]); + console.log(`Unsupported ButtonKind: ${model}, ${buttonKind}`); + return dummyButton; +} diff --git a/src/buttons_flex.ts b/src/buttons_flex.ts new file mode 100644 index 0000000..61515bf --- /dev/null +++ b/src/buttons_flex.ts @@ -0,0 +1,175 @@ +/** ****************************************************************************** + * (c) 2018 - 2024 Zondax AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************* */ +import { ButtonKind, type IButton, SwipeDirection } from "./types"; + +/* eslint-disable @typescript-eslint/no-namespace */ +export namespace flex { + export const infoButton: IButton = { + x: 405, + y: 75, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const quitAppButton: IButton = { + x: 240, + y: 550, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const swipeContinueButton: IButton = { + x: 250, + y: 325, + delay: 0.1, + direction: SwipeDirection.SwipeLeft, + }; + + export const navRightButton: IButton = { + x: 435, + y: 555, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const navLeftButton: IButton = { + x: 235, + y: 555, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + // Placeholder if Ledger moves this button + export const settingsNavRightButton: IButton = navRightButton; + + export const settingsNavnavLeftButton: IButton = { + x: 315, + y: 555, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const settingsQuitButton: IButton = { + x: 40, + y: 45, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const rejectButton: IButton = { + x: 95, + y: 555, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const toggleOption1: IButton = { + x: 415, + y: 140, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const approveTapButton: IButton = { + x: 240, + y: 435, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const prevPageButton: IButton = { + x: 45, + y: 45, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const approveHoldButton: IButton = { + x: 400, + y: 435, + delay: 5, + direction: SwipeDirection.NoSwipe, + }; + + export const toggleOption2: IButton = { + x: 350, + y: 200, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const toggleOption3: IButton = { + x: 350, + y: 250, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const confirmYesButton: IButton = { + x: 235, + y: 460, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const confirmNoButton: IButton = { + x: 235, + y: 555, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const showQRButton: IButton = { + x: 250, + y: 245, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const closeQRButton: IButton = { + x: 200, + y: 650, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const TouchElements = new Map([ + [ButtonKind.InfoButton, flex.infoButton], + [ButtonKind.QuitAppButton, flex.quitAppButton], + + [ButtonKind.SwipeContinueButton, flex.swipeContinueButton], + [ButtonKind.PrevPageButton, flex.prevPageButton], + + [ButtonKind.SettingsNavRightButton, flex.settingsNavRightButton], + [ButtonKind.SettingsNavLeftButton, flex.settingsNavnavLeftButton], + [ButtonKind.SettingsQuitButton, flex.settingsQuitButton], + + [ButtonKind.ToggleSettingButton1, flex.toggleOption1], + [ButtonKind.ToggleSettingButton2, flex.toggleOption2], + [ButtonKind.ToggleSettingButton3, flex.toggleOption3], + + [ButtonKind.NavRightButton, flex.navRightButton], + [ButtonKind.NavLeftButton, flex.navLeftButton], + + [ButtonKind.ApproveHoldButton, flex.approveHoldButton], + [ButtonKind.ApproveTapButton, flex.approveTapButton], + [ButtonKind.RejectButton, flex.rejectButton], + [ButtonKind.ConfirmYesButton, flex.confirmYesButton], + [ButtonKind.ConfirmNoButton, flex.confirmNoButton], + [ButtonKind.ShowQRButton, flex.showQRButton], + [ButtonKind.CloseQRButton, flex.closeQRButton], + ]); +} diff --git a/src/buttons_stax.ts b/src/buttons_stax.ts new file mode 100644 index 0000000..c0a06a7 --- /dev/null +++ b/src/buttons_stax.ts @@ -0,0 +1,174 @@ +/** ****************************************************************************** + * (c) 2018 - 2024 Zondax AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************* */ +import { ButtonKind, type IButton, SwipeDirection } from "./types"; + +/* eslint-disable @typescript-eslint/no-namespace */ +export namespace stax { + export const infoButton: IButton = { + x: 335, + y: 65, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const quitAppButton: IButton = { + x: 200, + y: 625, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const swipeContinueButton: IButton = { + x: 200, + y: 350, + delay: 0.1, + direction: SwipeDirection.SwipeLeft, + }; + + export const navRightButton: IButton = { + x: 360, + y: 625, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const navLeftButton: IButton = { + x: 195, + y: 625, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + // Placeholder if Ledger moves this button + export const settingsNavRightButton: IButton = navRightButton; + + export const settingsNavnavLeftButton: IButton = { + x: 275, + y: 625, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const settingsQuitButton: IButton = { + x: 40, + y: 45, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const rejectButton: IButton = { + x: 75, + y: 625, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const toggleOption1: IButton = { + x: 350, + y: 135, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const approveTapButton: IButton = { + x: 205, + y: 520, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const prevPageButton: IButton = { + x: 45, + y: 45, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const approveHoldButton: IButton = { + x: 335, + y: 520, + delay: 5, + direction: SwipeDirection.NoSwipe, + }; + + export const toggleOption2: IButton = { + x: 350, + y: 200, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const toggleOption3: IButton = { + x: 350, + y: 250, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const confirmYesButton: IButton = { + x: 200, + y: 550, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const confirmNoButton: IButton = { + x: 200, + y: 630, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const showQRButton: IButton = { + x: 200, + y: 300, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const closeQRButton: IButton = { + x: 200, + y: 650, + delay: 0.25, + direction: SwipeDirection.NoSwipe, + }; + + export const TouchElements = new Map([ + [ButtonKind.InfoButton, stax.infoButton], + [ButtonKind.QuitAppButton, stax.quitAppButton], + + [ButtonKind.SwipeContinueButton, stax.swipeContinueButton], + [ButtonKind.PrevPageButton, stax.prevPageButton], + + [ButtonKind.SettingsNavRightButton, stax.settingsNavRightButton], + [ButtonKind.SettingsNavLeftButton, stax.settingsNavnavLeftButton], + [ButtonKind.SettingsQuitButton, stax.settingsQuitButton], + + [ButtonKind.ToggleSettingButton1, stax.toggleOption1], + [ButtonKind.ToggleSettingButton2, stax.toggleOption2], + [ButtonKind.ToggleSettingButton3, stax.toggleOption3], + + [ButtonKind.NavRightButton, stax.navRightButton], + [ButtonKind.NavLeftButton, stax.navLeftButton], + [ButtonKind.ApproveHoldButton, stax.approveHoldButton], + [ButtonKind.ApproveTapButton, stax.approveTapButton], + [ButtonKind.RejectButton, stax.rejectButton], + [ButtonKind.ConfirmYesButton, stax.confirmYesButton], + [ButtonKind.ConfirmNoButton, stax.confirmNoButton], + [ButtonKind.ShowQRButton, stax.showQRButton], + [ButtonKind.CloseQRButton, stax.closeQRButton], + ]); +} diff --git a/src/constants.ts b/src/constants.ts index de08812..37f07aa 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,5 +1,5 @@ /** ****************************************************************************** - * (c) 2018 - 2023 Zondax AG + * (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -77,3 +77,10 @@ export const WINDOW_STAX: IDeviceWindow = { width: 400, height: 672, }; + +export const WINDOW_FLEX: IDeviceWindow = { + x: 0, + y: 0, + width: 480, + height: 600, +}; diff --git a/src/emulator.ts b/src/emulator.ts index 7d57fd5..04443db 100644 --- a/src/emulator.ts +++ b/src/emulator.ts @@ -1,5 +1,5 @@ /** ****************************************************************************** - * (c) 2018 - 2023 Zondax AG + * (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/index.ts b/src/index.ts index b25aca4..bfef925 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ /** ****************************************************************************** - * (c) 2018 - 2023 Zondax AG + * (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/src/types.ts b/src/types.ts index 06af743..1fc93cb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,5 @@ /** ****************************************************************************** - * (c) 2018 - 2023 Zondax AG + * (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,7 @@ export interface ISwipeCoordinates { y: number; } -export type TModel = "nanos" | "nanosp" | "nanox" | "stax"; +export type TModel = "nanos" | "nanosp" | "nanox" | "stax" | "flex"; export interface IStartOptions { logging: boolean; @@ -90,17 +90,20 @@ export const enum ButtonKind { InfoButton = 0, QuitAppButton, - TapContinueButton, + SwipeContinueButton, PrevPageButton, + SettingsNavRightButton, + SettingsNavLeftButton, + SettingsQuitButton, + ToggleSettingButton1, ToggleSettingButton2, ToggleSettingButton3, NavRightButton, NavLeftButton, - QuitSettingsButton, ApproveHoldButton, ApproveTapButton, diff --git a/src/zondax.ts b/src/zondax.ts index 82a9262..1c8e13e 100644 --- a/src/zondax.ts +++ b/src/zondax.ts @@ -1,5 +1,5 @@ /** ****************************************************************************** - * (c) 2018 - 2023 Zondax AG + * (c) 2018 - 2024 Zondax AG * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,19 @@ import { ClickNavigation, TouchNavigation } from "./actions"; import { ButtonKind, type TModel } from "./types"; +export function isTouchDevice(model: TModel): boolean { + return model === "stax" || model === "flex"; +} + export function zondaxMainmenuNavigation(model: TModel, clickArray?: number[]): ClickNavigation | TouchNavigation { - if (model === "stax") { - return new TouchNavigation([ + if (isTouchDevice(model)) { + return new TouchNavigation(model, [ ButtonKind.InfoButton, - ButtonKind.NavRightButton, + ButtonKind.SettingsNavRightButton, + ButtonKind.SettingsNavRightButton, ButtonKind.ToggleSettingButton1, ButtonKind.ToggleSettingButton1, - ButtonKind.QuitSettingsButton, + ButtonKind.SettingsQuitButton, ]); } const DEFAULT_MAINMENU_CLICKS = [1, 0, 0, 4, -5]; @@ -31,27 +36,28 @@ export function zondaxMainmenuNavigation(model: TModel, clickArray?: number[]): } export function zondaxToggleExpertMode(model: TModel, clickArray?: number[]): ClickNavigation | TouchNavigation { - if (model === "stax") { - return new TouchNavigation([ + if (isTouchDevice(model)) { + return new TouchNavigation(model, [ ButtonKind.InfoButton, ButtonKind.NavRightButton, ButtonKind.ToggleSettingButton1, - ButtonKind.QuitSettingsButton, + ButtonKind.SettingsQuitButton, ]); } const DEFAULT_EXPERT_MODE_CLICKS = [1, 0, -1]; return new ClickNavigation(clickArray ?? DEFAULT_EXPERT_MODE_CLICKS); } -export function zondaxStaxEnableSpecialMode(toggleSettingButton?: ButtonKind): TouchNavigation { - return new TouchNavigation([ +export function zondaxTouchEnableSpecialMode(model: TModel, toggleSettingButton?: ButtonKind): TouchNavigation { + return new TouchNavigation(model, [ ButtonKind.InfoButton, - ButtonKind.NavRightButton, + ButtonKind.SettingsNavRightButton, + ButtonKind.SettingsNavRightButton, ButtonKind.ToggleSettingButton1, - ButtonKind.NavLeftButton, - ButtonKind.NavRightButton, + ButtonKind.SettingsNavLeftButton, + ButtonKind.SettingsNavRightButton, toggleSettingButton ?? ButtonKind.ToggleSettingButton2, - ButtonKind.TapContinueButton, + ButtonKind.SwipeContinueButton, ButtonKind.ConfirmYesButton, ]); }