| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ash/mus/accelerators/accelerator_controller_registrar.h" |
| 6 |
| 7 #include <limits> |
| 8 |
| 9 #include "ash/common/accelerators/accelerator_controller.h" |
| 10 #include "ash/common/accelerators/accelerator_router.h" |
| 11 #include "ash/common/wm_shell.h" |
| 12 #include "ash/mus/accelerators/accelerator_ids.h" |
| 13 #include "ash/mus/bridge/wm_window_mus.h" |
| 14 #include "ash/mus/window_manager.h" |
| 15 #include "base/logging.h" |
| 16 #include "services/ui/common/event_matcher_util.h" |
| 17 #include "services/ui/public/cpp/window_manager_delegate.h" |
| 18 #include "services/ui/public/cpp/window_tree_client.h" |
| 19 #include "ui/base/accelerators/accelerator_history.h" |
| 20 |
| 21 namespace ash { |
| 22 namespace mus { |
| 23 namespace { |
| 24 |
| 25 // Callback from registering the accelerator. All our accelerators should be |
| 26 // registered, so we expect |added| to be true. |
| 27 void OnAcceleratorAdded(bool added) { |
| 28 DCHECK(added); |
| 29 } |
| 30 |
| 31 } // namespace |
| 32 |
| 33 AcceleratorControllerRegistrar::AcceleratorControllerRegistrar( |
| 34 WindowManager* window_manager, |
| 35 uint16_t id_namespace) |
| 36 : window_manager_(window_manager), |
| 37 id_namespace_(id_namespace), |
| 38 next_id_(0), |
| 39 router_(new AcceleratorRouter) { |
| 40 window_manager_->AddAcceleratorHandler(id_namespace, this); |
| 41 } |
| 42 |
| 43 AcceleratorControllerRegistrar::~AcceleratorControllerRegistrar() { |
| 44 window_manager_->RemoveAcceleratorHandler(id_namespace_); |
| 45 |
| 46 if (!window_manager_->window_manager_client()) |
| 47 return; |
| 48 |
| 49 // TODO(sky): consider not doing this. If we assume the destructor is called |
| 50 // during shutdown, then this is unnecessary and results in a bunch of |
| 51 // messages that are dropped. |
| 52 for (uint16_t local_id : ids_) { |
| 53 window_manager_->window_manager_client()->RemoveAccelerator( |
| 54 ComputeAcceleratorId(id_namespace_, local_id)); |
| 55 } |
| 56 } |
| 57 |
| 58 ui::mojom::EventResult AcceleratorControllerRegistrar::OnAccelerator( |
| 59 uint32_t id, |
| 60 const ui::Event& event) { |
| 61 // TODO: during startup a bunch of accelerators are registered, resulting in |
| 62 // lots of IPC. We should optimize this to send a single IPC. |
| 63 // http://crbug.com/632050 |
| 64 const ui::Accelerator accelerator(*event.AsKeyEvent()); |
| 65 auto iter = accelerator_to_ids_.find(accelerator); |
| 66 if (iter == accelerator_to_ids_.end()) { |
| 67 // Because of timing we may have unregistered the accelerator already, |
| 68 // ignore in that case. |
| 69 return ui::mojom::EventResult::UNHANDLED; |
| 70 } |
| 71 |
| 72 const Ids& ids = iter->second; |
| 73 AcceleratorController* accelerator_controller = |
| 74 WmShell::Get()->accelerator_controller(); |
| 75 const bool is_pre = GetAcceleratorLocalId(id) == ids.pre_id; |
| 76 if (is_pre) { |
| 77 // TODO(sky): this does not exactly match ash code. In particular ash code |
| 78 // is called for *all* key events, where as this is only called for |
| 79 // registered accelerators. This means the previous accelerator isn't the |
| 80 // same as it was in ash. We need to figure out exactly what is needed of |
| 81 // previous accelerator so that we can either register for the right set of |
| 82 // accelerators, or make WS send the previous accelerator. |
| 83 // http://crbug.com/630683. |
| 84 accelerator_controller->accelerator_history()->StoreCurrentAccelerator( |
| 85 accelerator); |
| 86 WmWindow* target_window = WmShell::Get()->GetFocusedWindow(); |
| 87 if (!target_window) |
| 88 target_window = WmShell::Get()->GetRootWindowForNewWindows(); |
| 89 DCHECK(target_window); |
| 90 return router_->ProcessAccelerator(target_window, *(event.AsKeyEvent()), |
| 91 accelerator) |
| 92 ? ui::mojom::EventResult::HANDLED |
| 93 : ui::mojom::EventResult::UNHANDLED; |
| 94 } |
| 95 DCHECK_EQ(GetAcceleratorLocalId(id), ids.post_id); |
| 96 // NOTE: for post return value doesn't really matter. |
| 97 return WmShell::Get()->accelerator_controller()->Process(accelerator) |
| 98 ? ui::mojom::EventResult::HANDLED |
| 99 : ui::mojom::EventResult::UNHANDLED; |
| 100 } |
| 101 |
| 102 void AcceleratorControllerRegistrar::OnAcceleratorRegistered( |
| 103 const ui::Accelerator& accelerator) { |
| 104 Ids ids; |
| 105 if (!GenerateIds(&ids)) { |
| 106 DVLOG(1) << "max number of accelerators registered, dropping request"; |
| 107 return; |
| 108 } |
| 109 DCHECK_EQ(0u, accelerator_to_ids_.count(accelerator)); |
| 110 accelerator_to_ids_[accelerator] = ids; |
| 111 DCHECK_EQ(accelerator_to_ids_.size() * 2, ids_.size()); |
| 112 |
| 113 ui::mojom::EventMatcherPtr event_matcher = ui::CreateKeyMatcher( |
| 114 static_cast<ui::mojom::KeyboardCode>(accelerator.key_code()), |
| 115 accelerator.modifiers()); |
| 116 event_matcher->accelerator_phase = ui::mojom::AcceleratorPhase::PRE_TARGET; |
| 117 DCHECK(accelerator.type() == ui::ET_KEY_PRESSED || |
| 118 accelerator.type() == ui::ET_KEY_RELEASED); |
| 119 event_matcher->type_matcher->type = accelerator.type() == ui::ET_KEY_PRESSED |
| 120 ? ui::mojom::EventType::KEY_PRESSED |
| 121 : ui::mojom::EventType::KEY_RELEASED; |
| 122 |
| 123 ui::mojom::EventMatcherPtr post_event_matcher = event_matcher.Clone(); |
| 124 post_event_matcher->accelerator_phase = |
| 125 ui::mojom::AcceleratorPhase::POST_TARGET; |
| 126 |
| 127 window_manager_->window_manager_client()->AddAccelerator( |
| 128 ComputeAcceleratorId(id_namespace_, ids.pre_id), std::move(event_matcher), |
| 129 base::Bind(OnAcceleratorAdded)); |
| 130 window_manager_->window_manager_client()->AddAccelerator( |
| 131 ComputeAcceleratorId(id_namespace_, ids.post_id), |
| 132 std::move(post_event_matcher), base::Bind(OnAcceleratorAdded)); |
| 133 } |
| 134 |
| 135 void AcceleratorControllerRegistrar::OnAcceleratorUnregistered( |
| 136 const ui::Accelerator& accelerator) { |
| 137 auto iter = accelerator_to_ids_.find(accelerator); |
| 138 DCHECK(iter != accelerator_to_ids_.end()); |
| 139 Ids ids = iter->second; |
| 140 accelerator_to_ids_.erase(iter); |
| 141 ids_.erase(ids.pre_id); |
| 142 ids_.erase(ids.post_id); |
| 143 DCHECK_EQ(accelerator_to_ids_.size() * 2, ids_.size()); |
| 144 window_manager_->window_manager_client()->RemoveAccelerator( |
| 145 ComputeAcceleratorId(id_namespace_, ids.pre_id)); |
| 146 window_manager_->window_manager_client()->RemoveAccelerator( |
| 147 ComputeAcceleratorId(id_namespace_, ids.post_id)); |
| 148 } |
| 149 |
| 150 bool AcceleratorControllerRegistrar::GenerateIds(Ids* ids) { |
| 151 if (ids_.size() + 2 >= std::numeric_limits<uint16_t>::max()) |
| 152 return false; |
| 153 ids->pre_id = GetNextLocalAcceleratorId(); |
| 154 ids->post_id = GetNextLocalAcceleratorId(); |
| 155 return true; |
| 156 } |
| 157 |
| 158 uint16_t AcceleratorControllerRegistrar::GetNextLocalAcceleratorId() { |
| 159 DCHECK_LT(ids_.size(), std::numeric_limits<uint16_t>::max()); |
| 160 // Common case is we never wrap once, so this is typically cheap. Additionally |
| 161 // we expect there not to be too many accelerators. |
| 162 while (ids_.count(next_id_) > 0) |
| 163 ++next_id_; |
| 164 ids_.insert(next_id_); |
| 165 return next_id_++; |
| 166 } |
| 167 |
| 168 } // namespace mus |
| 169 } // namespace ash |
| OLD | NEW |