ChatCommands: Add Clipboard Support (#1040)

* Add Chat Input Clipboard Support

Add CTRL+V and CTRL+C support to the in-game chatbox.

Fixes an issue with errors being thrown when shortcuts were used when not currently logged in.

Extracts clipboard logic (a couple places already had a sort of "copy" functionality) to a simple clipboard util.

* Checkstyle fix
This commit is contained in:
James
2019-07-19 01:28:05 -07:00
committed by Kyleeld
parent 24b7aff85a
commit d08d80c468
5 changed files with 118 additions and 14 deletions

View File

@@ -129,4 +129,15 @@ public interface ChatCommandsConfig extends Config
{ {
return true; return true;
} }
@ConfigItem(
position = 5,
keyName = "clipboardShortcuts",
name = "Clipboard shortcuts",
description = "Enable clipboard shortcuts (ctrl+c and ctrl+v)"
)
default boolean clipboardShortcuts()
{
return true;
}
} }

View File

@@ -29,9 +29,11 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.ScriptID; import net.runelite.api.ScriptID;
import net.runelite.api.GameState;
import net.runelite.api.VarClientStr; import net.runelite.api.VarClientStr;
import net.runelite.client.callback.ClientThread; import net.runelite.client.callback.ClientThread;
import net.runelite.client.input.KeyListener; import net.runelite.client.input.KeyListener;
import net.runelite.client.util.Clipboard;
@Singleton @Singleton
class ChatKeyboardListener implements KeyListener class ChatKeyboardListener implements KeyListener
@@ -54,15 +56,45 @@ class ChatKeyboardListener implements KeyListener
@Override @Override
public void keyPressed(KeyEvent e) public void keyPressed(KeyEvent e)
{ {
if (!e.isControlDown() || !chatCommandsConfig.clearShortcuts()) if (!e.isControlDown() || client.getGameState() != GameState.LOGGED_IN)
{ {
return; return;
} }
String input = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT);
switch (e.getKeyCode()) switch (e.getKeyCode())
{ {
case KeyEvent.VK_C:
if (!chatCommandsConfig.clipboardShortcuts())
{
break;
}
Clipboard.store(input);
break;
case KeyEvent.VK_V:
if (!chatCommandsConfig.clipboardShortcuts())
{
break;
}
final String clipboard = Clipboard.retrieve();
if (clipboard != null && !clipboard.isEmpty())
{
final String replacement = input + clipboard;
clientThread.invoke(() -> client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, replacement));
}
break;
case KeyEvent.VK_W: case KeyEvent.VK_W:
String input = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT); if (!chatCommandsConfig.clearShortcuts())
{
break;
}
if (input != null) if (input != null)
{ {
// remove trailing space // remove trailing space
@@ -96,6 +128,12 @@ class ChatKeyboardListener implements KeyListener
client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, ""); client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, "");
client.runScript(ScriptID.CHAT_PROMPT_INIT); client.runScript(ScriptID.CHAT_PROMPT_INIT);
}); });
if (!chatCommandsConfig.clearShortcuts())
{
break;
}
clientThread.invoke(() -> client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, ""));
break; break;
} }
} }

View File

@@ -32,10 +32,7 @@ import com.google.inject.Provides;
import java.awt.Desktop; import java.awt.Desktop;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Image; import java.awt.Image;
import java.awt.Toolkit;
import java.awt.TrayIcon; import java.awt.TrayIcon;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -103,6 +100,7 @@ import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.DrawManager; import net.runelite.client.ui.DrawManager;
import net.runelite.client.ui.NavigationButton; import net.runelite.client.ui.NavigationButton;
import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.Clipboard;
import net.runelite.client.util.HotkeyListener; import net.runelite.client.util.HotkeyListener;
import net.runelite.client.util.ImageUtil; import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.Text; import net.runelite.client.util.Text;
@@ -247,7 +245,7 @@ public class ScreenshotPlugin extends Plugin
{ {
updateConfig(); updateConfig();
addSubscriptions(); addSubscriptions();
overlayManager.add(screenshotOverlay); overlayManager.add(screenshotOverlay);
SCREENSHOT_DIR.mkdirs(); SCREENSHOT_DIR.mkdirs();
keyManager.registerKeyListener(hotkeyListener); keyManager.registerKeyListener(hotkeyListener);
@@ -855,9 +853,7 @@ public class ScreenshotPlugin extends Plugin
{ {
String link = imageUploadResponse.getData().getLink(); String link = imageUploadResponse.getData().getLink();
StringSelection selection = new StringSelection(link); Clipboard.store(link);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(selection, selection);
if (notifyWhenTaken) if (notifyWhenTaken)
{ {
@@ -915,7 +911,7 @@ public class ScreenshotPlugin extends Plugin
updateConfig(); updateConfig();
} }
private void updateConfig() private void updateConfig()
{ {
this.includeFrame = config.includeFrame(); this.includeFrame = config.includeFrame();

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2018, Connor <contact@connor-parks.email>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.util;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.IOException;
public class Clipboard
{
public static String retrieve()
{
Transferable contents = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
if (contents == null || ! contents.isDataFlavorSupported(DataFlavor.stringFlavor))
{
return null;
}
try
{
return (String) contents.getTransferData(DataFlavor.stringFlavor);
}
catch (UnsupportedFlavorException | IOException ex)
{
return null;
}
}
public static void store(String contents)
{
final StringSelection selection = new StringSelection(contents);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, null);
}
}

View File

@@ -26,8 +26,6 @@ package net.runelite.client.util;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import java.awt.Desktop; import java.awt.Desktop;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
@@ -144,8 +142,7 @@ public class LinkBrowser
if (result == JOptionPane.OK_OPTION) if (result == JOptionPane.OK_OPTION)
{ {
final StringSelection stringSelection = new StringSelection(data); Clipboard.store(data);
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
} }
}); });
} }