1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/gtk/accelerators_gtk.h"
6
7#include <gdk/gdk.h>
8#include <gdk/gdkkeysyms.h>
9#include <X11/XF86keysym.h>
10
11#include "base/memory/singleton.h"
12#include "chrome/app/chrome_command_ids.h"
13
14namespace {
15
16// A mostly complete list of chrome's accelerators. When one command has
17// multiple shortcuts, the first one in this list is considered "primary",
18// meaning that it will be displayed in context menus.
19const struct AcceleratorMapping {
20  guint keyval;
21  int command_id;
22  GdkModifierType modifier_type;
23} kAcceleratorMap[] = {
24  // Focus.
25  { GDK_k, IDC_FOCUS_SEARCH, GDK_CONTROL_MASK },
26  { GDK_e, IDC_FOCUS_SEARCH, GDK_CONTROL_MASK },
27  { XF86XK_Search, IDC_FOCUS_SEARCH, GdkModifierType(0) },
28  { GDK_l, IDC_FOCUS_LOCATION, GDK_CONTROL_MASK },
29  { GDK_d, IDC_FOCUS_LOCATION, GDK_MOD1_MASK },
30  { GDK_F6, IDC_FOCUS_LOCATION, GdkModifierType(0) },
31  { XF86XK_OpenURL, IDC_FOCUS_LOCATION, GdkModifierType(0) },
32  { XF86XK_Go, IDC_FOCUS_LOCATION, GdkModifierType(0) },
33
34  // Tab/window controls.
35  { GDK_Page_Down, IDC_SELECT_NEXT_TAB, GDK_CONTROL_MASK },
36  { GDK_Page_Up, IDC_SELECT_PREVIOUS_TAB, GDK_CONTROL_MASK },
37  { GDK_Page_Down, IDC_MOVE_TAB_NEXT,
38    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
39  { GDK_Page_Up, IDC_MOVE_TAB_PREVIOUS,
40    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
41  { GDK_Page_Up, IDC_SELECT_PREVIOUS_TAB, GDK_CONTROL_MASK },
42  { GDK_w, IDC_CLOSE_TAB, GDK_CONTROL_MASK },
43  { GDK_t, IDC_RESTORE_TAB,
44    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
45  { GDK_t, IDC_NEW_TAB, GDK_CONTROL_MASK },
46  { GDK_n, IDC_NEW_WINDOW, GDK_CONTROL_MASK },
47  { GDK_n, IDC_NEW_INCOGNITO_WINDOW,
48    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
49
50  { GDK_1, IDC_SELECT_TAB_0, GDK_CONTROL_MASK },
51  { GDK_2, IDC_SELECT_TAB_1, GDK_CONTROL_MASK },
52  { GDK_3, IDC_SELECT_TAB_2, GDK_CONTROL_MASK },
53  { GDK_4, IDC_SELECT_TAB_3, GDK_CONTROL_MASK },
54  { GDK_5, IDC_SELECT_TAB_4, GDK_CONTROL_MASK },
55  { GDK_6, IDC_SELECT_TAB_5, GDK_CONTROL_MASK },
56  { GDK_7, IDC_SELECT_TAB_6, GDK_CONTROL_MASK },
57  { GDK_8, IDC_SELECT_TAB_7, GDK_CONTROL_MASK },
58  { GDK_9, IDC_SELECT_LAST_TAB, GDK_CONTROL_MASK },
59
60  { GDK_1, IDC_SELECT_TAB_0, GDK_MOD1_MASK },
61  { GDK_2, IDC_SELECT_TAB_1, GDK_MOD1_MASK },
62  { GDK_3, IDC_SELECT_TAB_2, GDK_MOD1_MASK },
63  { GDK_4, IDC_SELECT_TAB_3, GDK_MOD1_MASK },
64  { GDK_5, IDC_SELECT_TAB_4, GDK_MOD1_MASK },
65  { GDK_6, IDC_SELECT_TAB_5, GDK_MOD1_MASK },
66  { GDK_7, IDC_SELECT_TAB_6, GDK_MOD1_MASK },
67  { GDK_8, IDC_SELECT_TAB_7, GDK_MOD1_MASK },
68  { GDK_9, IDC_SELECT_LAST_TAB, GDK_MOD1_MASK },
69
70  { GDK_KP_1, IDC_SELECT_TAB_0, GDK_CONTROL_MASK },
71  { GDK_KP_2, IDC_SELECT_TAB_1, GDK_CONTROL_MASK },
72  { GDK_KP_3, IDC_SELECT_TAB_2, GDK_CONTROL_MASK },
73  { GDK_KP_4, IDC_SELECT_TAB_3, GDK_CONTROL_MASK },
74  { GDK_KP_5, IDC_SELECT_TAB_4, GDK_CONTROL_MASK },
75  { GDK_KP_6, IDC_SELECT_TAB_5, GDK_CONTROL_MASK },
76  { GDK_KP_7, IDC_SELECT_TAB_6, GDK_CONTROL_MASK },
77  { GDK_KP_8, IDC_SELECT_TAB_7, GDK_CONTROL_MASK },
78  { GDK_KP_9, IDC_SELECT_LAST_TAB, GDK_CONTROL_MASK },
79
80  { GDK_KP_1, IDC_SELECT_TAB_0, GDK_MOD1_MASK },
81  { GDK_KP_2, IDC_SELECT_TAB_1, GDK_MOD1_MASK },
82  { GDK_KP_3, IDC_SELECT_TAB_2, GDK_MOD1_MASK },
83  { GDK_KP_4, IDC_SELECT_TAB_3, GDK_MOD1_MASK },
84  { GDK_KP_5, IDC_SELECT_TAB_4, GDK_MOD1_MASK },
85  { GDK_KP_6, IDC_SELECT_TAB_5, GDK_MOD1_MASK },
86  { GDK_KP_7, IDC_SELECT_TAB_6, GDK_MOD1_MASK },
87  { GDK_KP_8, IDC_SELECT_TAB_7, GDK_MOD1_MASK },
88  { GDK_KP_9, IDC_SELECT_LAST_TAB, GDK_MOD1_MASK },
89
90  { GDK_F4, IDC_CLOSE_TAB, GDK_CONTROL_MASK },
91  { GDK_F4, IDC_CLOSE_WINDOW, GDK_MOD1_MASK },
92
93  // Zoom level.
94  { GDK_KP_Add, IDC_ZOOM_PLUS, GDK_CONTROL_MASK },
95  { GDK_plus, IDC_ZOOM_PLUS,
96    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
97  { GDK_equal, IDC_ZOOM_PLUS, GDK_CONTROL_MASK },
98  { XF86XK_ZoomIn, IDC_ZOOM_PLUS, GdkModifierType(0) },
99  { GDK_KP_0, IDC_ZOOM_NORMAL, GDK_CONTROL_MASK },
100  { GDK_0, IDC_ZOOM_NORMAL, GDK_CONTROL_MASK },
101  { GDK_KP_Subtract, IDC_ZOOM_MINUS, GDK_CONTROL_MASK },
102  { GDK_minus, IDC_ZOOM_MINUS, GDK_CONTROL_MASK },
103  { GDK_underscore, IDC_ZOOM_MINUS,
104    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
105  { XF86XK_ZoomOut, IDC_ZOOM_MINUS, GdkModifierType(0) },
106
107  // Find in page.
108  { GDK_g, IDC_FIND_NEXT, GDK_CONTROL_MASK },
109  { GDK_F3, IDC_FIND_NEXT, GdkModifierType(0) },
110  { GDK_g, IDC_FIND_PREVIOUS,
111    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
112  { GDK_F3, IDC_FIND_PREVIOUS, GDK_SHIFT_MASK },
113
114  // Navigation / toolbar buttons.
115  { GDK_Home, IDC_HOME, GDK_MOD1_MASK },
116  { XF86XK_HomePage, IDC_HOME, GdkModifierType(0) },
117  { GDK_Escape, IDC_STOP, GdkModifierType(0) },
118  { XF86XK_Stop, IDC_STOP, GdkModifierType(0) },
119  { GDK_Left, IDC_BACK, GDK_MOD1_MASK },
120  { XF86XK_Back, IDC_BACK, GdkModifierType(0) },
121  { GDK_Right, IDC_FORWARD, GDK_MOD1_MASK },
122  { XF86XK_Forward, IDC_FORWARD, GdkModifierType(0) },
123  { GDK_r, IDC_RELOAD, GDK_CONTROL_MASK },
124  { GDK_r, IDC_RELOAD_IGNORING_CACHE,
125    GdkModifierType(GDK_CONTROL_MASK|GDK_SHIFT_MASK) },
126  { GDK_F5, IDC_RELOAD, GdkModifierType(0) },
127  { GDK_F5, IDC_RELOAD_IGNORING_CACHE, GDK_CONTROL_MASK },
128  { GDK_F5, IDC_RELOAD_IGNORING_CACHE, GDK_SHIFT_MASK },
129  { XF86XK_Reload, IDC_RELOAD, GdkModifierType(0) },
130  { XF86XK_Refresh, IDC_RELOAD, GdkModifierType(0) },
131
132  // Dev tools.
133  { GDK_u, IDC_VIEW_SOURCE, GDK_CONTROL_MASK },
134  { GDK_i, IDC_DEV_TOOLS,
135    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
136  { GDK_F12, IDC_DEV_TOOLS, GdkModifierType(0) },
137  { GDK_j, IDC_DEV_TOOLS_CONSOLE,
138    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
139  { GDK_c, IDC_DEV_TOOLS_INSPECT,
140    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
141  { GDK_Escape, IDC_TASK_MANAGER, GDK_SHIFT_MASK },
142
143  // Editing.
144  { GDK_c, IDC_COPY, GDK_CONTROL_MASK },
145  { GDK_x, IDC_CUT, GDK_CONTROL_MASK },
146  { GDK_v, IDC_PASTE, GDK_CONTROL_MASK },
147
148  // Autofill.
149  { GDK_a, IDC_AUTOFILL_DEFAULT,
150    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
151
152  // Miscellany.
153  { GDK_d, IDC_BOOKMARK_ALL_TABS,
154    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
155  { GDK_d, IDC_BOOKMARK_PAGE, GDK_CONTROL_MASK },
156  { GDK_o, IDC_OPEN_FILE, GDK_CONTROL_MASK },
157  { GDK_f, IDC_FIND, GDK_CONTROL_MASK },
158  { GDK_p, IDC_PRINT, GDK_CONTROL_MASK },
159  { GDK_b, IDC_SHOW_BOOKMARK_BAR,
160    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
161  { GDK_F11, IDC_FULLSCREEN, GdkModifierType(0) },
162  { GDK_Delete, IDC_CLEAR_BROWSING_DATA,
163    GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
164  { GDK_h, IDC_SHOW_HISTORY, GDK_CONTROL_MASK },
165  { GDK_j, IDC_SHOW_DOWNLOADS, GDK_CONTROL_MASK },
166  { GDK_F1, IDC_HELP_PAGE, GdkModifierType(0) },
167  { XF86XK_AddFavorite, IDC_BOOKMARK_PAGE, GdkModifierType(0) },
168  { XF86XK_Favorites, IDC_SHOW_BOOKMARK_BAR, GdkModifierType(0) },
169  { XF86XK_History, IDC_SHOW_HISTORY, GdkModifierType(0) },
170  { GDK_q, IDC_EXIT, GdkModifierType(GDK_CONTROL_MASK | GDK_SHIFT_MASK) },
171  { GDK_s, IDC_SAVE_PAGE, GDK_CONTROL_MASK },
172  { GDK_e, IDC_SHOW_APP_MENU, GDK_MOD1_MASK },
173  { GDK_f, IDC_SHOW_APP_MENU, GDK_MOD1_MASK },
174};
175
176}  // namespace
177
178AcceleratorsGtk::AcceleratorsGtk() {
179  for (size_t i = 0; i < arraysize(kAcceleratorMap); ++i) {
180    int command_id = kAcceleratorMap[i].command_id;
181    ui::AcceleratorGtk accelerator(kAcceleratorMap[i].keyval,
182                                      kAcceleratorMap[i].modifier_type);
183    all_accelerators_.push_back(
184        std::pair<int, ui::AcceleratorGtk>(command_id, accelerator));
185
186    if (primary_accelerators_.find(command_id) ==
187        primary_accelerators_.end()) {
188      primary_accelerators_[command_id] = accelerator;
189    }
190  }
191}
192
193AcceleratorsGtk::~AcceleratorsGtk() {}
194
195// static
196AcceleratorsGtk* AcceleratorsGtk::GetInstance() {
197  return Singleton<AcceleratorsGtk>::get();
198}
199
200const ui::AcceleratorGtk* AcceleratorsGtk::GetPrimaryAcceleratorForCommand(
201    int command_id) {
202  base::hash_map<int, ui::AcceleratorGtk>::const_iterator iter =
203      primary_accelerators_.find(command_id);
204
205  if (iter == primary_accelerators_.end())
206    return NULL;
207
208  return &iter->second;
209}
210