/*
* KeyboardHelper.java
*
* Copyright (C) 2009-15 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.core.client.command;
import org.rstudio.core.client.BrowseCap;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.KeyCodes;
public class KeyboardHelper
{
public static boolean isHyphen(NativeEvent event)
{
if (KeyboardShortcut.getModifierValue(event) != KeyboardShortcut.NONE)
return false;
return isHyphenKeycode(event.getKeyCode());
}
public static boolean isHyphenKeycode(NativeEvent event)
{
return isHyphenKeycode(event.getKeyCode());
}
public static boolean isHyphenKeycode(int keyCode)
{
if (BrowseCap.isFirefox())
return keyCode == 173;
else
return keyCode == 189;
}
public static boolean isUnderscore(NativeEvent event)
{
return event.getShiftKey() && isHyphenKeycode(event.getKeyCode());
}
public static boolean isPeriod(NativeEvent event)
{
return !event.getShiftKey() && isPeriodKeycode(event.getKeyCode());
}
public static boolean isPeriodKeycode(int keyCode)
{
return keyCode == 190;
}
public static boolean isModifierKey(int keyCode)
{
switch (keyCode)
{
case KeyCodes.KEY_CTRL:
case KeyCodes.KEY_ALT:
case KeyCodes.KEY_SHIFT:
case KeyCodes.KEY_WIN_IME:
case KeyCodes.KEY_WIN_KEY:
case KeyCodes.KEY_WIN_KEY_FF_LINUX:
case KeyCodes.KEY_WIN_KEY_RIGHT:
case KeyCodes.KEY_WIN_KEY_LEFT_META:
return true;
case KeyCodes.KEY_CONTEXT_MENU: // right meta on macOS
return !BrowseCap.isWindows();
default:
return false;
}
}
public static String keyNameFromKeyCode(int keyCode)
{
return keyNameFromKeyCode(keyCode, KEY_CODE_TO_KEY_NAME_MAP);
}
private static final native String keyNameFromKeyCode(int keyCode, JavaScriptObject map)
/*-{
return map[keyCode] || String.fromCharCode(keyCode);
}-*/;
public static int keyCodeFromKeyName(String keyName)
{
return keyCodeFromKeyName(keyName, KEY_NAME_TO_KEY_CODE_MAP);
}
private static final native int keyCodeFromKeyName(String keyName, JavaScriptObject map)
/*-{
return map[keyName.toLowerCase()] || -1;
}-*/;
private static final native JavaScriptObject makeKeyCodeToKeyNameMap()
/*-{
// Map array indices as key codes to corresponding name.
var map = new Array(256);
map[8] = "Backspace";
map[9] = "Tab";
map[12] = "NumLock";
map[13] = "Enter";
map[16] = "Shift";
map[17] = "Ctrl";
map[18] = "Alt";
map[19] = "Pause";
map[20] = "CapsLock";
map[27] = "Escape";
map[32] = "Space";
map[33] = "PageUp";
map[34] = "PageDown";
map[35] = "End";
map[36] = "Home";
map[37] = "Left";
map[38] = "Up";
map[39] = "Right";
map[40] = "Down";
map[45] = "Insert";
map[46] = "Delete";
// Add in numbers 0-9
for (var i = 48; i <= 57; i++)
map[i] = "" + (i - 48);
// Add in letters
for (var i = 65; i <= 90; i++)
map[i] = String.fromCharCode(i);
// TODO: Treat these keys differently?
map[91] = "Meta";
map[92] = "Meta";
map[93] = "Meta";
for (var i = 96; i <= 105; i++)
map[i] = "NumPad" + (i - 96);
map[106] = "*";
map[107] = "+";
map[109] = "-";
// NOTE: This is actually 'decimal point' which is
// distinct as a keycode from '.', but probably easier
// to just treat them the same.
map[110] = "."
map[111] = "/";
// Function keys
for (var i = 112; i <= 123; i++)
map[i] = "F" + (i - 111);
map[144] = "NumLock";
map[145] = "ScrollLock";
map[186] = ";";
map[187] = "=";
map[188] = ",";
map[189] = "-";
map[190] = ".";
map[191] = "/";
map[192] = "`";
map[219] = "[";
map[220] = "\\";
map[221] = "]";
map[222] = "'";
return map;
}-*/;
private static final native JavaScriptObject makeKeyNameToKeyCodeMap(JavaScriptObject map)
/*-{
var result = {};
for (var key in map) {
var value = map[key];
result[value.toLowerCase()] = parseInt(key);
}
return result;
}-*/;
private static final JavaScriptObject KEY_CODE_TO_KEY_NAME_MAP =
makeKeyCodeToKeyNameMap();
private static final JavaScriptObject KEY_NAME_TO_KEY_CODE_MAP =
makeKeyNameToKeyCodeMap(KEY_CODE_TO_KEY_NAME_MAP);
public static final int KEY_HYPHEN = BrowseCap.isFirefox() ? 173 : 189;
}