1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/system_key_event_listener.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 7513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include <gdk/gdkx.h> 8513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include <X11/XF86keysym.h> 9513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/audio_handler.h" 1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/chromeos/brightness_bubble.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/volume_bubble.h" 133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "chrome/browser/metrics/user_metrics.h" 1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "third_party/cros/chromeos_wm_ipc_enums.h" 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chromeos { 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst double kStepPercentage = 4.0; 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 2521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenSystemKeyEventListener* SystemKeyEventListener::GetInstance() { 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return Singleton<SystemKeyEventListener>::get(); 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSystemKeyEventListener::SystemKeyEventListener() 3072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen : stopped_(false), 3172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen audio_handler_(AudioHandler::GetInstance()) { 3221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen WmMessageListener::GetInstance()->AddObserver(this); 33513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch key_volume_mute_ = XKeysymToKeycode(GDK_DISPLAY(), XF86XK_AudioMute); 35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch key_volume_down_ = XKeysymToKeycode(GDK_DISPLAY(), XF86XK_AudioLowerVolume); 36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch key_volume_up_ = XKeysymToKeycode(GDK_DISPLAY(), XF86XK_AudioRaiseVolume); 37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch key_f8_ = XKeysymToKeycode(GDK_DISPLAY(), XK_F8); 38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch key_f9_ = XKeysymToKeycode(GDK_DISPLAY(), XK_F9); 39513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch key_f10_ = XKeysymToKeycode(GDK_DISPLAY(), XK_F10); 40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 41513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (key_volume_mute_) 42513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GrabKey(key_volume_mute_, 0); 43513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (key_volume_down_) 44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GrabKey(key_volume_down_, 0); 45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (key_volume_up_) 46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GrabKey(key_volume_up_, 0); 47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GrabKey(key_f8_, 0); 48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GrabKey(key_f9_, 0); 49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GrabKey(key_f10_, 0); 50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch gdk_window_add_filter(NULL, GdkEventFilter, this); 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSystemKeyEventListener::~SystemKeyEventListener() { 5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Stop(); 5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 5772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid SystemKeyEventListener::Stop() { 5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen if (stopped_) 5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return; 6021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen WmMessageListener::GetInstance()->RemoveObserver(this); 61513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch gdk_window_remove_filter(NULL, GdkEventFilter, this); 6272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen audio_handler_->Disconnect(); 6372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen stopped_ = true; 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SystemKeyEventListener::ProcessWmMessage(const WmIpc::Message& message, 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch GdkWindow* window) { 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (message.type() != WM_IPC_MESSAGE_CHROME_NOTIFY_SYSKEY_PRESSED) 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (message.param(0)) { 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case WM_IPC_SYSTEM_KEY_VOLUME_MUTE: 74513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch OnVolumeMute(); 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case WM_IPC_SYSTEM_KEY_VOLUME_DOWN: 77513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch OnVolumeDown(); 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case WM_IPC_SYSTEM_KEY_VOLUME_UP: 80513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch OnVolumeUp(); 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DLOG(ERROR) << "SystemKeyEventListener: Unexpected message " 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << message.param(0) 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch << " received"; 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// static 90513209b27ff55e2841eac0e4120199c23acce758Ben MurdochGdkFilterReturn SystemKeyEventListener::GdkEventFilter(GdkXEvent* gxevent, 91513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GdkEvent* gevent, 92513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch gpointer data) { 93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch SystemKeyEventListener* listener = static_cast<SystemKeyEventListener*>(data); 94513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch XEvent* xevent = static_cast<XEvent*>(gxevent); 95513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 96513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (xevent->type == KeyPress) { 97513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch int32 keycode = xevent->xkey.keycode; 98513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (keycode) { 994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Only doing non-Alt/Shift/Ctrl modified keys 1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if (!(xevent->xkey.state & (Mod1Mask | ShiftMask | ControlMask))) { 1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch if ((keycode == listener->key_f8_) || 1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch (keycode == listener->key_volume_mute_)) { 1033f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (keycode == listener->key_f8_) 1043f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeMute_F8")); 1054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch listener->OnVolumeMute(); 1064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return GDK_FILTER_REMOVE; 1074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else if ((keycode == listener->key_f9_) || 1084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch keycode == listener->key_volume_down_) { 1093f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (keycode == listener->key_f9_) 1103f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeDown_F9")); 1114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch listener->OnVolumeDown(); 1124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return GDK_FILTER_REMOVE; 1134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } else if ((keycode == listener->key_f10_) || 1144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch (keycode == listener->key_volume_up_)) { 1153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen if (keycode == listener->key_f10_) 1163f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeUp_F10")); 1174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch listener->OnVolumeUp(); 1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return GDK_FILTER_REMOVE; 1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 120513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 121513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 122513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 123513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch return GDK_FILTER_CONTINUE; 124513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 126513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SystemKeyEventListener::GrabKey(int32 key, uint32 mask) { 127513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch uint32 num_lock_mask = Mod2Mask; 128513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch uint32 caps_lock_mask = LockMask; 129513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch Window root = DefaultRootWindow(GDK_DISPLAY()); 130513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch XGrabKey(GDK_DISPLAY(), key, mask, root, True, GrabModeAsync, GrabModeAsync); 131513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch XGrabKey(GDK_DISPLAY(), key, mask | caps_lock_mask, root, True, 132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GrabModeAsync, GrabModeAsync); 133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch XGrabKey(GDK_DISPLAY(), key, mask | num_lock_mask, root, True, 134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch GrabModeAsync, GrabModeAsync); 135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch XGrabKey(GDK_DISPLAY(), key, mask | caps_lock_mask | num_lock_mask, root, 136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch True, GrabModeAsync, GrabModeAsync); 137513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 138513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 13921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// TODO(davej): Move the ShowBubble() calls in to AudioHandler so that this 14021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// function returns faster without blocking on GetVolumePercent(), and still 14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// guarantees that the volume displayed will be that after the adjustment. 142513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 14321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// TODO(davej): The IsMute() check can also be made non-blocking by changing to 14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// an AdjustVolumeByPercentOrUnmute() function which can do the steps off of 14521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// this thread when ShowBubble() is moved in to AudioHandler. 146513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 147513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SystemKeyEventListener::OnVolumeMute() { 148513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // Always muting (and not toggling) as per final decision on 149513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch // http://crosbug.com/3751 150513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch audio_handler_->SetMute(true); 15121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen VolumeBubble::GetInstance()->ShowBubble(0); 15221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen BrightnessBubble::GetInstance()->HideBubble(); 153513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 154513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 155513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SystemKeyEventListener::OnVolumeDown() { 156513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (audio_handler_->IsMute()) { 15721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen VolumeBubble::GetInstance()->ShowBubble(0); 158513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } else { 159513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch audio_handler_->AdjustVolumeByPercent(-kStepPercentage); 16021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen VolumeBubble::GetInstance()->ShowBubble( 161513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch audio_handler_->GetVolumePercent()); 162513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch } 16321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen BrightnessBubble::GetInstance()->HideBubble(); 164513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 165513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 166513209b27ff55e2841eac0e4120199c23acce758Ben Murdochvoid SystemKeyEventListener::OnVolumeUp() { 167513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch if (audio_handler_->IsMute()) 168513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch audio_handler_->SetMute(false); 169513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch else 170513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch audio_handler_->AdjustVolumeByPercent(kStepPercentage); 17121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen VolumeBubble::GetInstance()->ShowBubble( 172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch audio_handler_->GetVolumePercent()); 17321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen BrightnessBubble::GetInstance()->HideBubble(); 174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch} 175513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace chromeos 177