xref: /aosp_15_r20/external/perfetto/ui/src/frontend/help_modal.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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