OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview ChromeVox commands. | 6 * @fileoverview ChromeVox commands. |
7 */ | 7 */ |
8 | 8 |
9 goog.provide('CommandHandler'); | 9 goog.provide('CommandHandler'); |
10 | 10 |
(...skipping 27 matching lines...) Expand all Loading... |
38 if (!focusedNode) | 38 if (!focusedNode) |
39 ChromeVoxState.instance.setCurrentRange(null); | 39 ChromeVoxState.instance.setCurrentRange(null); |
40 }); | 40 }); |
41 | 41 |
42 // These commands don't require a current range and work in all modes. | 42 // These commands don't require a current range and work in all modes. |
43 switch (command) { | 43 switch (command) { |
44 case 'speakTimeAndDate': | 44 case 'speakTimeAndDate': |
45 chrome.automation.getDesktop(function(d) { | 45 chrome.automation.getDesktop(function(d) { |
46 // First, try speaking the on-screen time. | 46 // First, try speaking the on-screen time. |
47 var allTime = d.findAll({role: RoleType.TIME}); | 47 var allTime = d.findAll({role: RoleType.TIME}); |
48 allTime.filter(function(t) { return t.root.role == RoleType.DESKTOP; }); | 48 allTime.filter(function(t) { |
| 49 return t.root.role == RoleType.DESKTOP; |
| 50 }); |
49 | 51 |
50 var timeString = ''; | 52 var timeString = ''; |
51 allTime.forEach(function(t) { | 53 allTime.forEach(function(t) { |
52 if (t.name) timeString = t.name; | 54 if (t.name) |
| 55 timeString = t.name; |
53 }); | 56 }); |
54 if (timeString) { | 57 if (timeString) { |
55 cvox.ChromeVox.tts.speak(timeString, cvox.QueueMode.FLUSH); | 58 cvox.ChromeVox.tts.speak(timeString, cvox.QueueMode.FLUSH); |
56 } else { | 59 } else { |
57 // Fallback to the old way of speaking time. | 60 // Fallback to the old way of speaking time. |
58 var output = new Output(); | 61 var output = new Output(); |
59 var dateTime = new Date(); | 62 var dateTime = new Date(); |
60 output | 63 output |
61 .withString( | 64 .withString( |
62 dateTime.toLocaleTimeString() + ', ' + | 65 dateTime.toLocaleTimeString() + ', ' + |
(...skipping 397 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 pred = AutomationPredicate.group; | 463 pred = AutomationPredicate.group; |
461 break; | 464 break; |
462 case 'nextGroup': | 465 case 'nextGroup': |
463 skipSync = true; | 466 skipSync = true; |
464 dir = Dir.FORWARD; | 467 dir = Dir.FORWARD; |
465 pred = AutomationPredicate.group; | 468 pred = AutomationPredicate.group; |
466 break; | 469 break; |
467 case 'jumpToTop': | 470 case 'jumpToTop': |
468 var node = AutomationUtil.findNodePost( | 471 var node = AutomationUtil.findNodePost( |
469 current.start.node.root, Dir.FORWARD, AutomationPredicate.leaf); | 472 current.start.node.root, Dir.FORWARD, AutomationPredicate.leaf); |
470 if (node) | 473 if (node) |
471 current = cursors.Range.fromNode(node); | 474 current = cursors.Range.fromNode(node); |
472 break; | 475 break; |
473 case 'jumpToBottom': | 476 case 'jumpToBottom': |
474 var node = AutomationUtil.findNodePost( | 477 var node = AutomationUtil.findNodePost( |
475 current.start.node.root, Dir.BACKWARD, AutomationPredicate.leaf); | 478 current.start.node.root, Dir.BACKWARD, AutomationPredicate.leaf); |
476 if (node) | 479 if (node) |
477 current = cursors.Range.fromNode(node); | 480 current = cursors.Range.fromNode(node); |
478 break; | 481 break; |
479 case 'forceClickOnCurrentItem': | 482 case 'forceClickOnCurrentItem': |
480 if (ChromeVoxState.instance.currentRange) { | 483 if (ChromeVoxState.instance.currentRange) { |
481 var actionNode = ChromeVoxState.instance.currentRange.start.node; | 484 var actionNode = ChromeVoxState.instance.currentRange.start.node; |
482 while (actionNode.role == RoleType.INLINE_TEXT_BOX || | 485 while (actionNode.role == RoleType.INLINE_TEXT_BOX || |
483 actionNode.role == RoleType.STATIC_TEXT) | 486 actionNode.role == RoleType.STATIC_TEXT) |
484 actionNode = actionNode.parent; | 487 actionNode = actionNode.parent; |
485 if (actionNode.inPageLinkTarget) { | 488 if (actionNode.inPageLinkTarget) { |
486 ChromeVoxState.instance.navigateToRange( | 489 ChromeVoxState.instance.navigateToRange( |
487 cursors.Range.fromNode(actionNode.inPageLinkTarget)); | 490 cursors.Range.fromNode(actionNode.inPageLinkTarget)); |
488 } else { | 491 } else { |
489 actionNode.doDefault(); | 492 actionNode.doDefault(); |
490 } | 493 } |
491 } | 494 } |
492 // Skip all other processing; if focus changes, we should get an event | 495 // Skip all other processing; if focus changes, we should get an event |
493 // for that. | 496 // for that. |
494 return false; | 497 return false; |
495 case 'readFromHere': | 498 case 'readFromHere': |
496 ChromeVoxState.isReadingContinuously = true; | 499 ChromeVoxState.isReadingContinuously = true; |
497 var continueReading = function() { | 500 var continueReading = function() { |
498 if (!ChromeVoxState.isReadingContinuously || | 501 if (!ChromeVoxState.isReadingContinuously || |
499 !ChromeVoxState.instance.currentRange_) | 502 !ChromeVoxState.instance.currentRange_) |
500 return; | 503 return; |
501 | 504 |
502 var prevRange = ChromeVoxState.instance.currentRange_; | 505 var prevRange = ChromeVoxState.instance.currentRange_; |
503 var newRange = | 506 var newRange = ChromeVoxState.instance.currentRange_.move( |
504 ChromeVoxState.instance.currentRange_.move( | 507 cursors.Unit.NODE, Dir.FORWARD); |
505 cursors.Unit.NODE, Dir.FORWARD); | |
506 | 508 |
507 // Stop if we've wrapped back to the document. | 509 // Stop if we've wrapped back to the document. |
508 var maybeDoc = newRange.start.node; | 510 var maybeDoc = newRange.start.node; |
509 if (maybeDoc.role == RoleType.ROOT_WEB_AREA && | 511 if (maybeDoc.role == RoleType.ROOT_WEB_AREA && |
510 maybeDoc.parent.root.role == RoleType.DESKTOP) { | 512 maybeDoc.parent.root.role == RoleType.DESKTOP) { |
511 ChromeVoxState.isReadingContinuously = false; | 513 ChromeVoxState.isReadingContinuously = false; |
512 return; | 514 return; |
513 } | 515 } |
514 | 516 |
515 ChromeVoxState.instance.setCurrentRange(newRange); | 517 ChromeVoxState.instance.setCurrentRange(newRange); |
516 | 518 |
517 new Output() | 519 new Output() |
518 .withRichSpeechAndBraille(ChromeVoxState.instance.currentRange_, | 520 .withRichSpeechAndBraille( |
519 prevRange, | 521 ChromeVoxState.instance.currentRange_, prevRange, |
520 Output.EventType.NAVIGATE) | 522 Output.EventType.NAVIGATE) |
521 .onSpeechEnd(continueReading) | 523 .onSpeechEnd(continueReading) |
522 .go(); | 524 .go(); |
523 }.bind(this); | 525 }.bind(this); |
524 | 526 |
525 new Output() | 527 new Output() |
526 .withRichSpeechAndBraille(ChromeVoxState.instance.currentRange_, | 528 .withRichSpeechAndBraille( |
527 null, | 529 ChromeVoxState.instance.currentRange_, null, |
528 Output.EventType.NAVIGATE) | 530 Output.EventType.NAVIGATE) |
529 .onSpeechEnd(continueReading) | 531 .onSpeechEnd(continueReading) |
530 .go(); | 532 .go(); |
531 | 533 |
532 return false; | 534 return false; |
533 case 'contextMenu': | 535 case 'contextMenu': |
534 if (ChromeVoxState.instance.currentRange_) { | 536 if (ChromeVoxState.instance.currentRange_) { |
535 var actionNode = ChromeVoxState.instance.currentRange_.start.node; | 537 var actionNode = ChromeVoxState.instance.currentRange_.start.node; |
536 if (actionNode.role == RoleType.INLINE_TEXT_BOX) | 538 if (actionNode.role == RoleType.INLINE_TEXT_BOX) |
537 actionNode = actionNode.parent; | 539 actionNode = actionNode.parent; |
538 actionNode.showContextMenu(); | 540 actionNode.showContextMenu(); |
(...skipping 24 matching lines...) Expand all Loading... |
563 case 'readCurrentTitle': | 565 case 'readCurrentTitle': |
564 var target = ChromeVoxState.instance.currentRange_.start.node; | 566 var target = ChromeVoxState.instance.currentRange_.start.node; |
565 var output = new Output(); | 567 var output = new Output(); |
566 | 568 |
567 if (target.root.role == RoleType.ROOT_WEB_AREA) { | 569 if (target.root.role == RoleType.ROOT_WEB_AREA) { |
568 // Web. | 570 // Web. |
569 target = target.root; | 571 target = target.root; |
570 output.withString(target.name || target.docUrl); | 572 output.withString(target.name || target.docUrl); |
571 } else { | 573 } else { |
572 // Views. | 574 // Views. |
573 while (target.role != RoleType.WINDOW) target = target.parent; | 575 while (target.role != RoleType.WINDOW) |
| 576 target = target.parent; |
574 if (target) | 577 if (target) |
575 output.withString(target.name || ''); | 578 output.withString(target.name || ''); |
576 } | 579 } |
577 output.go(); | 580 output.go(); |
578 return false; | 581 return false; |
579 case 'readCurrentURL': | 582 case 'readCurrentURL': |
580 var output = new Output(); | 583 var output = new Output(); |
581 var target = ChromeVoxState.instance.currentRange_.start.node.root; | 584 var target = ChromeVoxState.instance.currentRange_.start.node.root; |
582 output.withString(target.docUrl || '').go(); | 585 output.withString(target.docUrl || '').go(); |
583 return false; | 586 return false; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 predErrorMsg = 'no_cell_right'; | 657 predErrorMsg = 'no_cell_right'; |
655 rootPred = AutomationPredicate.row; | 658 rootPred = AutomationPredicate.row; |
656 break; | 659 break; |
657 case 'goToRowFirstCell': | 660 case 'goToRowFirstCell': |
658 case 'goToRowLastCell': | 661 case 'goToRowLastCell': |
659 var node = current.start.node; | 662 var node = current.start.node; |
660 while (node && node.role != RoleType.ROW) | 663 while (node && node.role != RoleType.ROW) |
661 node = node.parent; | 664 node = node.parent; |
662 if (!node) | 665 if (!node) |
663 break; | 666 break; |
664 var end = AutomationUtil.findNodePost(node, | 667 var end = AutomationUtil.findNodePost( |
665 command == 'goToRowLastCell' ? Dir.BACKWARD : Dir.FORWARD, | 668 node, command == 'goToRowLastCell' ? Dir.BACKWARD : Dir.FORWARD, |
666 AutomationPredicate.leaf); | 669 AutomationPredicate.leaf); |
667 if (end) | 670 if (end) |
668 current = cursors.Range.fromNode(end); | 671 current = cursors.Range.fromNode(end); |
669 break; | 672 break; |
670 case 'goToColFirstCell': | 673 case 'goToColFirstCell': |
671 dir = Dir.FORWARD; | 674 dir = Dir.FORWARD; |
672 var node = current.start.node; | 675 var node = current.start.node; |
673 while (node && node.role != RoleType.TABLE) | 676 while (node && node.role != RoleType.TABLE) |
674 node = node.parent; | 677 node = node.parent; |
675 if (!node || !node.firstChild) | 678 if (!node || !node.firstChild) |
(...skipping 21 matching lines...) Expand all Loading... |
697 predErrorMsg = 'no_cell_below'; | 700 predErrorMsg = 'no_cell_below'; |
698 rootPred = AutomationPredicate.table; | 701 rootPred = AutomationPredicate.table; |
699 break; | 702 break; |
700 case 'goToFirstCell': | 703 case 'goToFirstCell': |
701 case 'goToLastCell': | 704 case 'goToLastCell': |
702 node = current.start.node; | 705 node = current.start.node; |
703 while (node && node.role != RoleType.TABLE) | 706 while (node && node.role != RoleType.TABLE) |
704 node = node.parent; | 707 node = node.parent; |
705 if (!node) | 708 if (!node) |
706 break; | 709 break; |
707 var end = AutomationUtil.findNodePost(node, | 710 var end = AutomationUtil.findNodePost( |
708 command == 'goToLastCell' ? Dir.BACKWARD : Dir.FORWARD, | 711 node, command == 'goToLastCell' ? Dir.BACKWARD : Dir.FORWARD, |
709 AutomationPredicate.leaf); | 712 AutomationPredicate.leaf); |
710 if (end) | 713 if (end) |
711 current = cursors.Range.fromNode(end); | 714 current = cursors.Range.fromNode(end); |
712 break; | 715 break; |
713 default: | 716 default: |
714 return true; | 717 return true; |
715 } | 718 } |
716 | 719 |
717 if (didNavigate) | 720 if (didNavigate) |
718 chrome.metricsPrivate.recordUserAction('Accessibility.ChromeVox.Navigate'); | 721 chrome.metricsPrivate.recordUserAction('Accessibility.ChromeVox.Navigate'); |
(...skipping 14 matching lines...) Expand all Loading... |
733 | 736 |
734 if (node) { | 737 if (node) { |
735 current = cursors.Range.fromNode(node); | 738 current = cursors.Range.fromNode(node); |
736 } else { | 739 } else { |
737 cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.WRAP); | 740 cvox.ChromeVox.earcons.playEarcon(cvox.Earcon.WRAP); |
738 var root = AutomationUtil.getTopLevelRoot(bound) || bound.root; | 741 var root = AutomationUtil.getTopLevelRoot(bound) || bound.root; |
739 if (dir == Dir.FORWARD) { | 742 if (dir == Dir.FORWARD) { |
740 bound = root; | 743 bound = root; |
741 } else { | 744 } else { |
742 bound = AutomationUtil.findNodePost( | 745 bound = AutomationUtil.findNodePost( |
743 root, dir, AutomationPredicate.leaf) || bound; | 746 root, dir, AutomationPredicate.leaf) || |
| 747 bound; |
744 } | 748 } |
745 node = AutomationUtil.findNextNode( | 749 node = AutomationUtil.findNextNode( |
746 bound, dir, pred, {skipInitialAncestry: true}); | 750 bound, dir, pred, {skipInitialAncestry: true}); |
747 | 751 |
748 if (node && !skipSync) { | 752 if (node && !skipSync) { |
749 node = AutomationUtil.findNodePre( | 753 node = AutomationUtil.findNodePre( |
750 node, Dir.FORWARD, AutomationPredicate.object) || node; | 754 node, Dir.FORWARD, AutomationPredicate.object) || |
751 } | 755 node; |
| 756 } |
752 | 757 |
753 if (node) { | 758 if (node) { |
754 current = cursors.Range.fromNode(node); | 759 current = cursors.Range.fromNode(node); |
755 } else if (predErrorMsg) { | 760 } else if (predErrorMsg) { |
756 cvox.ChromeVox.tts.speak( | 761 cvox.ChromeVox.tts.speak( |
757 Msgs.getMsg(predErrorMsg), cvox.QueueMode.FLUSH); | 762 Msgs.getMsg(predErrorMsg), cvox.QueueMode.FLUSH); |
758 return false; | 763 return false; |
759 } | 764 } |
760 } | 765 } |
761 } | 766 } |
762 } | 767 } |
763 | 768 |
764 if (current) | 769 if (current) |
765 ChromeVoxState.instance.navigateToRange(current, undefined, speechProps); | 770 ChromeVoxState.instance.navigateToRange(current, undefined, speechProps); |
766 | 771 |
767 return false; | 772 return false; |
768 }; | 773 }; |
(...skipping 16 matching lines...) Expand all Loading... |
785 chrome.commands.onCommand.addListener(CommandHandler.onCommand); | 790 chrome.commands.onCommand.addListener(CommandHandler.onCommand); |
786 }; | 791 }; |
787 | 792 |
788 /** | 793 /** |
789 * Increase or decrease a speech property and make an announcement. | 794 * Increase or decrease a speech property and make an announcement. |
790 * @param {string} propertyName The name of the property to change. | 795 * @param {string} propertyName The name of the property to change. |
791 * @param {boolean} increase If true, increases the property value by one | 796 * @param {boolean} increase If true, increases the property value by one |
792 * step size, otherwise decreases. | 797 * step size, otherwise decreases. |
793 * @private | 798 * @private |
794 */ | 799 */ |
795 CommandHandler.increaseOrDecreaseSpeechProperty_ = | 800 CommandHandler.increaseOrDecreaseSpeechProperty_ = function( |
796 function(propertyName, increase) { | 801 propertyName, increase) { |
797 cvox.ChromeVox.tts.increaseOrDecreaseProperty(propertyName, increase); | 802 cvox.ChromeVox.tts.increaseOrDecreaseProperty(propertyName, increase); |
798 var announcement; | 803 var announcement; |
799 var valueAsPercent = Math.round( | 804 var valueAsPercent = |
800 cvox.ChromeVox.tts.propertyToPercentage(propertyName) * 100); | 805 Math.round(cvox.ChromeVox.tts.propertyToPercentage(propertyName) * 100); |
801 switch (propertyName) { | 806 switch (propertyName) { |
802 case cvox.AbstractTts.RATE: | 807 case cvox.AbstractTts.RATE: |
803 announcement = Msgs.getMsg('announce_rate', [valueAsPercent]); | 808 announcement = Msgs.getMsg('announce_rate', [valueAsPercent]); |
804 break; | 809 break; |
805 case cvox.AbstractTts.PITCH: | 810 case cvox.AbstractTts.PITCH: |
806 announcement = Msgs.getMsg('announce_pitch', [valueAsPercent]); | 811 announcement = Msgs.getMsg('announce_pitch', [valueAsPercent]); |
807 break; | 812 break; |
808 case cvox.AbstractTts.VOLUME: | 813 case cvox.AbstractTts.VOLUME: |
809 announcement = Msgs.getMsg('announce_volume', [valueAsPercent]); | 814 announcement = Msgs.getMsg('announce_volume', [valueAsPercent]); |
810 break; | 815 break; |
(...skipping 15 matching lines...) Expand all Loading... |
826 * Called when an image frame is received on a node. | 831 * Called when an image frame is received on a node. |
827 * @param {!(AutomationEvent|CustomAutomationEvent)} event The event. | 832 * @param {!(AutomationEvent|CustomAutomationEvent)} event The event. |
828 * @private | 833 * @private |
829 */ | 834 */ |
830 CommandHandler.onImageFrameUpdated_ = function(event) { | 835 CommandHandler.onImageFrameUpdated_ = function(event) { |
831 var target = event.target; | 836 var target = event.target; |
832 if (target != CommandHandler.imageNode_) | 837 if (target != CommandHandler.imageNode_) |
833 return; | 838 return; |
834 | 839 |
835 if (!AutomationUtil.isDescendantOf( | 840 if (!AutomationUtil.isDescendantOf( |
836 ChromeVoxState.instance.currentRange.start.node, | 841 ChromeVoxState.instance.currentRange.start.node, |
837 CommandHandler.imageNode_)) { | 842 CommandHandler.imageNode_)) { |
838 CommandHandler.imageNode_.removeEventListener( | 843 CommandHandler.imageNode_.removeEventListener( |
839 EventType.IMAGE_FRAME_UPDATED, | 844 EventType.IMAGE_FRAME_UPDATED, CommandHandler.onImageFrameUpdated_, |
840 CommandHandler.onImageFrameUpdated_, false); | 845 false); |
841 CommandHandler.imageNode_ = null; | 846 CommandHandler.imageNode_ = null; |
842 return; | 847 return; |
843 } | 848 } |
844 | 849 |
845 if (target.imageDataUrl) { | 850 if (target.imageDataUrl) { |
846 cvox.ChromeVox.braille.writeRawImage(target.imageDataUrl); | 851 cvox.ChromeVox.braille.writeRawImage(target.imageDataUrl); |
847 cvox.ChromeVox.braille.freeze(); | 852 cvox.ChromeVox.braille.freeze(); |
848 } | 853 } |
849 }; | 854 }; |
850 | 855 |
851 /** | 856 /** |
852 * Handle the command to view the first graphic within the current range | 857 * Handle the command to view the first graphic within the current range |
853 * as braille. | 858 * as braille. |
854 * @param {!AutomationNode} current The current range. | 859 * @param {!AutomationNode} current The current range. |
855 * @private | 860 * @private |
856 */ | 861 */ |
857 CommandHandler.viewGraphicAsBraille_ = function(current) { | 862 CommandHandler.viewGraphicAsBraille_ = function(current) { |
858 if (CommandHandler.imageNode_) { | 863 if (CommandHandler.imageNode_) { |
859 CommandHandler.imageNode_.removeEventListener( | 864 CommandHandler.imageNode_.removeEventListener( |
860 EventType.IMAGE_FRAME_UPDATED, | 865 EventType.IMAGE_FRAME_UPDATED, CommandHandler.onImageFrameUpdated_, |
861 CommandHandler.onImageFrameUpdated_, false); | 866 false); |
862 CommandHandler.imageNode_ = null; | 867 CommandHandler.imageNode_ = null; |
863 } | 868 } |
864 | 869 |
865 // Find the first node within the current range that supports image data. | 870 // Find the first node within the current range that supports image data. |
866 var imageNode = AutomationUtil.findNodePost( | 871 var imageNode = AutomationUtil.findNodePost( |
867 current.start.node, Dir.FORWARD, | 872 current.start.node, Dir.FORWARD, AutomationPredicate.supportsImageData); |
868 AutomationPredicate.supportsImageData); | |
869 if (!imageNode) | 873 if (!imageNode) |
870 return; | 874 return; |
871 | 875 |
872 imageNode.addEventListener(EventType.IMAGE_FRAME_UPDATED, | 876 imageNode.addEventListener( |
873 this.onImageFrameUpdated_, false); | 877 EventType.IMAGE_FRAME_UPDATED, this.onImageFrameUpdated_, false); |
874 CommandHandler.imageNode_ = imageNode; | 878 CommandHandler.imageNode_ = imageNode; |
875 if (imageNode.imageDataUrl) { | 879 if (imageNode.imageDataUrl) { |
876 var event = new CustomAutomationEvent( | 880 var event = new CustomAutomationEvent( |
877 EventType.IMAGE_FRAME_UPDATED, imageNode, 'page'); | 881 EventType.IMAGE_FRAME_UPDATED, imageNode, 'page'); |
878 CommandHandler.onImageFrameUpdated_(event); | 882 CommandHandler.onImageFrameUpdated_(event); |
879 } else { | 883 } else { |
880 imageNode.getImageData(0, 0); | 884 imageNode.getImageData(0, 0); |
881 } | 885 } |
882 }; | 886 }; |
883 | 887 |
884 /** | 888 /** |
885 * Performs global initialization. | 889 * Performs global initialization. |
886 * @private | 890 * @private |
887 */ | 891 */ |
888 CommandHandler.init_ = function() { | 892 CommandHandler.init_ = function() { |
889 var firstRunId = 'jdgcneonijmofocbhmijhacgchbihela'; | 893 var firstRunId = 'jdgcneonijmofocbhmijhacgchbihela'; |
890 chrome.runtime.onMessageExternal.addListener( | 894 chrome.runtime.onMessageExternal.addListener(function( |
891 function(request, sender, sendResponse) { | 895 request, sender, sendResponse) { |
892 if (sender.id != firstRunId) | 896 if (sender.id != firstRunId) |
893 return; | 897 return; |
894 | 898 |
895 if (request.openTutorial) { | 899 if (request.openTutorial) { |
896 var launchTutorial = function(desktop, evt) { | 900 var launchTutorial = function(desktop, evt) { |
897 desktop.removeEventListener( | 901 desktop.removeEventListener( |
898 chrome.automation.EventType.FOCUS, launchTutorial, true); | 902 chrome.automation.EventType.FOCUS, launchTutorial, true); |
899 CommandHandler.onCommand('help'); | 903 CommandHandler.onCommand('help'); |
900 }; | 904 }; |
901 | 905 |
902 // Since we get this command early on ChromeVox launch, the first run | 906 // Since we get this command early on ChromeVox launch, the first run |
903 // UI is not yet shown. Monitor for when first run gets focused, and | 907 // UI is not yet shown. Monitor for when first run gets focused, and |
904 // show our tutorial. | 908 // show our tutorial. |
905 chrome.automation.getDesktop(function(desktop) { | 909 chrome.automation.getDesktop(function(desktop) { |
906 launchTutorial = launchTutorial.bind(this, desktop); | 910 launchTutorial = launchTutorial.bind(this, desktop); |
907 desktop.addEventListener( | 911 desktop.addEventListener( |
908 chrome.automation.EventType.FOCUS, launchTutorial, true); | 912 chrome.automation.EventType.FOCUS, launchTutorial, true); |
909 }); | |
910 } | |
911 }); | 913 }); |
| 914 } |
| 915 }); |
912 }; | 916 }; |
913 | 917 |
914 CommandHandler.init_(); | 918 CommandHandler.init_(); |
915 | 919 |
916 }); // goog.scope | 920 }); // goog.scope |
OLD | NEW |