1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2019 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workerimport m from 'mithril'; 16*6dbdd20aSAndroid Build Coastguard Workerimport {showModal} from '../widgets/modal'; 17*6dbdd20aSAndroid Build Coastguard Workerimport {Spinner} from '../widgets/spinner'; 18*6dbdd20aSAndroid Build Coastguard Workerimport { 19*6dbdd20aSAndroid Build Coastguard Worker KeyboardLayoutMap, 20*6dbdd20aSAndroid Build Coastguard Worker nativeKeyboardLayoutMap, 21*6dbdd20aSAndroid Build Coastguard Worker NotSupportedError, 22*6dbdd20aSAndroid Build Coastguard Worker} from './keyboard_layout_map'; 23*6dbdd20aSAndroid Build Coastguard Workerimport {KeyMapping} from './pan_and_zoom_handler'; 24*6dbdd20aSAndroid Build Coastguard Workerimport {HotkeyGlyphs} from '../widgets/hotkey_glyphs'; 25*6dbdd20aSAndroid Build Coastguard Workerimport {assertExists} from '../base/logging'; 26*6dbdd20aSAndroid Build Coastguard Workerimport {AppImpl} from '../core/app_impl'; 27*6dbdd20aSAndroid Build Coastguard Worker 28*6dbdd20aSAndroid Build Coastguard Workerexport function toggleHelp() { 29*6dbdd20aSAndroid Build Coastguard Worker AppImpl.instance.analytics.logEvent('User Actions', 'Show help'); 30*6dbdd20aSAndroid Build Coastguard Worker showModal({ 31*6dbdd20aSAndroid Build Coastguard Worker title: 'Perfetto Help', 32*6dbdd20aSAndroid Build Coastguard Worker content: () => m(KeyMappingsHelp), 33*6dbdd20aSAndroid Build Coastguard Worker buttons: [], 34*6dbdd20aSAndroid Build Coastguard Worker }); 35*6dbdd20aSAndroid Build Coastguard Worker} 36*6dbdd20aSAndroid Build Coastguard Worker 37*6dbdd20aSAndroid Build Coastguard Workerfunction keycap(glyph: m.Children): m.Children { 38*6dbdd20aSAndroid Build Coastguard Worker return m('.keycap', glyph); 39*6dbdd20aSAndroid Build Coastguard Worker} 40*6dbdd20aSAndroid Build Coastguard Worker 41*6dbdd20aSAndroid Build Coastguard Worker// A fallback keyboard map based on the QWERTY keymap. Converts keyboard event 42*6dbdd20aSAndroid Build Coastguard Worker// codes to their associated glyphs on an English QWERTY keyboard. 43*6dbdd20aSAndroid Build Coastguard Workerclass EnglishQwertyKeyboardLayoutMap implements KeyboardLayoutMap { 44*6dbdd20aSAndroid Build Coastguard Worker get(code: string): string { 45*6dbdd20aSAndroid Build Coastguard Worker // Converts 'KeyX' -> 'x' 46*6dbdd20aSAndroid Build Coastguard Worker return code.replace(/^Key([A-Z])$/, '$1').toLowerCase(); 47*6dbdd20aSAndroid Build Coastguard Worker } 48*6dbdd20aSAndroid Build Coastguard Worker} 49*6dbdd20aSAndroid Build Coastguard Worker 50*6dbdd20aSAndroid Build Coastguard Workerclass KeyMappingsHelp implements m.ClassComponent { 51*6dbdd20aSAndroid Build Coastguard Worker private keyMap?: KeyboardLayoutMap; 52*6dbdd20aSAndroid Build Coastguard Worker 53*6dbdd20aSAndroid Build Coastguard Worker oninit() { 54*6dbdd20aSAndroid Build Coastguard Worker nativeKeyboardLayoutMap() 55*6dbdd20aSAndroid Build Coastguard Worker .then((keyMap: KeyboardLayoutMap) => { 56*6dbdd20aSAndroid Build Coastguard Worker this.keyMap = keyMap; 57*6dbdd20aSAndroid Build Coastguard Worker AppImpl.instance.scheduleFullRedraw('force'); 58*6dbdd20aSAndroid Build Coastguard Worker }) 59*6dbdd20aSAndroid Build Coastguard Worker .catch((e) => { 60*6dbdd20aSAndroid Build Coastguard Worker if ( 61*6dbdd20aSAndroid Build Coastguard Worker e instanceof NotSupportedError || 62*6dbdd20aSAndroid Build Coastguard Worker String(e).includes('SecurityError') 63*6dbdd20aSAndroid Build Coastguard Worker ) { 64*6dbdd20aSAndroid Build Coastguard Worker // Keyboard layout is unavailable. Since showing the keyboard 65*6dbdd20aSAndroid Build Coastguard Worker // mappings correct for the user's keyboard layout is a nice-to- 66*6dbdd20aSAndroid Build Coastguard Worker // have, and users with non-QWERTY layouts are usually aware of the 67*6dbdd20aSAndroid Build Coastguard Worker // fact that the are using non-QWERTY layouts, we resort to showing 68*6dbdd20aSAndroid Build Coastguard Worker // English QWERTY mappings as a best-effort approach. 69*6dbdd20aSAndroid Build Coastguard Worker // The alternative would be to show key mappings for all keyboard 70*6dbdd20aSAndroid Build Coastguard Worker // layouts which is not feasible. 71*6dbdd20aSAndroid Build Coastguard Worker this.keyMap = new EnglishQwertyKeyboardLayoutMap(); 72*6dbdd20aSAndroid Build Coastguard Worker AppImpl.instance.scheduleFullRedraw('force'); 73*6dbdd20aSAndroid Build Coastguard Worker } else { 74*6dbdd20aSAndroid Build Coastguard Worker // Something unexpected happened. Either the browser doesn't conform 75*6dbdd20aSAndroid Build Coastguard Worker // to the keyboard API spec, or the keyboard API spec has changed! 76*6dbdd20aSAndroid Build Coastguard Worker throw e; 77*6dbdd20aSAndroid Build Coastguard Worker } 78*6dbdd20aSAndroid Build Coastguard Worker }); 79*6dbdd20aSAndroid Build Coastguard Worker } 80*6dbdd20aSAndroid Build Coastguard Worker 81*6dbdd20aSAndroid Build Coastguard Worker view(): m.Children { 82*6dbdd20aSAndroid Build Coastguard Worker return m( 83*6dbdd20aSAndroid Build Coastguard Worker '.help', 84*6dbdd20aSAndroid Build Coastguard Worker m('h2', 'Navigation'), 85*6dbdd20aSAndroid Build Coastguard Worker m( 86*6dbdd20aSAndroid Build Coastguard Worker 'table', 87*6dbdd20aSAndroid Build Coastguard Worker m( 88*6dbdd20aSAndroid Build Coastguard Worker 'tr', 89*6dbdd20aSAndroid Build Coastguard Worker m( 90*6dbdd20aSAndroid Build Coastguard Worker 'td', 91*6dbdd20aSAndroid Build Coastguard Worker this.codeToKeycap(KeyMapping.KEY_ZOOM_IN), 92*6dbdd20aSAndroid Build Coastguard Worker '/', 93*6dbdd20aSAndroid Build Coastguard Worker this.codeToKeycap(KeyMapping.KEY_ZOOM_OUT), 94*6dbdd20aSAndroid Build Coastguard Worker ), 95*6dbdd20aSAndroid Build Coastguard Worker m('td', 'Zoom in/out'), 96*6dbdd20aSAndroid Build Coastguard Worker ), 97*6dbdd20aSAndroid Build Coastguard Worker m( 98*6dbdd20aSAndroid Build Coastguard Worker 'tr', 99*6dbdd20aSAndroid Build Coastguard Worker m( 100*6dbdd20aSAndroid Build Coastguard Worker 'td', 101*6dbdd20aSAndroid Build Coastguard Worker this.codeToKeycap(KeyMapping.KEY_PAN_LEFT), 102*6dbdd20aSAndroid Build Coastguard Worker '/', 103*6dbdd20aSAndroid Build Coastguard Worker this.codeToKeycap(KeyMapping.KEY_PAN_RIGHT), 104*6dbdd20aSAndroid Build Coastguard Worker ), 105*6dbdd20aSAndroid Build Coastguard Worker m('td', 'Pan left/right'), 106*6dbdd20aSAndroid Build Coastguard Worker ), 107*6dbdd20aSAndroid Build Coastguard Worker ), 108*6dbdd20aSAndroid Build Coastguard Worker m('h2', 'Mouse Controls'), 109*6dbdd20aSAndroid Build Coastguard Worker m( 110*6dbdd20aSAndroid Build Coastguard Worker 'table', 111*6dbdd20aSAndroid Build Coastguard Worker m('tr', m('td', 'Click'), m('td', 'Select event')), 112*6dbdd20aSAndroid Build Coastguard Worker m('tr', m('td', 'Ctrl + Scroll wheel'), m('td', 'Zoom in/out')), 113*6dbdd20aSAndroid Build Coastguard Worker m('tr', m('td', 'Click + Drag'), m('td', 'Select area')), 114*6dbdd20aSAndroid Build Coastguard Worker m('tr', m('td', 'Shift + Click + Drag'), m('td', 'Pan left/right')), 115*6dbdd20aSAndroid Build Coastguard Worker ), 116*6dbdd20aSAndroid Build Coastguard Worker m('h2', 'Running commands from the viewer page'), 117*6dbdd20aSAndroid Build Coastguard Worker m( 118*6dbdd20aSAndroid Build Coastguard Worker 'table', 119*6dbdd20aSAndroid Build Coastguard Worker m( 120*6dbdd20aSAndroid Build Coastguard Worker 'tr', 121*6dbdd20aSAndroid Build Coastguard Worker m('td', keycap('>'), ' in the (empty) search box'), 122*6dbdd20aSAndroid Build Coastguard Worker m('td', 'Switch to command mode'), 123*6dbdd20aSAndroid Build Coastguard Worker ), 124*6dbdd20aSAndroid Build Coastguard Worker ), 125*6dbdd20aSAndroid Build Coastguard Worker m('h2', 'Making SQL queries from the viewer page'), 126*6dbdd20aSAndroid Build Coastguard Worker m( 127*6dbdd20aSAndroid Build Coastguard Worker 'table', 128*6dbdd20aSAndroid Build Coastguard Worker m( 129*6dbdd20aSAndroid Build Coastguard Worker 'tr', 130*6dbdd20aSAndroid Build Coastguard Worker m('td', keycap(':'), ' in the (empty) search box'), 131*6dbdd20aSAndroid Build Coastguard Worker m('td', 'Switch to query mode'), 132*6dbdd20aSAndroid Build Coastguard Worker ), 133*6dbdd20aSAndroid Build Coastguard Worker m('tr', m('td', keycap('Enter')), m('td', 'Execute query')), 134*6dbdd20aSAndroid Build Coastguard Worker m( 135*6dbdd20aSAndroid Build Coastguard Worker 'tr', 136*6dbdd20aSAndroid Build Coastguard Worker m('td', keycap('Ctrl'), ' + ', keycap('Enter')), 137*6dbdd20aSAndroid Build Coastguard Worker m( 138*6dbdd20aSAndroid Build Coastguard Worker 'td', 139*6dbdd20aSAndroid Build Coastguard Worker 'Execute query and pin output ' + 140*6dbdd20aSAndroid Build Coastguard Worker '(output will not be replaced by regular query input)', 141*6dbdd20aSAndroid Build Coastguard Worker ), 142*6dbdd20aSAndroid Build Coastguard Worker ), 143*6dbdd20aSAndroid Build Coastguard Worker ), 144*6dbdd20aSAndroid Build Coastguard Worker m('h2', 'Making SQL queries from the query page'), 145*6dbdd20aSAndroid Build Coastguard Worker m( 146*6dbdd20aSAndroid Build Coastguard Worker 'table', 147*6dbdd20aSAndroid Build Coastguard Worker m( 148*6dbdd20aSAndroid Build Coastguard Worker 'tr', 149*6dbdd20aSAndroid Build Coastguard Worker m('td', keycap('Ctrl'), ' + ', keycap('Enter')), 150*6dbdd20aSAndroid Build Coastguard Worker m('td', 'Execute query'), 151*6dbdd20aSAndroid Build Coastguard Worker ), 152*6dbdd20aSAndroid Build Coastguard Worker m( 153*6dbdd20aSAndroid Build Coastguard Worker 'tr', 154*6dbdd20aSAndroid Build Coastguard Worker m('td', keycap('Ctrl'), ' + ', keycap('Enter'), ' (with selection)'), 155*6dbdd20aSAndroid Build Coastguard Worker m('td', 'Execute selection'), 156*6dbdd20aSAndroid Build Coastguard Worker ), 157*6dbdd20aSAndroid Build Coastguard Worker ), 158*6dbdd20aSAndroid Build Coastguard Worker m('h2', 'Command Hotkeys'), 159*6dbdd20aSAndroid Build Coastguard Worker m( 160*6dbdd20aSAndroid Build Coastguard Worker 'table', 161*6dbdd20aSAndroid Build Coastguard Worker AppImpl.instance.commands.commands 162*6dbdd20aSAndroid Build Coastguard Worker .filter(({defaultHotkey}) => defaultHotkey) 163*6dbdd20aSAndroid Build Coastguard Worker .sort((a, b) => a.name.localeCompare(b.name)) 164*6dbdd20aSAndroid Build Coastguard Worker .map(({defaultHotkey, name}) => { 165*6dbdd20aSAndroid Build Coastguard Worker return m( 166*6dbdd20aSAndroid Build Coastguard Worker 'tr', 167*6dbdd20aSAndroid Build Coastguard Worker m('td', m(HotkeyGlyphs, {hotkey: assertExists(defaultHotkey)})), 168*6dbdd20aSAndroid Build Coastguard Worker m('td', name), 169*6dbdd20aSAndroid Build Coastguard Worker ); 170*6dbdd20aSAndroid Build Coastguard Worker }), 171*6dbdd20aSAndroid Build Coastguard Worker ), 172*6dbdd20aSAndroid Build Coastguard Worker ); 173*6dbdd20aSAndroid Build Coastguard Worker } 174*6dbdd20aSAndroid Build Coastguard Worker 175*6dbdd20aSAndroid Build Coastguard Worker private codeToKeycap(code: string): m.Children { 176*6dbdd20aSAndroid Build Coastguard Worker if (this.keyMap) { 177*6dbdd20aSAndroid Build Coastguard Worker return keycap(this.keyMap.get(code)); 178*6dbdd20aSAndroid Build Coastguard Worker } else { 179*6dbdd20aSAndroid Build Coastguard Worker return keycap(m(Spinner)); 180*6dbdd20aSAndroid Build Coastguard Worker } 181*6dbdd20aSAndroid Build Coastguard Worker } 182*6dbdd20aSAndroid Build Coastguard Worker} 183