blob: 5d91ed156b86c189fb0518fbb3fe4bf64c61fd1a [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "rgbkbd/rgb_keyboard_controller_impl.h"
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include "base/check.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "rgbkbd/constants.h"
namespace rgbkbd {
RgbKeyboardControllerImpl::RgbKeyboardControllerImpl(RgbKeyboard* keyboard)
: keyboard_(keyboard), background_color_(kWhiteBackgroundColor) {}
RgbKeyboardControllerImpl::~RgbKeyboardControllerImpl() = default;
uint32_t RgbKeyboardControllerImpl::GetRgbKeyboardCapabilities() {
if (!capabilities_.has_value()) {
capabilities_ = keyboard_->GetRgbKeyboardCapabilities();
}
return static_cast<uint32_t>(capabilities_.value());
}
void RgbKeyboardControllerImpl::SetKeyColor(const KeyColor& key_color) {
keyboard_->SetKeyColor(key_color.key, key_color.color.r, key_color.color.g,
key_color.color.b);
}
void RgbKeyboardControllerImpl::SetAllKeyColors(const Color& color) {
keyboard_->SetAllKeyColors(color.r, color.g, color.b);
}
void RgbKeyboardControllerImpl::SetCapsLockState(bool enabled) {
caps_lock_enabled_ = enabled;
// Per zone keyboards can not independently set left/right shift RGB colors.
// TODO(michaelcheco): Prevent this call from happening for per zone keyboards
// higher up in the stack.
if (IsZonedKeyboard()) {
LOG(ERROR) << "Attempted to set caps lock color for a per zone keyboard";
return;
}
SetKeyColor({kLeftShiftKey, GetCurrentCapsLockColor(kLeftShiftKey)});
SetKeyColor({kRightShiftKey, GetCurrentCapsLockColor(kRightShiftKey)});
}
void RgbKeyboardControllerImpl::SetStaticBackgroundColor(uint8_t r,
uint8_t g,
uint8_t b) {
background_type_ = BackgroundType::kStaticSingleColor;
background_color_ = Color(r, g, b);
SetAllKeyColors(background_color_);
// If Capslock was enabled, re-color the highlight keys.
if (caps_lock_enabled_) {
SetCapsLockState(/*enabled=*/true);
}
}
void RgbKeyboardControllerImpl::SetKeyboardClient(RgbKeyboard* keyboard) {
DCHECK(keyboard);
keyboard_ = keyboard;
}
void RgbKeyboardControllerImpl::SetKeyboardCapabilityForTesting(
RgbKeyboardCapabilities capability) {
capabilities_ = capability;
}
const std::vector<uint32_t>& RgbKeyboardControllerImpl::GetZone(
int zone) const {
DCHECK(capabilities_.has_value());
DCHECK(zone >= 0 && zone < GetZoneCount());
switch (capabilities_.value()) {
case RgbKeyboardCapabilities::kNone:
NOTREACHED();
return kEmptyZone;
case RgbKeyboardCapabilities::kIndividualKey:
return GetIndividualKeyZones()[zone];
case RgbKeyboardCapabilities::kFourZoneFortyLed:
return GetFourtyLedZones()[zone];
case RgbKeyboardCapabilities::kFourZoneTwelveLed:
return GetTwelveLedZones()[zone];
case RgbKeyboardCapabilities::kFourZoneFourLed:
return GetFourLedZones()[zone];
}
}
int RgbKeyboardControllerImpl::GetZoneCount() const {
DCHECK(capabilities_.has_value());
switch (capabilities_.value()) {
case RgbKeyboardCapabilities::kNone:
return 0;
case RgbKeyboardCapabilities::kIndividualKey:
return 5;
case RgbKeyboardCapabilities::kFourZoneFortyLed:
case RgbKeyboardCapabilities::kFourZoneTwelveLed:
case RgbKeyboardCapabilities::kFourZoneFourLed:
return 4;
}
}
Color RgbKeyboardControllerImpl::GetRainbowZoneColor(int zone) const {
DCHECK(capabilities_.has_value());
DCHECK(zone >= 0 && zone < GetZoneCount());
switch (capabilities_.value()) {
case RgbKeyboardCapabilities::kNone:
NOTREACHED();
return kWhiteBackgroundColor;
case RgbKeyboardCapabilities::kIndividualKey:
return kIndividualKeyRainbowColors[zone];
case RgbKeyboardCapabilities::kFourZoneFortyLed:
return kFourZonesRainbowColors[zone];
case RgbKeyboardCapabilities::kFourZoneTwelveLed:
return kFourZonesRainbowColors[zone];
case RgbKeyboardCapabilities::kFourZoneFourLed:
return kFourZonesRainbowColors[zone];
}
}
void RgbKeyboardControllerImpl::SetZoneColor(int zone,
uint8_t r,
uint8_t g,
uint8_t b) {
if (zone < 0 || zone >= GetZoneCount()) {
LOG(ERROR) << "Attempted to set color for invalid zone: " << zone;
return;
}
for (uint32_t led : GetZone(zone)) {
if (capabilities_ == RgbKeyboardCapabilities::kIndividualKey) {
individual_key_background_map_.insert_or_assign(led, Color(r, g, b));
}
// Check if caps lock is enabled to avoid overriding the caps lock
// highlight keys.
if (caps_lock_enabled_ && IsShiftKey(led)) {
continue;
}
keyboard_->SetKeyColor(led, r, g, b);
}
}
void RgbKeyboardControllerImpl::SetStaticZoneColor(int zone,
uint8_t r,
uint8_t g,
uint8_t b) {
background_type_ = BackgroundType::kStaticZones;
zone_colors_.insert_or_assign(zone, Color(r, g, b));
SetZoneColor(zone, r, g, b);
}
void RgbKeyboardControllerImpl::SetRainbowMode() {
DCHECK(capabilities_.has_value());
background_type_ = BackgroundType::kStaticRainbow;
int zone_count = GetZoneCount();
for (int zone = 0; zone < zone_count; ++zone) {
Color color = GetRainbowZoneColor(zone);
SetZoneColor(zone, color.r, color.g, color.b);
}
}
// TODO(jimmyxgong): Implement this stub.
void RgbKeyboardControllerImpl::SetAnimationMode(RgbAnimationMode mode) {
NOTIMPLEMENTED();
}
std::vector<KeyColor> RgbKeyboardControllerImpl::
GetRainbowModeColorsWithShiftKeysHighlightedForTesting() {
DCHECK(capabilities_ == RgbKeyboardCapabilities::kIndividualKey);
std::vector<KeyColor> vec;
vec.emplace_back(kLeftShiftKey, kCapsLockHighlight);
vec.emplace_back(kRightShiftKey, kCapsLockHighlight);
for (const auto& entry : kRainbowModeIndividualKey) {
if (entry.key == kLeftShiftKey || entry.key == kRightShiftKey) {
continue;
}
vec.push_back(entry);
}
return vec;
}
Color RgbKeyboardControllerImpl::GetCurrentCapsLockColor(uint32_t key) const {
if (caps_lock_enabled_) {
return kCapsLockHighlight;
}
if (background_type_ == BackgroundType::kStaticRainbow ||
background_type_ == BackgroundType::kStaticZones) {
return GetBackgroundColorForKey(key);
}
return background_color_;
}
Color RgbKeyboardControllerImpl::GetBackgroundColorForKey(uint32_t key) const {
DCHECK(capabilities_ == RgbKeyboardCapabilities::kIndividualKey);
auto entry = individual_key_background_map_.find(key);
if (entry == individual_key_background_map_.end()) {
LOG(ERROR) << "The background color for key " << key << " wasn't set.";
return kWhiteBackgroundColor;
}
return entry->second;
}
bool RgbKeyboardControllerImpl::IsZonedKeyboard() const {
DCHECK(capabilities_.has_value());
return capabilities_.value() != RgbKeyboardCapabilities::kIndividualKey;
}
void RgbKeyboardControllerImpl::ReinitializeOnDeviceReconnected() {
if (background_type_ != BackgroundType::kNone) {
SetKeyColor({kLeftShiftKey, GetCurrentCapsLockColor(kLeftShiftKey)});
SetKeyColor({kRightShiftKey, GetCurrentCapsLockColor(kRightShiftKey)});
}
switch (background_type_) {
case BackgroundType::kStaticSingleColor:
SetStaticBackgroundColor(background_color_.r, background_color_.g,
background_color_.b);
break;
case BackgroundType::kStaticRainbow:
SetRainbowMode();
break;
case BackgroundType::kStaticZones:
for (auto const& [zone, color] : zone_colors_) {
SetStaticZoneColor(zone, color.r, color.g, color.b);
}
break;
case BackgroundType::kNone:
break;
}
}
void RgbKeyboardControllerImpl::SetKeyboardCapabilityAsIndividualKey() {
capabilities_ = RgbKeyboardCapabilities::kIndividualKey;
}
void RgbKeyboardControllerImpl::OnUsbDeviceAdded(const std::string& sys_path,
uint8_t bus_number,
uint8_t device_address,
uint16_t vendor_id,
uint16_t product_id) {
if (vendor_id == kPrismVendorId && product_id == kPrismProductId) {
LOG(INFO) << "Detected the Prism device reconnecting to the system.";
// Save prism usb sys_path to know when it disconnects.
prism_usb_sys_path_ = sys_path;
keyboard_->InitializeUsbKeyboard();
ReinitializeOnDeviceReconnected();
}
}
// Invoked when a USB device is removed from the system.
void RgbKeyboardControllerImpl::OnUsbDeviceRemoved(
const std::string& sys_path) {
if (sys_path == prism_usb_sys_path_) {
LOG(INFO) << "Detected the Prism device being removed from the system.";
prism_usb_sys_path_.clear();
keyboard_->ResetUsbKeyboard();
}
}
} // namespace rgbkbd