Directly using VirtualBox from Java #5
7 changed files with 270 additions and 63 deletions
|
@ -70,7 +70,7 @@
|
|||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.9.2-R0.1-SNAPSHOT</version>
|
||||
<version>1.12-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
|
@ -89,10 +89,6 @@
|
|||
<artifactId>gson</artifactId>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>ebean</artifactId>
|
||||
<groupId>org.avaje</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>snakeyaml</artifactId>
|
||||
<groupId>org.yaml</groupId>
|
||||
|
@ -109,6 +105,12 @@
|
|||
<version>3.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>craftbukkit</artifactId>
|
||||
<version>1.12-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
|
|
|
@ -1,18 +1,38 @@
|
|||
package sznp.virtualcomputer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.map.MapCanvas;
|
||||
import org.bukkit.map.MapRenderer;
|
||||
import org.bukkit.map.MapView;
|
||||
|
||||
public class BukkitRenderer extends MapRenderer implements IRenderer {
|
||||
private byte[] allpixels;
|
||||
private BufferedImage image;
|
||||
private int startindex;
|
||||
|
||||
public BukkitRenderer(BufferedImage image) {
|
||||
this.image = image;
|
||||
/**
|
||||
* Generic implementation, should work on most versions
|
||||
*
|
||||
* @param id
|
||||
* The ID of the current map
|
||||
* @param world
|
||||
* The world to create new maps in
|
||||
* @param allpixels
|
||||
* The raw pixel data from the machine in BGRA format
|
||||
* @param startindex
|
||||
* The index to start from in allpixels
|
||||
*/
|
||||
public BukkitRenderer(short id, World world, byte[] allpixels, int startindex) {
|
||||
MapView map = IRenderer.prepare(id, world);
|
||||
map.addRenderer(this);
|
||||
this.allpixels = allpixels;
|
||||
this.startindex = startindex;
|
||||
image = new BufferedImage(640, 480, BufferedImage.TYPE_INT_RGB);
|
||||
}
|
||||
|
||||
private int progress = 0;
|
||||
|
@ -22,6 +42,19 @@ public class BukkitRenderer extends MapRenderer implements IRenderer {
|
|||
public void render(MapView view, MapCanvas canvas, Player player) {
|
||||
long time = System.nanoTime();
|
||||
|
||||
final int[] a = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); // Directly update the bytes of the image
|
||||
|
||||
// (byte) bgra to rgb (int)
|
||||
for (int i = startindex, j = 0; i < startindex + 128 * 128; i = i + 4, j++) {
|
||||
int b, g, r;
|
||||
|
||||
b = allpixels[i] & 0xFF;
|
||||
g = allpixels[i + 1] & 0xFF;
|
||||
r = allpixels[i + 2] & 0xFF;
|
||||
|
||||
a[j] = (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
try {
|
||||
canvas.drawImage(0, progress * updatepixels, image.getSubimage(0, progress * updatepixels, 128,
|
||||
(progress * updatepixels + updatepixels >= 128 ? 128 - progress * updatepixels : updatepixels)));
|
||||
|
|
|
@ -62,7 +62,7 @@ public class Commands implements CommandExecutor
|
|||
case "key":
|
||||
if (args.length < 2)
|
||||
{
|
||||
sender.sendMessage("§cUsage: /computer key <key> [down/up|interval]");
|
||||
sender.sendMessage("§cUsage: /computer key <key> [down/up|duration(ticks)]");
|
||||
return true;
|
||||
}
|
||||
if (args.length < 3)
|
||||
|
@ -187,8 +187,7 @@ public class Commands implements CommandExecutor
|
|||
}
|
||||
MouseLockerPlayerListener.LockedSpeed = Float
|
||||
.parseFloat(args[2]);
|
||||
sender.sendMessage("§aMouse speed set to "
|
||||
+ MouseLockerPlayerListener.LockedSpeed);
|
||||
sender.sendMessage("§aMouse speed set to " + MouseLockerPlayerListener.LockedSpeed);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,9 @@ public class DirectRenderer implements IRenderer {
|
|||
* @throws Exception
|
||||
* Usually happens on incompatibility
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public DirectRenderer(short id, World world, byte[] allpixels, int startindex)
|
||||
throws Exception, Exception, Exception, Exception {
|
||||
map = Bukkit.getMap(id);
|
||||
if (map == null)
|
||||
map = Bukkit.createMap(world);
|
||||
map.getRenderers().clear();
|
||||
map = IRenderer.prepare(id, world);
|
||||
final Field field = map.getClass().getDeclaredField("renderCache");
|
||||
field.setAccessible(true);
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
package sznp.virtualcomputer;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.map.MapView;
|
||||
|
||||
public interface IRenderer {
|
||||
static MapView prepare(short id, World world) {
|
||||
@SuppressWarnings("deprecation")
|
||||
MapView map = Bukkit.getMap(id);
|
||||
if (map == null)
|
||||
map = Bukkit.createMap(world);
|
||||
map.getRenderers().clear();
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package sznp.virtualcomputer;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferInt;
|
||||
import java.util.HashMap;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.countercraft.movecraft.craft.Craft;
|
||||
import net.countercraft.movecraft.craft.CraftManager;
|
||||
|
@ -12,21 +12,18 @@ import org.bukkit.Material;
|
|||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
import org.virtualbox_5_1.IFramebuffer;
|
||||
import org.virtualbox_5_1.ISession;
|
||||
import org.virtualbox_5_1.IVirtualBox;
|
||||
import org.virtualbox_5_1.VirtualBoxManager;
|
||||
import org.virtualbox_5_1.*;
|
||||
|
||||
import com.mcplugindev.slipswhitley.sketchmap.map.RelativeLocation;
|
||||
import com.mcplugindev.slipswhitley.sketchmap.map.SketchMap;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
public class PluginMain extends JavaPlugin {
|
||||
private IVirtualBox vbox;
|
||||
private ISession session;
|
||||
private SketchMap smap;
|
||||
private ArrayList<IRenderer> renderers = new ArrayList<>();
|
||||
private IMachine machine;
|
||||
|
||||
public static PluginMain Instance;
|
||||
public static byte[] allpixels = new byte[640 * 480];
|
||||
|
||||
// Fired when plugin is first enabled
|
||||
@Override
|
||||
|
@ -36,21 +33,27 @@ public class PluginMain extends JavaPlugin {
|
|||
ConsoleCommandSender ccs = getServer().getConsoleSender();
|
||||
this.getCommand("computer").setExecutor(new Commands());
|
||||
ccs.sendMessage("§bInitializing VirtualBox...");
|
||||
final String vbpath = System.getProperty("os.name").toLowerCase().contains("mac")
|
||||
? "/Applications/VirtualBox.app/Contents/MacOS" : "/opt/virtualbox";
|
||||
if (System.getProperty("vbox.home") == null || System.getProperty("vbox.home").isEmpty())
|
||||
System.setProperty("vbox.home", "/opt/virtualbox");
|
||||
System.setProperty("vbox.home", vbpath);
|
||||
if (System.getProperty("sun.boot.library.path") == null
|
||||
|| System.getProperty("sun.boot.library.path").isEmpty())
|
||||
System.setProperty("sun.boot.library.path", vbpath);
|
||||
addLibraryPath(vbpath);
|
||||
final VirtualBoxManager manager = VirtualBoxManager.createInstance(getDataFolder().getAbsolutePath());
|
||||
vbox = manager.getVBox();
|
||||
session = manager.getSessionObject();
|
||||
ccs.sendMessage("§bStarting VM for testing...");
|
||||
vbox.getMachines().get(0).launchVMProcess(session, "headless", "").waitForCompletion(2000);
|
||||
session.getConsole().getDisplay().attachFramebuffer(0L, new IFramebuffer(new MCFrameBuffer()));
|
||||
ccs.sendMessage("§bLoading SketchMap...");
|
||||
img = new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB);
|
||||
HashMap<Short, RelativeLocation> map = new HashMap<>();
|
||||
for (int i = 0; i < 5; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
map.put((short) (i * 4 + j), new RelativeLocation(i, j));
|
||||
smap = new SketchMap(img, "Screen", 5, 4, false, map);
|
||||
ccs.sendMessage("§bLoading Screen...");
|
||||
try {
|
||||
for (short i = 0; i < 20; i++)
|
||||
renderers.add(new DirectRenderer(i, Bukkit.getWorlds().get(0), allpixels, i * 128 * 128 * 4)); // TODO: The pixels are selected in a horribly wrong way probably
|
||||
ccs.sendMessage("§bUsing Direct Renderer");
|
||||
} catch (NoClassDefFoundError e) {
|
||||
for (short i = 0; i < 20; i++)
|
||||
renderers.add(new BukkitRenderer(i, Bukkit.getWorlds().get(0), allpixels, i * 128 * 128 * 4));
|
||||
ccs.sendMessage("§6Compability error, using slower renderer");
|
||||
}
|
||||
ccs.sendMessage("§bLoaded!");
|
||||
getServer().getPluginManager().registerEvents(new MouseLockerPlayerListener(), this);
|
||||
DoStart();
|
||||
|
@ -67,12 +70,12 @@ public class PluginMain extends JavaPlugin {
|
|||
saveConfig();
|
||||
}
|
||||
|
||||
private volatile BufferedImage img;
|
||||
private volatile BukkitTask task = null;
|
||||
|
||||
public void Start(CommandSender sender) {
|
||||
sender.sendMessage("§eStarting computer...");
|
||||
// computer.Start();
|
||||
if (machine == null)
|
||||
machine = vbox.getMachines().get(0);
|
||||
machine.launchVMProcess(session, "headless", "").waitForCompletion(10000);
|
||||
session.getConsole().getDisplay().attachFramebuffer(0L, new IFramebuffer(new MCFrameBuffer()));
|
||||
sender.sendMessage("§eComputer started.");
|
||||
DoStart();
|
||||
}
|
||||
|
@ -80,14 +83,6 @@ public class PluginMain extends JavaPlugin {
|
|||
public static int MouseSpeed = 1;
|
||||
|
||||
private void DoStart() {
|
||||
if (task == null)
|
||||
task = this.getServer().getScheduler().runTaskTimerAsynchronously(this, new Runnable() {
|
||||
public void run() {
|
||||
final int[] a = ((DataBufferInt) smap.image.getRaster().getDataBuffer()).getData();
|
||||
// final int[] data = computer.GetScreenPixelColors();
|
||||
// System.arraycopy(data, 0, a, 0, data.length);
|
||||
}
|
||||
}, 1, 10);
|
||||
if (getServer().getPluginManager().isPluginEnabled("Movecraft")) {
|
||||
this.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
|
||||
public void run() {
|
||||
|
@ -113,50 +108,106 @@ public class PluginMain extends JavaPlugin {
|
|||
|
||||
public void Stop(CommandSender sender) {
|
||||
sender.sendMessage("§eStopping computer...");
|
||||
// computer.PowerOff();
|
||||
session.getConsole().powerDown().waitForCompletion(2000);
|
||||
sender.sendMessage("§eComputer stopped.");
|
||||
}
|
||||
|
||||
public void PowerButton(CommandSender sender) {
|
||||
sender.sendMessage("§eStarting/stoppping computer...");
|
||||
sender.sendMessage("§ePressing powerbutton...");
|
||||
final CommandSender s = sender;
|
||||
getServer().getScheduler().runTaskAsynchronously(this, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
/*
|
||||
* if (computer.PowerButton()) { DoStart(); s.sendMessage("§eComputer started."); } else s.sendMessage("§ePowerbutton pressed.");
|
||||
*/
|
||||
if (session.getState() != SessionState.Locked || session.getMachine() == null) {
|
||||
Start(sender);
|
||||
} else {
|
||||
session.getConsole().powerButton();
|
||||
s.sendMessage("§ePowerbutton pressed.");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Reset(CommandSender sender) {
|
||||
sender.sendMessage("§eResetting computer...");
|
||||
// computer.Reset();
|
||||
if (session.getState() == SessionState.Locked)
|
||||
session.getConsole().powerDown().waitForCompletion(10000);
|
||||
sender.sendMessage("§eComputer reset.");
|
||||
}
|
||||
|
||||
public void FixScreen(CommandSender sender) {
|
||||
sender.sendMessage("§eFixing screen...");
|
||||
// computer.FixScreen();
|
||||
session.getConsole().getDisplay().setSeamlessMode(false);
|
||||
session.getConsole().getDisplay().setVideoModeHint(0L, true, false, 0, 0, 640L, 480L, 32L);
|
||||
sender.sendMessage("§eScreen fixed.");
|
||||
}
|
||||
|
||||
public void PressKey(CommandSender sender, String key, String stateorduration) {
|
||||
/*
|
||||
* if (stateorduration.length() == 0) computer.PressKey(key, (short) 0); else if (stateorduration.equalsIgnoreCase("down")) computer.PressKey(key, (short) -1); else if
|
||||
* (stateorduration.equalsIgnoreCase("up")) computer.PressKey(key, (short) -2); else computer.PressKey(key, Short.parseShort(stateorduration));
|
||||
*/
|
||||
if (session.getState() == SessionState.Locked) {
|
||||
int durationorstate;
|
||||
if (stateorduration.length() == 0)
|
||||
durationorstate = 0;
|
||||
else if (stateorduration.equalsIgnoreCase("down"))
|
||||
durationorstate = -1;
|
||||
else if (stateorduration.equalsIgnoreCase("up"))
|
||||
durationorstate = -2;
|
||||
else
|
||||
durationorstate = Short.parseShort(stateorduration);
|
||||
int code = 0;
|
||||
// Release key scan code concept taken from VirtualBox source code (KeyboardImpl.cpp:putCAD())
|
||||
// +128
|
||||
if (durationorstate != 2)
|
||||
session.getConsole().getKeyboard().putScancode(code);
|
||||
Runnable sendrelease = () -> session.getConsole().getKeyboard()
|
||||
.putScancodes(Lists.newArrayList(code + 128, Scancode.sc_controlLeft.Code + 128,
|
||||
Scancode.sc_shiftLeft.Code + 128, Scancode.sc_altLeft.Code + 128));
|
||||
if (durationorstate == 0 || durationorstate == -2)
|
||||
sendrelease.run();
|
||||
if (durationorstate > 0) {
|
||||
Bukkit.getScheduler().runTaskLaterAsynchronously(this, sendrelease, durationorstate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs, boolean down) {
|
||||
/*
|
||||
* if (down) computer.UpdateMouse(x, y, z, w, mbs); else computer.UpdateMouse(x, y, z, w, "");
|
||||
*/
|
||||
if (session.getState() != SessionState.Locked)
|
||||
return;
|
||||
int state = 0;
|
||||
if (mbs.length() > 0 && down)
|
||||
state = Arrays.stream(MouseButtonState.values()).filter(mousebs -> mousebs.name().equalsIgnoreCase(mbs))
|
||||
.findAny().orElseThrow(() -> new RuntimeException("Unknown mouse button")).value();
|
||||
session.getConsole().getMouse().putMouseEvent(x, y, z, w, state);
|
||||
}
|
||||
|
||||
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs) {
|
||||
UpdateMouse(sender, x, y, z, w, mbs, true);
|
||||
UpdateMouse(sender, x, y, z, w, mbs, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified path to the java library path
|
||||
*
|
||||
* @param pathToAdd
|
||||
* the path to add
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void addLibraryPath(String pathToAdd) throws Exception {
|
||||
final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
|
||||
usrPathsField.setAccessible(true);
|
||||
|
||||
// get array of paths
|
||||
final String[] paths = (String[]) usrPathsField.get(null);
|
||||
|
||||
// check if the path to add is already present
|
||||
for (String path : paths) {
|
||||
if (path.equals(pathToAdd)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// add the new path
|
||||
final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
|
||||
newPaths[newPaths.length - 1] = pathToAdd;
|
||||
usrPathsField.set(null, newPaths);
|
||||
}
|
||||
}
|
||||
|
|
114
VirtualComputer/src/sznp/virtualcomputer/Scancode.java
Normal file
114
VirtualComputer/src/sznp/virtualcomputer/Scancode.java
Normal file
|
@ -0,0 +1,114 @@
|
|||
package sznp.virtualcomputer;
|
||||
|
||||
/*
|
||||
The scancode values come from:
|
||||
- http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc (March 16), 2000).
|
||||
- http://www.computer-engineering.org/ps2keyboard/scancodes1.html
|
||||
- using MapVirtualKeyEx( VK_*), MAPVK_VK_TO_VSC_EX), 0 ) with the english us keyboard layout
|
||||
- reading win32 WM_INPUT keyboard messages.
|
||||
*/
|
||||
|
||||
enum Scancode { // https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names
|
||||
|
||||
sc_escape(0x01), sc_1(0x02), sc_2(0x03), sc_3(0x04), sc_4(0x05), sc_5(0x06), sc_6(0x07), sc_7(0x08), sc_8(
|
||||
0x09), sc_9(0x0A), sc_0(0x0B), sc_minus(0x0C), sc_equals(0x0D), sc_backspace(0x0E), sc_tab(0x0F), sc_q(
|
||||
0x10), sc_w(0x11), sc_e(0x12), sc_r(0x13), sc_t(0x14), sc_y(0x15), sc_u(0x16), sc_i(0x17), sc_o(
|
||||
0x18), sc_p(0x19), sc_bracketLeft(0x1A), sc_bracketRight(0x1B), sc_enter(
|
||||
0x1C), sc_controlLeft(0x1D), sc_a(0x1E), sc_s(0x1F), sc_d(
|
||||
0x20), sc_f(0x21), sc_g(0x22), sc_h(0x23), sc_j(0x24), sc_k(0x25), sc_l(
|
||||
0x26), sc_semicolon(0x27), sc_apostrophe(0x28), sc_grave(
|
||||
0x29), sc_shiftLeft(0x2A), sc_backslash(0x2B), sc_z(
|
||||
0x2C), sc_x(0x2D), sc_c(0x2E), sc_v(0x2F), sc_b(
|
||||
0x30), sc_n(0x31), sc_m(0x32), sc_comma(
|
||||
0x33), sc_preiod(0x34), sc_slash(
|
||||
0x35), sc_shiftRight(
|
||||
0x36), sc_numpad_multiply(
|
||||
0x37), sc_altLeft(
|
||||
0x38), sc_space(
|
||||
0x39), sc_capsLock(
|
||||
0x3A), sc_f1(
|
||||
0x3B), sc_f2(
|
||||
0x3C), sc_f3(
|
||||
0x3D), sc_f4(
|
||||
0x3E), sc_f5(
|
||||
0x3F), sc_f6(
|
||||
0x40), sc_f7(
|
||||
0x41), sc_f8(
|
||||
0x42), sc_f9(
|
||||
0x43), sc_f10(
|
||||
0x44), sc_numLock(
|
||||
0x45), sc_scrollLock(
|
||||
0x46), sc_numpad_7(
|
||||
0x47), sc_numpad_8(
|
||||
0x48), sc_numpad_9(
|
||||
0x49), sc_numpad_minus(
|
||||
0x4A), sc_numpad_4(
|
||||
0x4B), sc_numpad_5(
|
||||
0x4C), sc_numpad_6(
|
||||
0x4D), sc_numpad_plus(
|
||||
0x4E), sc_numpad_1(
|
||||
0x4F), sc_numpad_2(
|
||||
0x50), sc_numpad_3(
|
||||
0x51), sc_numpad_0(
|
||||
0x52), sc_numpad_period(
|
||||
0x53), sc_alt_printScreen(
|
||||
0x54), /*
|
||||
* Alt
|
||||
* +
|
||||
* print
|
||||
* screen.
|
||||
* MapVirtualKeyEx(
|
||||
* VK_SNAPSHOT
|
||||
* )
|
||||
* ,
|
||||
* MAPVK_VK_TO_VSC_EX
|
||||
* )
|
||||
* ,
|
||||
* 0
|
||||
* )
|
||||
* returns
|
||||
* scancode
|
||||
* 0x54.
|
||||
*/
|
||||
sc_bracketAngle(0x56), /* Key between the left shift and Z. */
|
||||
sc_f11(0x57), sc_f12(0x58), sc_oem_1(0x5a), /* VK_OEM_WSCTRL */
|
||||
sc_oem_2(0x5b), /* VK_OEM_FINISH */
|
||||
sc_oem_3(0x5c), /* VK_OEM_JUMP */
|
||||
sc_eraseEOF(0x5d), sc_oem_4(0x5e), /* VK_OEM_BACKTAB */
|
||||
sc_oem_5(0x5f), /* VK_OEM_AUTO */
|
||||
sc_zoom(0x62), sc_help(0x63), sc_f13(0x64), sc_f14(0x65), sc_f15(0x66), sc_f16(0x67), sc_f17(0x68), sc_f18(
|
||||
0x69), sc_f19(
|
||||
0x6a), sc_f20(0x6b), sc_f21(0x6c), sc_f22(0x6d), sc_f23(0x6e), sc_oem_6(0x6f), /* VK_OEM_PA3 */
|
||||
sc_katakana(0x70), sc_oem_7(0x71), /* VK_OEM_RESET */
|
||||
sc_f24(0x76), sc_sbcschar(0x77), sc_convert(0x79), sc_nonconvert(0x7B), /* VK_OEM_PA1 */
|
||||
|
||||
sc_media_previous(0xE010), sc_media_next(0xE019), sc_numpad_enter(0xE01C), sc_controlRight(0xE01D), sc_volume_mute(
|
||||
0xE020), sc_launch_app2(0xE021), sc_media_play(0xE022), sc_media_stop(
|
||||
0xE024), sc_volume_down(0xE02E), sc_volume_up(
|
||||
0xE030), sc_browser_home(0xE032), sc_numpad_divide(0xE035), sc_printScreen(0xE037),
|
||||
/*
|
||||
* sc_printScreen: - make: 0xE02A 0xE037 - break: 0xE0B7 0xE0AA - MapVirtualKeyEx( VK_SNAPSHOT), MAPVK_VK_TO_VSC_EX), 0 ) returns scancode 0x54; - There is no VK_KEYDOWN with VK_SNAPSHOT.
|
||||
*/
|
||||
sc_altRight(0xE038), sc_cancel(0xE046), /* CTRL + Pause */
|
||||
sc_home(0xE047), sc_arrowUp(0xE048), sc_pageUp(0xE049), sc_arrowLeft(0xE04B), sc_arrowRight(0xE04D), sc_end(
|
||||
0xE04F), sc_arrowDown(0xE050), sc_pageDown(0xE051), sc_insert(0xE052), sc_delete(0xE053), sc_metaLeft(
|
||||
0xE05B), sc_metaRight(0xE05C), sc_application(0xE05D), sc_power(0xE05E), sc_sleep(0xE05F), sc_wake(
|
||||
0xE063), sc_browser_search(0xE065), sc_browser_favorites(0xE066), sc_browser_refresh(
|
||||
0xE067), sc_browser_stop(0xE068), sc_browser_forward(0xE069), sc_browser_back(
|
||||
0xE06A), sc_launch_app1(
|
||||
0xE06B), sc_launch_email(0xE06C), sc_launch_media(0xE06D),
|
||||
|
||||
sc_pause(0xE11D45);
|
||||
/*
|
||||
* sc_pause: - make: 0xE11D 45 0xE19D C5 - make in raw input: 0xE11D 0x45 - break: none - No repeat when you hold the key down - There are no break so I don't know how the key down/up is expected
|
||||
* to work. Raw input sends "keydown" and "keyup" messages), and it appears that the keyup message is sent directly after the keydown message (you can't hold the key down) so depending on when
|
||||
* GetMessage or PeekMessage will return messages), you may get both a keydown and keyup message "at the same time". If you use VK messages most of the time you only get keydown messages), but
|
||||
* some times you get keyup messages too. - when pressed at the same time as one or both control keys, generates a 0xE046 (sc_cancel) and the string for that scancode is "break".
|
||||
*/
|
||||
|
||||
public int Code;
|
||||
|
||||
Scancode(int code) {
|
||||
Code = code;
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue