system_key_event_listener.cc revision 3f50c38dc070f4bb515c1b64450dae14f316474e
1// Copyright (c) 2010 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/chromeos/system_key_event_listener.h" 6 7#include <gdk/gdkx.h> 8#include <X11/XF86keysym.h> 9 10#include "chrome/browser/chromeos/audio_handler.h" 11#include "chrome/browser/chromeos/brightness_bubble.h" 12#include "chrome/browser/chromeos/volume_bubble.h" 13#include "chrome/browser/metrics/user_metrics.h" 14#include "third_party/cros/chromeos_wm_ipc_enums.h" 15 16namespace chromeos { 17 18namespace { 19 20const double kStepPercentage = 4.0; 21 22} // namespace 23 24// static 25SystemKeyEventListener* SystemKeyEventListener::GetInstance() { 26 return Singleton<SystemKeyEventListener>::get(); 27} 28 29SystemKeyEventListener::SystemKeyEventListener() 30 : audio_handler_(AudioHandler::GetInstance()) { 31 WmMessageListener::GetInstance()->AddObserver(this); 32 33 key_volume_mute_ = XKeysymToKeycode(GDK_DISPLAY(), XF86XK_AudioMute); 34 key_volume_down_ = XKeysymToKeycode(GDK_DISPLAY(), XF86XK_AudioLowerVolume); 35 key_volume_up_ = XKeysymToKeycode(GDK_DISPLAY(), XF86XK_AudioRaiseVolume); 36 key_f8_ = XKeysymToKeycode(GDK_DISPLAY(), XK_F8); 37 key_f9_ = XKeysymToKeycode(GDK_DISPLAY(), XK_F9); 38 key_f10_ = XKeysymToKeycode(GDK_DISPLAY(), XK_F10); 39 40 if (key_volume_mute_) 41 GrabKey(key_volume_mute_, 0); 42 if (key_volume_down_) 43 GrabKey(key_volume_down_, 0); 44 if (key_volume_up_) 45 GrabKey(key_volume_up_, 0); 46 GrabKey(key_f8_, 0); 47 GrabKey(key_f9_, 0); 48 GrabKey(key_f10_, 0); 49 gdk_window_add_filter(NULL, GdkEventFilter, this); 50} 51 52SystemKeyEventListener::~SystemKeyEventListener() { 53 WmMessageListener::GetInstance()->RemoveObserver(this); 54 gdk_window_remove_filter(NULL, GdkEventFilter, this); 55} 56 57void SystemKeyEventListener::ProcessWmMessage(const WmIpc::Message& message, 58 GdkWindow* window) { 59 if (message.type() != WM_IPC_MESSAGE_CHROME_NOTIFY_SYSKEY_PRESSED) 60 return; 61 62 switch (message.param(0)) { 63 case WM_IPC_SYSTEM_KEY_VOLUME_MUTE: 64 OnVolumeMute(); 65 break; 66 case WM_IPC_SYSTEM_KEY_VOLUME_DOWN: 67 OnVolumeDown(); 68 break; 69 case WM_IPC_SYSTEM_KEY_VOLUME_UP: 70 OnVolumeUp(); 71 break; 72 default: 73 DLOG(ERROR) << "SystemKeyEventListener: Unexpected message " 74 << message.param(0) 75 << " received"; 76 } 77} 78 79// static 80GdkFilterReturn SystemKeyEventListener::GdkEventFilter(GdkXEvent* gxevent, 81 GdkEvent* gevent, 82 gpointer data) { 83 SystemKeyEventListener* listener = static_cast<SystemKeyEventListener*>(data); 84 XEvent* xevent = static_cast<XEvent*>(gxevent); 85 86 if (xevent->type == KeyPress) { 87 int32 keycode = xevent->xkey.keycode; 88 if (keycode) { 89 // Only doing non-Alt/Shift/Ctrl modified keys 90 if (!(xevent->xkey.state & (Mod1Mask | ShiftMask | ControlMask))) { 91 if ((keycode == listener->key_f8_) || 92 (keycode == listener->key_volume_mute_)) { 93 if (keycode == listener->key_f8_) 94 UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeMute_F8")); 95 listener->OnVolumeMute(); 96 return GDK_FILTER_REMOVE; 97 } else if ((keycode == listener->key_f9_) || 98 keycode == listener->key_volume_down_) { 99 if (keycode == listener->key_f9_) 100 UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeDown_F9")); 101 listener->OnVolumeDown(); 102 return GDK_FILTER_REMOVE; 103 } else if ((keycode == listener->key_f10_) || 104 (keycode == listener->key_volume_up_)) { 105 if (keycode == listener->key_f10_) 106 UserMetrics::RecordAction(UserMetricsAction("Accel_VolumeUp_F10")); 107 listener->OnVolumeUp(); 108 return GDK_FILTER_REMOVE; 109 } 110 } 111 } 112 } 113 return GDK_FILTER_CONTINUE; 114} 115 116void SystemKeyEventListener::GrabKey(int32 key, uint32 mask) { 117 uint32 num_lock_mask = Mod2Mask; 118 uint32 caps_lock_mask = LockMask; 119 Window root = DefaultRootWindow(GDK_DISPLAY()); 120 XGrabKey(GDK_DISPLAY(), key, mask, root, True, GrabModeAsync, GrabModeAsync); 121 XGrabKey(GDK_DISPLAY(), key, mask | caps_lock_mask, root, True, 122 GrabModeAsync, GrabModeAsync); 123 XGrabKey(GDK_DISPLAY(), key, mask | num_lock_mask, root, True, 124 GrabModeAsync, GrabModeAsync); 125 XGrabKey(GDK_DISPLAY(), key, mask | caps_lock_mask | num_lock_mask, root, 126 True, GrabModeAsync, GrabModeAsync); 127} 128 129// TODO(davej): Move the ShowBubble() calls in to AudioHandler so that this 130// function returns faster without blocking on GetVolumePercent(), and still 131// guarantees that the volume displayed will be that after the adjustment. 132 133// TODO(davej): The IsMute() check can also be made non-blocking by changing to 134// an AdjustVolumeByPercentOrUnmute() function which can do the steps off of 135// this thread when ShowBubble() is moved in to AudioHandler. 136 137void SystemKeyEventListener::OnVolumeMute() { 138 // Always muting (and not toggling) as per final decision on 139 // http://crosbug.com/3751 140 audio_handler_->SetMute(true); 141 VolumeBubble::GetInstance()->ShowBubble(0); 142 BrightnessBubble::GetInstance()->HideBubble(); 143} 144 145void SystemKeyEventListener::OnVolumeDown() { 146 if (audio_handler_->IsMute()) { 147 VolumeBubble::GetInstance()->ShowBubble(0); 148 } else { 149 audio_handler_->AdjustVolumeByPercent(-kStepPercentage); 150 VolumeBubble::GetInstance()->ShowBubble( 151 audio_handler_->GetVolumePercent()); 152 } 153 BrightnessBubble::GetInstance()->HideBubble(); 154} 155 156void SystemKeyEventListener::OnVolumeUp() { 157 if (audio_handler_->IsMute()) 158 audio_handler_->SetMute(false); 159 else 160 audio_handler_->AdjustVolumeByPercent(kStepPercentage); 161 VolumeBubble::GetInstance()->ShowBubble( 162 audio_handler_->GetVolumePercent()); 163 BrightnessBubble::GetInstance()->HideBubble(); 164} 165 166} // namespace chromeos 167