pxt-microbit 4.1.38 → 4.1.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -728,6 +728,50 @@ declare namespace pxsim {
728
728
  }
729
729
  declare namespace pxsim.info {
730
730
  }
731
+ declare namespace pxsim.keymap {
732
+ enum Key {
733
+ None = 0,
734
+ Left = 1,
735
+ Up = 2,
736
+ Right = 3,
737
+ Down = 4,
738
+ A = 5,
739
+ B = 6,
740
+ Menu = 7,
741
+ Screenshot = -1,
742
+ Gif = -2,
743
+ Reset = -3,
744
+ TogglePause = -4
745
+ }
746
+ function _setPlayerKeys(player: number, // player number is 1-based
747
+ up: number, down: number, left: number, right: number, A: number, B: number): void;
748
+ function _setSystemKeys(screenshot: number, gif: number, menu: number, reset: number): void;
749
+ }
750
+ declare namespace pxsim {
751
+ import Key = pxsim.keymap.Key;
752
+ interface KeymapBoard extends EventBusBoard {
753
+ keymapState: KeymapState;
754
+ }
755
+ function getKeymapState(): KeymapState;
756
+ class KeymapState {
757
+ keymap: {
758
+ [keyCode: number]: Key;
759
+ };
760
+ altmap: {
761
+ [keyCode: number]: Key;
762
+ };
763
+ mappings: {
764
+ [name: string]: number[];
765
+ };
766
+ constructor();
767
+ setPlayerKeys(player: number, // player number is 1-based
768
+ up: number, down: number, left: number, right: number, A: number, B: number): void;
769
+ setSystemKeys(screenshot: number, gif: number, menu: number, reset: number): void;
770
+ getKey(keyCode: number): Key;
771
+ private saveMap;
772
+ private clearMap;
773
+ }
774
+ }
731
775
  declare namespace pxsim.multiplayer {
732
776
  function postImage(im: pxsim.RefImage, goal: string): void;
733
777
  function getCurrentImage(): pxsim.RefImage;
@@ -2395,6 +2395,145 @@ var pxsim;
2395
2395
  pxsim.ToggleState = ToggleState;
2396
2396
  })(pxsim || (pxsim = {}));
2397
2397
  var pxsim;
