diff options
author | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-25 15:02:11 +0000 |
---|---|---|
committer | tfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-25 15:02:11 +0000 |
commit | 2b68f8170eac47782a7680fc97b44886e27ac2fe (patch) | |
tree | 4ac3bd72425f89bed4226f0d724d089362c5ede3 /ui/base/accelerators | |
parent | 3138146004b13a2f1a249da15531d96a53f3e2d2 (diff) | |
download | chromium_src-2b68f8170eac47782a7680fc97b44886e27ac2fe.zip chromium_src-2b68f8170eac47782a7680fc97b44886e27ac2fe.tar.gz chromium_src-2b68f8170eac47782a7680fc97b44886e27ac2fe.tar.bz2 |
Move accelerator related files to ui/base/accelerators
BUG=104599
R=mazda@chromium.org
Review URL: http://codereview.chromium.org/8695005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111597 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base/accelerators')
-rw-r--r-- | ui/base/accelerators/accelerator.cc | 163 | ||||
-rw-r--r-- | ui/base/accelerators/accelerator.h | 129 | ||||
-rw-r--r-- | ui/base/accelerators/accelerator_cocoa.h | 44 | ||||
-rw-r--r-- | ui/base/accelerators/accelerator_cocoa.mm | 41 | ||||
-rw-r--r-- | ui/base/accelerators/accelerator_gtk.h | 59 | ||||
-rw-r--r-- | ui/base/accelerators/accelerator_manager.cc | 77 | ||||
-rw-r--r-- | ui/base/accelerators/accelerator_manager.h | 65 |
7 files changed, 578 insertions, 0 deletions
diff --git a/ui/base/accelerators/accelerator.cc b/ui/base/accelerators/accelerator.cc new file mode 100644 index 0000000..74d9f03 --- /dev/null +++ b/ui/base/accelerators/accelerator.cc @@ -0,0 +1,163 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/accelerators/accelerator.h" + +#if defined(OS_WIN) +#include <windows.h> +#elif defined(TOOLKIT_USES_GTK) +#include <gdk/gdk.h> +#endif + +#include "base/i18n/rtl.h" +#include "base/logging.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "grit/ui_strings.h" +#include "ui/base/l10n/l10n_util.h" + +namespace ui { + +string16 Accelerator::GetShortcutText() const { + int string_id = 0; + switch(key_code_) { + case ui::VKEY_TAB: + string_id = IDS_APP_TAB_KEY; + break; + case ui::VKEY_RETURN: + string_id = IDS_APP_ENTER_KEY; + break; + case ui::VKEY_ESCAPE: + string_id = IDS_APP_ESC_KEY; + break; + case ui::VKEY_PRIOR: + string_id = IDS_APP_PAGEUP_KEY; + break; + case ui::VKEY_NEXT: + string_id = IDS_APP_PAGEDOWN_KEY; + break; + case ui::VKEY_END: + string_id = IDS_APP_END_KEY; + break; + case ui::VKEY_HOME: + string_id = IDS_APP_HOME_KEY; + break; + case ui::VKEY_INSERT: + string_id = IDS_APP_INSERT_KEY; + break; + case ui::VKEY_DELETE: + string_id = IDS_APP_DELETE_KEY; + break; + case ui::VKEY_LEFT: + string_id = IDS_APP_LEFT_ARROW_KEY; + break; + case ui::VKEY_RIGHT: + string_id = IDS_APP_RIGHT_ARROW_KEY; + break; + case ui::VKEY_BACK: + string_id = IDS_APP_BACKSPACE_KEY; + break; + case ui::VKEY_F1: + string_id = IDS_APP_F1_KEY; + break; + case ui::VKEY_F11: + string_id = IDS_APP_F11_KEY; + break; + default: + break; + } + + string16 shortcut; + if (!string_id) { +#if defined(OS_WIN) + // Our fallback is to try translate the key code to a regular character + // unless it is one of digits (VK_0 to VK_9). Some keyboard + // layouts have characters other than digits assigned in + // an unshifted mode (e.g. French AZERY layout has 'a with grave + // accent' for '0'). For display in the menu (e.g. Ctrl-0 for the + // default zoom level), we leave VK_[0-9] alone without translation. + wchar_t key; + if (key_code_ >= '0' && key_code_ <= '9') + key = key_code_; + else + key = LOWORD(::MapVirtualKeyW(key_code_, MAPVK_VK_TO_CHAR)); + shortcut += key; +#elif defined(TOOLKIT_USES_GTK) + const gchar* name = NULL; + switch (key_code_) { + case ui::VKEY_OEM_2: + name = static_cast<const gchar*>("/"); + break; + default: + name = gdk_keyval_name(gdk_keyval_to_lower(key_code_)); + break; + } + if (name) { + if (name[0] != 0 && name[1] == 0) + shortcut += static_cast<string16::value_type>(g_ascii_toupper(name[0])); + else + shortcut += UTF8ToUTF16(name); + } +#endif + } else { + shortcut = l10n_util::GetStringUTF16(string_id); + } + + // Checking whether the character used for the accelerator is alphanumeric. + // If it is not, then we need to adjust the string later on if the locale is + // right-to-left. See below for more information of why such adjustment is + // required. + string16 shortcut_rtl; + bool adjust_shortcut_for_rtl = false; + if (base::i18n::IsRTL() && shortcut.length() == 1 && + !IsAsciiAlpha(shortcut[0]) && !IsAsciiDigit(shortcut[0])) { + adjust_shortcut_for_rtl = true; + shortcut_rtl.assign(shortcut); + } + + if (IsShiftDown()) + shortcut = l10n_util::GetStringFUTF16(IDS_APP_SHIFT_MODIFIER, shortcut); + + // Note that we use 'else-if' in order to avoid using Ctrl+Alt as a shortcut. + // See http://blogs.msdn.com/oldnewthing/archive/2004/03/29/101121.aspx for + // more information. + if (IsCtrlDown()) + shortcut = l10n_util::GetStringFUTF16(IDS_APP_CONTROL_MODIFIER, shortcut); + else if (IsAltDown()) + shortcut = l10n_util::GetStringFUTF16(IDS_APP_ALT_MODIFIER, shortcut); + + // For some reason, menus in Windows ignore standard Unicode directionality + // marks (such as LRE, PDF, etc.). On RTL locales, we use RTL menus and + // therefore any text we draw for the menu items is drawn in an RTL context. + // Thus, the text "Ctrl++" (which we currently use for the Zoom In option) + // appears as "++Ctrl" in RTL because the Unicode BiDi algorithm puts + // punctuations on the left when the context is right-to-left. Shortcuts that + // do not end with a punctuation mark (such as "Ctrl+H" do not have this + // problem). + // + // The only way to solve this problem is to adjust the string if the locale + // is RTL so that it is drawn correnctly in an RTL context. Instead of + // returning "Ctrl++" in the above example, we return "++Ctrl". This will + // cause the text to appear as "Ctrl++" when Windows draws the string in an + // RTL context because the punctunation no longer appears at the end of the + // string. + // + // TODO(idana) bug# 1232732: this hack can be avoided if instead of using + // views::Menu we use views::MenuItemView because the latter is a View + // subclass and therefore it supports marking text as RTL or LTR using + // standard Unicode directionality marks. + if (adjust_shortcut_for_rtl) { + int key_length = static_cast<int>(shortcut_rtl.length()); + DCHECK_GT(key_length, 0); + shortcut_rtl.append(ASCIIToUTF16("+")); + + // Subtracting the size of the shortcut key and 1 for the '+' sign. + shortcut_rtl.append(shortcut, 0, shortcut.length() - key_length - 1); + shortcut.swap(shortcut_rtl); + } + + return shortcut; +} + +} // namespace ui diff --git a/ui/base/accelerators/accelerator.h b/ui/base/accelerators/accelerator.h new file mode 100644 index 0000000..5977c8c2 --- /dev/null +++ b/ui/base/accelerators/accelerator.h @@ -0,0 +1,129 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// This class describe a keyboard accelerator (or keyboard shortcut). +// Keyboard accelerators are registered with the FocusManager. +// It has a copy constructor and assignment operator so that it can be copied. +// It also defines the < operator so that it can be used as a key in a std::map. +// + +#ifndef UI_BASE_ACCELERATORS_ACCELERATOR_H_ +#define UI_BASE_ACCELERATORS_ACCELERATOR_H_ +#pragma once + +#include "base/string16.h" +#include "ui/base/keycodes/keyboard_codes.h" +#include "ui/base/events.h" +#include "ui/base/ui_export.h" + +namespace ui { + +// This is a cross-platform base class for accelerator keys used in menus. It is +// meant to be subclassed for concrete toolkit implementations. +class UI_EXPORT Accelerator { + public: + Accelerator() : key_code_(ui::VKEY_UNKNOWN), modifiers_(0) {} + + Accelerator(ui::KeyboardCode keycode, int modifiers) + : key_code_(keycode), + modifiers_(modifiers) {} + + Accelerator(const Accelerator& accelerator) { + key_code_ = accelerator.key_code_; + modifiers_ = accelerator.modifiers_; + } + + Accelerator(ui::KeyboardCode keycode, + bool shift_pressed, bool ctrl_pressed, bool alt_pressed) + : key_code_(keycode), + modifiers_(0) { + if (shift_pressed) + modifiers_ |= ui::EF_SHIFT_DOWN; + if (ctrl_pressed) + modifiers_ |= ui::EF_CONTROL_DOWN; + if (alt_pressed) + modifiers_ |= ui::EF_ALT_DOWN; + } + + virtual ~Accelerator() {} + + Accelerator& operator=(const Accelerator& accelerator) { + if (this != &accelerator) { + key_code_ = accelerator.key_code_; + modifiers_ = accelerator.modifiers_; + } + return *this; + } + + // We define the < operator so that the KeyboardShortcut can be used as a key + // in a std::map. + bool operator <(const Accelerator& rhs) const { + if (key_code_ != rhs.key_code_) + return key_code_ < rhs.key_code_; + return modifiers_ < rhs.modifiers_; + } + + bool operator ==(const Accelerator& rhs) const { + return (key_code_ == rhs.key_code_) && (modifiers_ == rhs.modifiers_); + } + + bool operator !=(const Accelerator& rhs) const { + return !(*this == rhs); + } + + ui::KeyboardCode key_code() const { return key_code_; } + + int modifiers() const { return modifiers_; } + + bool IsShiftDown() const { + return (modifiers_ & ui::EF_SHIFT_DOWN) == ui::EF_SHIFT_DOWN; + } + + bool IsCtrlDown() const { + return (modifiers_ & ui::EF_CONTROL_DOWN) == ui::EF_CONTROL_DOWN; + } + + bool IsAltDown() const { + return (modifiers_ & ui::EF_ALT_DOWN) == ui::EF_ALT_DOWN; + } + + // Returns a string with the localized shortcut if any. + string16 GetShortcutText() const; + + protected: + // The keycode (VK_...). + ui::KeyboardCode key_code_; + + // The state of the Shift/Ctrl/Alt keys (platform-dependent). + int modifiers_; +}; + +// An interface that classes that want to register for keyboard accelerators +// should implement. +class UI_EXPORT AcceleratorTarget { + public: + // This method should return true if the accelerator was processed. + virtual bool AcceleratorPressed(const Accelerator& accelerator) = 0; + + protected: + virtual ~AcceleratorTarget() {} +}; + +// Since acclerator code is one of the few things that can't be cross platform +// in the chrome UI, separate out just the GetAcceleratorForCommandId() from +// the menu delegates. +class AcceleratorProvider { + public: + // Gets the accelerator for the specified command id. Returns true if the + // command id has a valid accelerator, false otherwise. + virtual bool GetAcceleratorForCommandId(int command_id, + ui::Accelerator* accelerator) = 0; + + protected: + virtual ~AcceleratorProvider() {} +}; + +} // namespace ui + +#endif // UI_BASE_ACCELERATORS_ACCELERATOR_H_ diff --git a/ui/base/accelerators/accelerator_cocoa.h b/ui/base/accelerators/accelerator_cocoa.h new file mode 100644 index 0000000..5be4715 --- /dev/null +++ b/ui/base/accelerators/accelerator_cocoa.h @@ -0,0 +1,44 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_ACCELERATORS_ACCELERATOR_COCOA_H_ +#define UI_BASE_ACCELERATORS_ACCELERATOR_COCOA_H_ +#pragma once + +#include <Foundation/Foundation.h> + +#include "base/memory/scoped_nsobject.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/ui_export.h" + +namespace ui { + +// This is a subclass of the cross-platform Accelerator, but with more direct +// support for Cocoa key equivalents. Note that the typical use case for this +// class is to initialize it with a string literal, which is why it sends +// |-copy| to the |key_code| paramater in the constructor. +class UI_EXPORT AcceleratorCocoa : public Accelerator { + public: + AcceleratorCocoa(); + AcceleratorCocoa(NSString* key_code, NSUInteger mask); + AcceleratorCocoa(const AcceleratorCocoa& accelerator); + virtual ~AcceleratorCocoa(); + + AcceleratorCocoa& operator=(const AcceleratorCocoa& accelerator); + + bool operator==(const AcceleratorCocoa& rhs) const; + bool operator!=(const AcceleratorCocoa& rhs) const; + + NSString* characters() const { + return characters_.get(); + } + + private: + // String of characters for the key equivalent. + scoped_nsobject<NSString> characters_; +}; + +} // namespace ui + +#endif // UI_BASE_ACCELERATORS_ACCELERATOR_COCOA_H_ diff --git a/ui/base/accelerators/accelerator_cocoa.mm b/ui/base/accelerators/accelerator_cocoa.mm new file mode 100644 index 0000000..f88290c --- /dev/null +++ b/ui/base/accelerators/accelerator_cocoa.mm @@ -0,0 +1,41 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/accelerators/accelerator_cocoa.h" + +namespace ui { + +AcceleratorCocoa::AcceleratorCocoa() : Accelerator() {} + +AcceleratorCocoa::AcceleratorCocoa(NSString* key_code, NSUInteger mask) + : Accelerator(ui::VKEY_UNKNOWN, mask), + characters_([key_code copy]) { +} + +AcceleratorCocoa::AcceleratorCocoa(const AcceleratorCocoa& accelerator) + : Accelerator(accelerator) { + characters_.reset([accelerator.characters_ copy]); +} + +AcceleratorCocoa::~AcceleratorCocoa() {} + +AcceleratorCocoa& AcceleratorCocoa::operator=( + const AcceleratorCocoa& accelerator) { + if (this != &accelerator) { + *static_cast<Accelerator*>(this) = accelerator; + characters_.reset([accelerator.characters_ copy]); + } + return *this; +} + +bool AcceleratorCocoa::operator==(const AcceleratorCocoa& rhs) const { + return [characters_ isEqualToString:rhs.characters_.get()] && + (modifiers_ == rhs.modifiers_); +} + +bool AcceleratorCocoa::operator!=(const AcceleratorCocoa& rhs) const { + return !(*this == rhs); +} + +} // namespace ui diff --git a/ui/base/accelerators/accelerator_gtk.h b/ui/base/accelerators/accelerator_gtk.h new file mode 100644 index 0000000..4b4f1b3 --- /dev/null +++ b/ui/base/accelerators/accelerator_gtk.h @@ -0,0 +1,59 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_ACCELERATORS_ACCELERATOR_GTK_H_ +#define UI_BASE_ACCELERATORS_ACCELERATOR_GTK_H_ +#pragma once + +#include <gdk/gdk.h> + +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/keycodes/keyboard_code_conversion_gtk.h" +#include "ui/base/keycodes/keyboard_codes_posix.h" + +namespace ui { + +class AcceleratorGtk : public Accelerator { + public: + AcceleratorGtk(ui::KeyboardCode key_code, + bool shift_pressed, bool ctrl_pressed, bool alt_pressed) + : gdk_keyval_(0) { + key_code_ = key_code; + modifiers_ = 0; + if (shift_pressed) + modifiers_ |= GDK_SHIFT_MASK; + if (ctrl_pressed) + modifiers_ |= GDK_CONTROL_MASK; + if (alt_pressed) + modifiers_ |= GDK_MOD1_MASK; + } + + AcceleratorGtk(guint keyval, GdkModifierType modifier_type) { + key_code_ = ui::WindowsKeyCodeForGdkKeyCode(keyval); + gdk_keyval_ = keyval; + modifiers_ = modifier_type; + } + + AcceleratorGtk() : gdk_keyval_(0) { } + virtual ~AcceleratorGtk() { } + + guint GetGdkKeyCode() const { + return gdk_keyval_ > 0 ? + // The second parameter is false because accelerator keys are + // expressed in terms of the non-shift-modified key. + gdk_keyval_ : ui::GdkKeyCodeForWindowsKeyCode(key_code_, false); + } + + GdkModifierType gdk_modifier_type() const { + return static_cast<GdkModifierType>(modifiers()); + } + + private: + // The GDK keycode. + guint gdk_keyval_; +}; + +} // namespace ui + +#endif // UI_BASE_ACCELERATORS_ACCELERATOR_GTK_H_ diff --git a/ui/base/accelerators/accelerator_manager.cc b/ui/base/accelerators/accelerator_manager.cc new file mode 100644 index 0000000..c675211 --- /dev/null +++ b/ui/base/accelerators/accelerator_manager.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/base/accelerators/accelerator_manager.h" + +#include <algorithm> + +#include "base/logging.h" + +namespace ui { + +AcceleratorManager::AcceleratorManager() { +} + +AcceleratorManager::~AcceleratorManager() { +} + +void AcceleratorManager::Register(const Accelerator& accelerator, + AcceleratorTarget* target) { + AcceleratorTargetList& targets = accelerators_[accelerator]; + DCHECK(std::find(targets.begin(), targets.end(), target) == targets.end()) + << "Registering the same target multiple times"; + targets.push_front(target); +} + +void AcceleratorManager::Unregister(const Accelerator& accelerator, + AcceleratorTarget* target) { + AcceleratorMap::iterator map_iter = accelerators_.find(accelerator); + if (map_iter == accelerators_.end()) { + NOTREACHED() << "Unregistering non-existing accelerator"; + return; + } + + AcceleratorTargetList* targets = &map_iter->second; + AcceleratorTargetList::iterator target_iter = + std::find(targets->begin(), targets->end(), target); + if (target_iter == targets->end()) { + NOTREACHED() << "Unregistering accelerator for wrong target"; + return; + } + + targets->erase(target_iter); +} + +void AcceleratorManager::UnregisterAll(AcceleratorTarget* target) { + for (AcceleratorMap::iterator map_iter = accelerators_.begin(); + map_iter != accelerators_.end(); ++map_iter) { + AcceleratorTargetList* targets = &map_iter->second; + targets->remove(target); + } +} + +bool AcceleratorManager::Process(const Accelerator& accelerator) { + AcceleratorMap::iterator map_iter = accelerators_.find(accelerator); + if (map_iter != accelerators_.end()) { + // We have to copy the target list here, because an AcceleratorPressed + // event handler may modify the list. + AcceleratorTargetList targets(map_iter->second); + for (AcceleratorTargetList::iterator iter = targets.begin(); + iter != targets.end(); ++iter) { + if ((*iter)->AcceleratorPressed(accelerator)) + return true; + } + } + return false; +} + +AcceleratorTarget* AcceleratorManager::GetCurrentTarget( + const Accelerator& accelerator) const { + AcceleratorMap::const_iterator map_iter = accelerators_.find(accelerator); + if (map_iter == accelerators_.end() || map_iter->second.empty()) + return NULL; + return map_iter->second.front(); +} + +} // namespace ui diff --git a/ui/base/accelerators/accelerator_manager.h b/ui/base/accelerators/accelerator_manager.h new file mode 100644 index 0000000..50c73c0 --- /dev/null +++ b/ui/base/accelerators/accelerator_manager.h @@ -0,0 +1,65 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_BASE_ACCELERATORS_ACCELERATOR_MANAGER_H_ +#define UI_BASE_ACCELERATORS_ACCELERATOR_MANAGER_H_ +#pragma once + +#include <list> +#include <map> + +#include "base/basictypes.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/ui_export.h" + +namespace ui { + +// The AcceleratorManger is used to handle keyboard accelerators. +class UI_EXPORT AcceleratorManager { + public: + AcceleratorManager(); + ~AcceleratorManager(); + + // Register a keyboard accelerator for the specified target. If multiple + // targets are registered for an accelerator, a target registered later has + // higher priority. + // Note that we are currently limited to accelerators that are either: + // - a key combination including Ctrl or Alt + // - the escape key + // - the enter key + // - any F key (F1, F2, F3 ...) + // - any browser specific keys (as available on special keyboards) + void Register(const Accelerator& accelerator, AcceleratorTarget* target); + + // Unregister the specified keyboard accelerator for the specified target. + void Unregister(const Accelerator& accelerator, AcceleratorTarget* target); + + // Unregister all keyboard accelerator for the specified target. + void UnregisterAll(AcceleratorTarget* target); + + // Activate the target associated with the specified accelerator. + // First, AcceleratorPressed handler of the most recently registered target + // is called, and if that handler processes the event (i.e. returns true), + // this method immediately returns. If not, we do the same thing on the next + // target, and so on. + // Returns true if an accelerator was activated. + bool Process(const Accelerator& accelerator); + + // Returns the AcceleratorTarget that should be activated for the specified + // keyboard accelerator, or NULL if no view is registered for that keyboard + // accelerator. + AcceleratorTarget* GetCurrentTarget(const Accelerator& accelertor) const; + + private: + // The accelerators and associated targets. + typedef std::list<AcceleratorTarget*> AcceleratorTargetList; + typedef std::map<Accelerator, AcceleratorTargetList> AcceleratorMap; + AcceleratorMap accelerators_; + + DISALLOW_COPY_AND_ASSIGN(AcceleratorManager); +}; + +} // namespace ui + +#endif // UI_BASE_ACCELERATORS_ACCELERATOR_MANAGER_H_ |