chromium/ui/events/test/keyboard_layout_mac.cc

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/events/test/keyboard_layout.h"

#include "base/check_op.h"
#include "base/strings/sys_string_conversions.h"

namespace ui {

PlatformKeyboardLayout GetPlatformKeyboardLayout(KeyboardLayout layout) {
  // Right now tests only need US English.  If other layouts need to be
  // supported in the future this code should be extended.
  DCHECK_EQ(KEYBOARD_LAYOUT_ENGLISH_US, layout);

  const char kUsInputSourceId[] = "com.apple.keylayout.US";

  base::apple::ScopedCFTypeRef<CFMutableDictionaryRef> input_source_list_filter(
      CFDictionaryCreateMutable(kCFAllocatorDefault, 1,
                                &kCFTypeDictionaryKeyCallBacks,
                                &kCFTypeDictionaryValueCallBacks));
  base::apple::ScopedCFTypeRef<CFStringRef> input_source_id_ref =
      base::SysUTF8ToCFStringRef(kUsInputSourceId);
  CFDictionaryAddValue(input_source_list_filter.get(),
                       kTISPropertyInputSourceID, input_source_id_ref.get());
  base::apple::ScopedCFTypeRef<CFArrayRef> input_source_list(
      TISCreateInputSourceList(input_source_list_filter.get(), true));
  if (CFArrayGetCount(input_source_list.get()) != 1) {
    return PlatformKeyboardLayout();
  }

  return base::apple::ScopedCFTypeRef<TISInputSourceRef>(
      (TISInputSourceRef)CFArrayGetValueAtIndex(input_source_list.get(), 0),
      base::scoped_policy::RETAIN);
}

PlatformKeyboardLayout ScopedKeyboardLayout::GetActiveLayout() {
  return PlatformKeyboardLayout(TISCopyCurrentKeyboardInputSource());
}

void ScopedKeyboardLayout::ActivateLayout(PlatformKeyboardLayout layout) {
  DCHECK(layout);
  // According to the documentation in HIToolbox's TextInputSources.h
  // (recommended reading), TISSelectInputSource() can fail if the input source
  // isn't "selectable" or "enabled".
  //
  // On the bots, for some reason, sometimes the US keyboard layout isn't
  // "enabled" even though it is present - we aren't sure why this happens,
  // perhaps if input sources have never been switched on this bot before? In
  // any case, it's harmless to re-enable it here if it's already enabled.
  OSStatus result = TISEnableInputSource(layout.get());
  DCHECK_EQ(noErr, result);
  result = TISSelectInputSource(layout.get());
  DCHECK_EQ(noErr, result);
}

}  // namespace ui