2398
+ (function (pxsim) {
2399
+ var keymap;
2400
+ (function (keymap) {
2401
+ // Keep in sync with pxt-arcade-sim/api.ts
2402
+ let Key;
2403
+ (function (Key) {
2404
+ Key[Key["None"] = 0] = "None";
2405
+ // Player 1
2406
+ Key[Key["Left"] = 1] = "Left";
2407
+ Key[Key["Up"] = 2] = "Up";
2408
+ Key[Key["Right"] = 3] = "Right";
2409
+ Key[Key["Down"] = 4] = "Down";
2410
+ Key[Key["A"] = 5] = "A";
2411
+ Key[Key["B"] = 6] = "B";
2412
+ Key[Key["Menu"] = 7] = "Menu";
2413
+ // Player 2 = Player 1 + 7
2414
+ // Player 3 = Player 2 + 7
2415
+ // Player 4 = Player 3 + 7
2416
+ // system keys
2417
+ Key[Key["Screenshot"] = -1] = "Screenshot";
2418
+ Key[Key["Gif"] = -2] = "Gif";
2419
+ Key[Key["Reset"] = -3] = "Reset";
2420
+ Key[Key["TogglePause"] = -4] = "TogglePause";
2421
+ })(Key = keymap.Key || (keymap.Key = {}));
2422
+ function _setPlayerKeys(player, // player number is 1-based
2423
+ up, down, left, right, A, B) {
2424
+ pxsim.getKeymapState().setPlayerKeys(player, up, down, left, right, A, B);
2425
+ }
2426
+ keymap._setPlayerKeys = _setPlayerKeys;
2427
+ function _setSystemKeys(screenshot, gif, menu, reset) {
2428
+ pxsim.getKeymapState().setSystemKeys(screenshot, gif, menu, reset);
2429
+ }
2430
+ keymap._setSystemKeys = _setSystemKeys;
2431
+ })(keymap = pxsim.keymap || (pxsim.keymap = {}));
2432
+ })(pxsim || (pxsim = {}));
2433
+ (function (pxsim) {
2434
+ var Key = pxsim.keymap.Key;
2435
+ function getKeymapState() {
2436
+ return pxsim.board().keymapState;
2437
+ }
2438
+ pxsim.getKeymapState = getKeymapState;
2439
+ const reservedKeyCodes = [
2440
+ 27,
2441
+ 9 // Tab
2442
+ ];
2443
+ class KeymapState {
2444
+ constructor() {
2445
+ this.keymap = {};
2446
+ this.altmap = {};
2447
+ this.mappings = {};
2448
+ // Player 1 keymap
2449
+ this.setPlayerKeys(1, // Player 1
2450
+ 87, // W - Up
2451
+ 83, // D - Down
2452
+ 65, // A - Left
2453
+ 83, // S - Right
2454
+ 32, // Space - A
2455
+ 13 // Enter - B
2456
+ );
2457
+ // Player 2 keymap
2458
+ this.setPlayerKeys(2, // Player 2
2459
+ 73, // I - Up
2460
+ 75, // K - Down
2461
+ 74, // J - Left
2462
+ 75, // K - Right
2463
+ 85, // U - A
2464
+ 79 // O - B
2465
+ );
2466
+ // Note: Player 3 and 4 have no default keyboard mapping
2467
+ // System keymap
2468
+ this.setSystemKeys(80, // P - Screenshot
2469
+ 82, // R - Gif
2470
+ 0, // Menu - not mapped
2471
+ 0 // Reset - not mapped
2472
+ );
2473
+ // Player 1 alternate mapping. This is cleared when the game sets any player keys explicitly
2474
+ this.altmap[38] = Key.Up; // UpArrow
2475
+ this.altmap[37] = Key.Left; // LeftArrow
2476
+ this.altmap[40] = Key.Down; // DownArrow
2477
+ this.altmap[39] = Key.Right; // RightArrow
2478
+ this.altmap[81] = Key.A; // Q
2479
+ this.altmap[90] = Key.A; // Z
2480
+ this.altmap[88] = Key.B; // X
2481
+ this.altmap[69] = Key.B; // E
2482
+ }
2483
+ setPlayerKeys(player, // player number is 1-based
2484
+ up, down, left, right, A, B) {
2485
+ // We only support four players
2486
+ if (player < 1 || player > 4)
2487
+ return;
2488
+ const keyCodes = [up, down, left, right, A, B];
2489
+ // Check for reserved key codes
2490
+ // TODO: How to surface this runtime error to the user?
2491
+ // TODO: Send message to UI: "Keyboard mapping contains a reserved key code"
2492
+ const filtered = keyCodes.filter(keyCode => reservedKeyCodes.includes(keyCode));
2493
+ if (filtered.length)
2494
+ return;
2495
+ // Clear existing mapped keys for player
2496
+ const mapName = `player-${player}`;
2497
+ this.clearMap(mapName);
2498
+ // Clear altmap When explicitly setting the player keys
2499
+ this.altmap = {};
2500
+ // Map the new keys
2501
+ const offset = (player - 1) * 7; // +7 for player 2's keys
2502
+ this.keymap[up] = Key.Up + offset;
2503
+ this.keymap[down] = Key.Down + offset;
2504
+ this.keymap[left] = Key.Left + offset;
2505
+ this.keymap[right] = Key.Right + offset;
2506
+ this.keymap[A] = Key.A + offset;
2507
+ this.keymap[B] = Key.B + offset;
2508
+ // Remember this mapping
2509
+ this.saveMap(mapName, keyCodes);
2510
+ }
2511
+ setSystemKeys(screenshot, gif, menu, reset) {
2512
+ const mapName = "system";
2513
+ // Clear existing mapped keys for system
2514
+ this.clearMap(mapName);
2515
+ this.keymap[screenshot] = Key.Screenshot;
2516
+ this.keymap[gif] = Key.Gif;
2517
+ this.keymap[menu] = Key.Menu;
2518
+ this.keymap[reset] = Key.Reset;
2519
+ // Remember this mapping
2520
+ this.saveMap(mapName, [screenshot, gif, menu, reset]);
2521
+ }
2522
+ getKey(keyCode) {
2523
+ return keyCode ? this.keymap[keyCode] || this.altmap[keyCode] || Key.None : Key.None;
2524
+ }
2525
+ saveMap(name, keyCodes) {
2526
+ this.mappings[name] = keyCodes;
2527
+ }
2528
+ clearMap(name) {
2529
+ const keyCodes = this.mappings[name];
2530
+ keyCodes === null || keyCodes === void 0 ? void 0 : keyCodes.forEach(keyCode => delete this.keymap[keyCode]);
2531
+ delete this.mappings[name];
2532
+ }
2533
+ }
2534
+ pxsim.KeymapState = KeymapState;
2535
+ })(pxsim || (pxsim = {}));
2536
+ var pxsim;
2398
2537
  (function (pxsim) {
2399
2538
  var multiplayer;
2400
2539
  (function (multiplayer) {
package/built/editor.js CHANGED
@@ -3245,26 +3245,25 @@ class DAPWrapper {
3245
3245
  }
3246
3246
  return len;
3247
3247
  }
3248
- startReadSerial() {
3249
- const rid = this.connectionId;
3248
+ startReadSerial(connectionId) {
3250
3249
  const startTime = Date.now();
3251
- log(`start read serial ${rid}`);
3250
+ log(`start read serial ${connectionId}`);
3252
3251
  const readSerialLoop = async () => {
3253
3252
  try {
3254
- while (rid === this.connectionId) {
3253
+ while (connectionId === this.connectionId) {
3255
3254
  const len = await this.readSerial();
3256
3255
  const hasData = len > 0;
3257
3256
  //if (hasData)
3258
3257
  // logV(`serial read ${len} bytes`)
3259
3258
  await this.jacdacProcess(hasData);
3260
3259
  }
3261
- log(`stopped serial reader ${rid}`);
3260
+ log(`stopped serial reader ${connectionId}`);
3262
3261
  }
3263
3262
  catch (err) {
3264
- log(`serial error ${rid}: ${err.message}`);
3263
+ log(`serial error ${connectionId}: ${err.message}`);
3265
3264
  console.error(err);
3266
- if (rid != this.connectionId) {
3267
- log(`stopped serial reader ${rid}`);
3265
+ if (connectionId != this.connectionId) {
3266
+ log(`stopped serial reader ${connectionId}`);
3268
3267
  }
3269
3268
  else {
3270
3269
  pxt.tickEvent("hid.flash.serial.error");
@@ -3340,8 +3339,9 @@ class DAPWrapper {
3340
3339
  log(`page size ${this.pageSize}, num pages ${this.numPages}`);
3341
3340
  await this.checkStateAsync(true);
3342
3341
  // start jacdac, serial async
3343
- this.startJacdacSetup();
3344
- this.startReadSerial();
3342
+ const connectionId = this.connectionId;
3343
+ this.startJacdacSetup(connectionId)
3344
+ .then(() => this.startReadSerial(connectionId));
3345
3345
  }
3346
3346
  async checkStateAsync(resume) {
3347
3347
  const states = ["reset", "lockup", "sleeping", "halted", "running"];
@@ -3695,32 +3695,13 @@ class DAPWrapper {
3695
3695
  async findJacdacXchgAddr(cid) {
3696
3696
  const memStart = 536870912;
3697
3697
  const memStop = memStart + 128 * 1024;
3698
- const checkSize = 1024;
3699
- let p0 = 0x20006000;
3700
- let p1 = 0x20006000 + checkSize;
3701
- const check = async (addr) => {
3702
- if (addr < memStart)
3703
- return null;
3704
- if (addr + checkSize > memStop)
3705
- return null;
3706
- const buf = await this.readWords(addr, checkSize >> 2);
3707
- for (let i = 0; i < buf.length; ++i) {
3708
- if (buf[i] == 0x786D444A && buf[i + 1] == 0xB0A6C0E9)
3709
- return addr + (i << 2);
3710
- }
3711
- return 0;
3712
- };
3713
- while (cid == this.connectionId) {
3714
- const a0 = await check(p0);
3715
- if (a0)
3716
- return a0;
3717
- const a1 = await check(p1);
3718
- if (a1)
3719
- return a1;
3720
- if (a0 === null && a1 === null)
3721
- return null;
3722
- p0 -= checkSize;
3723
- p1 += checkSize;
3698
+ const addr = (await this.readWords(memStop - 4, 1))[0];
3699
+ if (cid != this.connectionId)
3700
+ return null;
3701
+ if (memStart <= addr && addr < memStop) {
3702
+ const buf = await this.readWords(addr, 2);
3703
+ if (buf[0] == 0x786D444A && buf[1] == 0xB0A6C0E9)
3704
+ return addr;
3724
3705
  }
3725
3706
  return null;
3726
3707
  }
@@ -3729,9 +3710,10 @@ class DAPWrapper {
3729
3710
  * and gracefull cancel as needed
3730
3711
  * @returns
3731
3712
  */
3732
- async startJacdacSetup() {
3713
+ async startJacdacSetup(connectionId) {
3733
3714
  this.xchgAddr = null;
3734
3715
  this.irqn = undefined;
3716
+ this.lastXchg = undefined;
3735
3717
  if (!this.usesCODAL) {
3736
3718
  log(`jacdac: CODAL disabled`);
3737
3719
  return;
@@ -3740,19 +3722,18 @@ class DAPWrapper {
3740
3722
  log(`jacdac: jacdac not compiled in`);
3741
3723
  return;
3742
3724
  }
3743
- const cid = this.connectionId;
3744
3725
  try {
3745
3726
  // allow jacdac to boot
3746
3727
  const now = pxt.U.now();
3747
3728
  await pxt.Util.delay(1000);
3748
3729
  let xchgRetry = 0;
3749
3730
  let xchg;
3750
- while (xchg == null && xchgRetry++ < 2) {
3731
+ while (xchg == null && xchgRetry++ < 3) {
3751
3732
  log(`jacdac: finding xchg address (retry ${xchgRetry})`);
3752
- await pxt.Util.delay(100); // wait for the program to start and setup memory correctly
3753
- if (cid != this.connectionId)
3733
+ await pxt.Util.delay(500); // wait for the program to start and setup memory correctly
3734
+ if (connectionId != this.connectionId)
3754
3735
  return;
3755
- xchg = await this.findJacdacXchgAddr(cid);
3736
+ xchg = await this.findJacdacXchgAddr(connectionId);
3756
3737
  }
3757
3738
  log(`jacdac: exchange address 0x${xchg ? xchg.toString(16) : "?"}; ${xchgRetry} retries; ${(pxt.U.now() - now) | 0}ms`);
3758
3739
  if (xchg == null) {
@@ -3761,7 +3742,7 @@ class DAPWrapper {
3761
3742
  pxt.tickEvent("hid.flash.jacdac.error.missingxchg");
3762
3743
  return;
3763
3744
  }
3764
- if (cid != this.connectionId)
3745
+ if (connectionId != this.connectionId)
3765
3746
  return;
3766
3747
  const info = await this.readBytes(xchg, 16);
3767
3748
  if (info[12 + 2] != 0xff) {
@@ -3771,7 +3752,7 @@ class DAPWrapper {
3771
3752
  return;
3772
3753
  }
3773
3754
  // make sure connection is not outdated
3774
- if (cid != this.connectionId)
3755
+ if (connectionId != this.connectionId)
3775
3756
  return;
3776
3757
  // clear initial lock
3777
3758
  await this.writeWord(xchg + 12, 0);
@@ -3782,7 +3763,7 @@ class DAPWrapper {
3782
3763
  pxt.tickEvent("hid.flash.jacdac.connected");
3783
3764
  }
3784
3765
  catch (e) {
3785
- if (cid != this.connectionId) {
3766
+ if (connectionId != this.connectionId) {
3786
3767
  log(`jacdac: setup aborted`);
3787
3768
  return;
3788
3769
  }