Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/kmcaster.git
.idea/workspace.xml
<component name="ChangeListManager">
<list default="true" id="be1819c5-28d3-4984-9634-0b266734e13c" name="Default Changelist" comment="">
- <change afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/ImageComponent.java" afterDir="false" />
- <change afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/KeyState.java" afterDir="false" />
+ <change afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/HardwareSwitches.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
- <change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/AppImage.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/AppImage.java" afterDir="false" />
+ <change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/AppImage.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/SvgRasterizer.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/EventFrame.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/EventFrame.java" afterDir="false" />
+ <change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/ImageComponent.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/ImageComponent.java" afterDir="false" />
+ <change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/KeyState.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/HardwareState.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/KmCaster.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/KmCaster.java" afterDir="false" />
- <change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/listeners/Key.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/listeners/Key.java" afterDir="false" />
+ <change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/listeners/Key.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/SwitchName.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/listeners/KeyboardListener.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/listeners/KeyboardListener.java" afterDir="false" />
+ <change beforePath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/listeners/KeyboardModifier.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/com/whitemagicsoftware/kmcaster/listeners/KeyboardModifier.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
</state>
<state x="707" y="657" width="431" height="302" key="#com.intellij.refactoring.move.moveInner.MoveInnerDialog/0.28.2560.1529@0.28.2560.1529" timestamp="1594958994663" />
- <state x="567" y="28" width="711" height="1526" key="#com.intellij.refactoring.rename.AutomaticRenamingDialog" timestamp="1594954562308">
+ <state x="567" y="28" width="711" height="1526" key="#com.intellij.refactoring.rename.AutomaticRenamingDialog" timestamp="1594967090738">
<screen x="0" y="28" width="2560" height="1529" />
</state>
- <state x="567" y="28" width="711" height="1526" key="#com.intellij.refactoring.rename.AutomaticRenamingDialog/0.28.2560.1529@0.28.2560.1529" timestamp="1594954562308" />
+ <state x="567" y="28" width="711" height="1526" key="#com.intellij.refactoring.rename.AutomaticRenamingDialog/0.28.2560.1529@0.28.2560.1529" timestamp="1594967090738" />
<state x="659" y="559" width="526" height="497" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog" timestamp="1594880960290">
<screen x="0" y="28" width="2560" height="1529" />
</state>
<state x="659" y="559" width="526" height="497" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog/0.28.2560.1529@0.28.2560.1529" timestamp="1594880960290" />
<state x="710" y="704" width="425" height="207" key="DetectedRootsChooserDialog" timestamp="1594872764235">
<screen x="0" y="28" width="2560" height="1529" />
</state>
<state x="710" y="704" width="425" height="207" key="DetectedRootsChooserDialog/0.28.2560.1529@0.28.2560.1529" timestamp="1594872764235" />
- <state width="1479" height="330" key="GridCell.Tab.0.bottom" timestamp="1594963811114">
+ <state width="1479" height="330" key="GridCell.Tab.0.bottom" timestamp="1594967617575">
<screen x="0" y="28" width="2560" height="1529" />
</state>
- <state width="1479" height="330" key="GridCell.Tab.0.bottom/0.28.2560.1529@0.28.2560.1529" timestamp="1594963811114" />
- <state width="1479" height="330" key="GridCell.Tab.0.center" timestamp="1594963811113">
+ <state width="1479" height="330" key="GridCell.Tab.0.bottom/0.28.2560.1529@0.28.2560.1529" timestamp="1594967617575" />
+ <state width="1479" height="330" key="GridCell.Tab.0.center" timestamp="1594967617574">
<screen x="0" y="28" width="2560" height="1529" />
</state>
- <state width="1479" height="330" key="GridCell.Tab.0.center/0.28.2560.1529@0.28.2560.1529" timestamp="1594963811113" />
- <state width="1479" height="330" key="GridCell.Tab.0.left" timestamp="1594963811113">
+ <state width="1479" height="330" key="GridCell.Tab.0.center/0.28.2560.1529@0.28.2560.1529" timestamp="1594967617574" />
+ <state width="1479" height="330" key="GridCell.Tab.0.left" timestamp="1594967617574">
<screen x="0" y="28" width="2560" height="1529" />
</state>
- <state width="1479" height="330" key="GridCell.Tab.0.left/0.28.2560.1529@0.28.2560.1529" timestamp="1594963811113" />
- <state width="1479" height="330" key="GridCell.Tab.0.right" timestamp="1594963811113">
+ <state width="1479" height="330" key="GridCell.Tab.0.left/0.28.2560.1529@0.28.2560.1529" timestamp="1594967617574" />
+ <state width="1479" height="330" key="GridCell.Tab.0.right" timestamp="1594967617575">
<screen x="0" y="28" width="2560" height="1529" />
</state>
- <state width="1479" height="330" key="GridCell.Tab.0.right/0.28.2560.1529@0.28.2560.1529" timestamp="1594963811113" />
+ <state width="1479" height="330" key="GridCell.Tab.0.right/0.28.2560.1529@0.28.2560.1529" timestamp="1594967617575" />
<state width="1479" height="406" key="GridCell.Tab.1.bottom" timestamp="1594959771008">
<screen x="0" y="28" width="2560" height="1529" />
</state>
<state x="833" y="545" width="586" height="502" key="find.popup/0.28.2560.1529@0.28.2560.1529" timestamp="1594949350582" />
- <state x="589" y="382" width="672" height="677" key="run.anything.popup" timestamp="1594954728874">
+ <state x="915" y="547" width="415" height="496" key="refactoring.ChangeSignatureDialog" timestamp="1594967617639">
<screen x="0" y="28" width="2560" height="1529" />
</state>
- <state x="589" y="382" width="672" height="677" key="run.anything.popup/0.28.2560.1529@0.28.2560.1529" timestamp="1594954728874" />
- <state x="589" y="477" width="672" height="678" key="search.everywhere.popup" timestamp="1594956705885">
+ <state x="915" y="547" width="415" height="496" key="refactoring.ChangeSignatureDialog/0.28.2560.1529@0.28.2560.1529" timestamp="1594967617639" />
+ <state x="589" y="382" width="672" height="677" key="run.anything.popup" timestamp="1594967368555">
<screen x="0" y="28" width="2560" height="1529" />
</state>
- <state x="589" y="477" width="672" height="678" key="search.everywhere.popup/0.28.2560.1529@0.28.2560.1529" timestamp="1594956705885" />
+ <state x="589" y="382" width="672" height="677" key="run.anything.popup/0.28.2560.1529@0.28.2560.1529" timestamp="1594967368555" />
+ <state x="589" y="477" width="672" height="678" key="search.everywhere.popup" timestamp="1594965859325">
+ <screen x="0" y="28" width="2560" height="1529" />
+ </state>
+ <state x="589" y="477" width="672" height="678" key="search.everywhere.popup/0.28.2560.1529@0.28.2560.1529" timestamp="1594965859325" />
</component>
</project>
src/main/com/whitemagicsoftware/kmcaster/AppImage.java
-/*
- * Copyright 2020 White Magic Software, Ltd.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * o Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * o 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
- * HOLDER 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 com.whitemagicsoftware.kmcaster;
-
-import com.kitfox.svg.SVGDiagram;
-import com.kitfox.svg.SVGException;
-import com.kitfox.svg.SVGUniverse;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.net.URL;
-import java.util.Map;
-
-import static com.whitemagicsoftware.kmcaster.KmCaster.rethrow;
-import static java.awt.RenderingHints.*;
-import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
-import static java.lang.String.format;
-
-/**
- * Responsible for loading vector graphics representations of application
- * images. The images provide an on-screen interface that indicate to the user
- * what key or mouse events are being triggered.
- */
-public class AppImage {
- public final static Map<Object, Object> RENDERING_HINTS = Map.of(
- KEY_ANTIALIASING,
- VALUE_ANTIALIAS_ON,
- KEY_ALPHA_INTERPOLATION,
- VALUE_ALPHA_INTERPOLATION_QUALITY,
- KEY_COLOR_RENDERING,
- VALUE_COLOR_RENDER_QUALITY,
- KEY_DITHERING,
- VALUE_DITHER_DISABLE,
- KEY_FRACTIONALMETRICS,
- VALUE_FRACTIONALMETRICS_ON,
- KEY_INTERPOLATION,
- VALUE_INTERPOLATION_BICUBIC,
- KEY_RENDERING,
- VALUE_RENDER_QUALITY,
- KEY_STROKE_CONTROL,
- VALUE_STROKE_PURE,
- KEY_TEXT_ANTIALIASING,
- VALUE_TEXT_ANTIALIAS_ON
- );
-
- private final static String IMAGES = "/images";
- private final static String IMAGES_KEY = IMAGES + "/key";
- private final static String IMAGES_MOUSE = IMAGES + "/mouse";
-
- public static final AppImage MOUSE_REST = mouseImage( "0" );
- public static final AppImage MOUSE_LEFT = mouseImage( "1" );
- public static final AppImage MOUSE_CHORD = mouseImage( "2" );
- public static final AppImage MOUSE_RIGHT = mouseImage( "3" );
- public static final AppImage MOUSE_LR = mouseImage( "1-3" );
- public static final AppImage KEY_UP_SHIFT = keyUpImage( "long" );
- public static final AppImage KEY_UP_ALT = keyUpImage( "medium" );
- public static final AppImage KEY_UP_CTRL = keyUpImage( "medium" );
- public static final AppImage KEY_UP_REGULAR = keyUpImage( "short" );
- public static final AppImage KEY_DN_SHIFT = keyDnImage( "long" );
- public static final AppImage KEY_DN_ALT = keyDnImage( "medium" );
- public static final AppImage KEY_DN_CTRL = keyDnImage( "medium" );
- public static final AppImage KEY_DN_REGULAR = keyDnImage( "short" );
-
- private static AppImage mouseImage( final String prefix ) {
- return createImage( format( "%s/%s", IMAGES_MOUSE, prefix ) );
- }
-
- private static AppImage keyImage( final String state, final String prefix ) {
- return createImage( format( "%s/%s/%s", IMAGES_KEY, state, prefix ) );
- }
-
- private static AppImage keyUpImage( final String prefix ) {
- return keyImage( "up", prefix );
- }
-
- private static AppImage keyDnImage( final String prefix ) {
- return keyImage( "dn", prefix );
- }
-
- private static AppImage createImage( final String path ) {
- return new AppImage( format( "%s.svg", path ) );
- }
-
- private final SVGUniverse mRenderer = new SVGUniverse();
- private final String mPath;
-
- /**
- * Constructs an enumerated type that represents the different types of
- * images shown when keyboard and mouse events are triggered.
- *
- * @param path File name, including directory, to load.
- */
- private AppImage( final String path ) {
- mPath = path;
- }
-
- public Image toImage( final Dimension dstDim ) {
- final var diagram = loadDiagram();
- final var diaWidth = diagram.getWidth();
- final var diaHeight = diagram.getHeight();
- final var srcDim = new Dimension( (int) diaWidth, (int) diaHeight );
-
- final var scaledDim = scale( srcDim, dstDim );
- final var w = (int) scaledDim.getWidth();
- final var h = (int) scaledDim.getHeight();
-
- final var image = new BufferedImage( w, h, TYPE_INT_ARGB );
-
- try {
- final Graphics2D g = image.createGraphics();
- g.setRenderingHints( RENDERING_HINTS );
-
- final AffineTransform transform = g.getTransform();
- transform.setToScale( w / diaWidth, h / diaHeight );
-
- g.setTransform( transform );
- diagram.render( g );
- g.dispose();
- } catch( final SVGException e ) {
- rethrow( e );
- }
-
- return image;
- }
-
- private SVGDiagram loadDiagram() {
- final var url = getResourceUrl();
- return applySettings( mRenderer.getDiagram( mRenderer.loadSVG( url ) ) );
- }
-
- private SVGDiagram applySettings( final SVGDiagram diagram ) {
- diagram.setIgnoringClipHeuristic( true );
- return diagram;
- }
-
- private URL getResourceUrl() {
- return AppImage.class.getResource( getPath() );
- }
-
- private String getPath() {
- return mPath;
- }
-
- private Dimension scale( final Dimension src, final Dimension dst ) {
- final var srcWidth = src.getWidth();
- final var srcHeight = src.getHeight();
- final var dstHeight = dst.getHeight();
-
- var newWidth = srcWidth;
- var newHeight = srcHeight;
-
- if( newHeight < dstHeight ) {
- newHeight = dstHeight;
- newWidth = (newHeight * srcWidth) / srcHeight;
- }
-
- return new Dimension( (int) newWidth, (int) newHeight );
- }
-}
src/main/com/whitemagicsoftware/kmcaster/EventFrame.java
import com.whitemagicsoftware.kmcaster.listeners.FrameDragListener;
-import com.whitemagicsoftware.kmcaster.listeners.Key;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.util.HashMap;
import java.util.Map;
-import static com.whitemagicsoftware.kmcaster.AppImage.*;
-import static com.whitemagicsoftware.kmcaster.listeners.Key.*;
+import static com.whitemagicsoftware.kmcaster.HardwareSwitches.state;
+import static com.whitemagicsoftware.kmcaster.SwitchName.*;
public class EventFrame extends JFrame {
private static final float ARC = 8;
private static final Dimension FRAME_DIMENSIONS = new Dimension( 484, 70 );
private static final Color TRANSLUCENT = new Color( .2f, .2f, .2f, 0.5f );
private static final Color TRANSPARENT = new Color( 0, 0, 0, 0 );
- private final Map<KeyState, Image> mKeyStates = new HashMap<>();
- private final Map<Key, ImageComponent> mKeyViews = new HashMap<>();
+ private final HardwareSwitches mSwitches;
+ private final Map<SwitchName, ImageComponent> mKeyViews = new HashMap<>();
public EventFrame() {
final var dimensions = new Dimension( getWidth(), getHeight() - 10 );
+ mSwitches = new HardwareSwitches( dimensions );
- final var mouseImage = MOUSE_REST.toImage( dimensions );
+ final var mouseImage = mSwitches.get( state( MOUSE_LEFT, false ) );
final var mouseComponent = createImageComponent( mouseImage );
- final var shiftUpImage = KEY_UP_SHIFT.toImage( dimensions );
- final var ctrlUpImage = KEY_UP_CTRL.toImage( dimensions );
- final var altUpImage = KEY_UP_ALT.toImage( dimensions );
- final var regularUpImage = KEY_UP_REGULAR.toImage( dimensions );
+ final var shiftUpImage = mSwitches.get( state( KEY_SHIFT, false ) );
+ final var ctrlUpImage = mSwitches.get( state( KEY_CTRL, false ) );
+ final var altUpImage = mSwitches.get( state( KEY_ALT, false ) );
+ final var regularUpImage = mSwitches.get( state( KEY_REGULAR, false ) );
final var shiftComponent = createImageComponent( shiftUpImage );
content.setLayout( layout );
content.add( panel );
-
- final var shiftDnImage = KEY_DN_SHIFT.toImage( dimensions );
- final var ctrlDnImage = KEY_DN_CTRL.toImage( dimensions );
- final var altDnImage = KEY_DN_ALT.toImage( dimensions );
- final var regularDnImage = KEY_DN_REGULAR.toImage( dimensions );
-
- mKeyStates.put( new KeyState( KEY_SHIFT, false ), shiftUpImage );
- mKeyStates.put( new KeyState( KEY_SHIFT, true ), shiftDnImage );
- mKeyStates.put( new KeyState( KEY_CTRL, false ), ctrlUpImage );
- mKeyStates.put( new KeyState( KEY_CTRL, true ), ctrlDnImage );
- mKeyStates.put( new KeyState( KEY_ALT, false ), altUpImage );
- mKeyStates.put( new KeyState( KEY_ALT, true ), altDnImage );
- mKeyStates.put( new KeyState( KEY_REGULAR, false ), regularUpImage );
- mKeyStates.put( new KeyState( KEY_REGULAR, true ), regularDnImage );
mKeyViews.put( KEY_SHIFT, shiftComponent );
mKeyViews.put( KEY_CTRL, ctrlComponent );
mKeyViews.put( KEY_ALT, altComponent );
mKeyViews.put( KEY_REGULAR, regularComponent );
}
- protected void updateKeys( final KeyState keyState ) {
- final var image = mKeyStates.get( keyState );
+ protected void updateKeys( final HardwareState keyState ) {
+ final var image = mSwitches.get( keyState );
final var component = mKeyViews.get( keyState.getKey() );
src/main/com/whitemagicsoftware/kmcaster/HardwareState.java
+/*
+ * Copyright 2020 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o 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
+ * HOLDER 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 com.whitemagicsoftware.kmcaster;
+
+/**
+ * Responsible for defining hardware switch states.
+ */
+public class HardwareState {
+ private final SwitchName mKey;
+ private final String mState;
+
+ public HardwareState( final SwitchName key, final boolean pressed ) {
+ assert key != null;
+
+ mKey = key;
+ mState = Boolean.toString( pressed );
+ }
+
+ public SwitchName getKey() {
+ return mKey;
+ }
+
+ @Override
+ public boolean equals( final Object o ) {
+ if( this == o ) {
+ return true;
+ }
+ if( o == null || getClass() != o.getClass() ) {
+ return false;
+ }
+
+ final HardwareState that = (HardwareState) o;
+
+ if( mKey != that.mKey ) {
+ return false;
+ }
+ return mState.equals( that.mState );
+ }
+
+ @Override
+ public int hashCode() {
+ int result = mKey.hashCode();
+ result = 31 * result + mState.hashCode();
+ return result;
+ }
+}
src/main/com/whitemagicsoftware/kmcaster/HardwareSwitches.java
+/*
+ * Copyright 2020 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o 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
+ * HOLDER 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 com.whitemagicsoftware.kmcaster;
+
+import java.awt.*;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.whitemagicsoftware.kmcaster.SwitchName.*;
+import static java.lang.String.format;
+
+/**
+ * Responsible for loading vector graphics representations of application
+ * images. The images provide an on-screen interface that indicate to the user
+ * what key or mouse events are being triggered.
+ */
+public class HardwareSwitches {
+
+ private final static String DIR_IMAGES = "/images";
+ private final static String DIR_IMAGES_KEYBOARD = DIR_IMAGES + "/key";
+ private final static String DIR_IMAGES_MOUSE = DIR_IMAGES + "/mouse";
+
+ private final static SvgRasterizer sRasterizer = new SvgRasterizer();
+
+ private final Map<HardwareState, Image> mImages = new HashMap<>();
+ private final Dimension mDimension;
+
+ /**
+ * Constructs an enumerated type that represents the different types of
+ * images shown when keyboard and mouse events are triggered.
+ *
+ * @param dimension The image will be scaled to the given height, aspect
+ * ratio is maintained.
+ */
+ public HardwareSwitches( final Dimension dimension ) {
+ assert dimension != null;
+
+ mDimension = dimension;
+
+ final var mouseReleased = mouseImage( "0" );
+
+ for( int i = 1; i <= 3; i++ ) {
+ final var s = Integer.toString( i );
+ final var switchName = SwitchName.valueFrom( "button " + s );
+ mImages.put( state( switchName, true ), mouseImage( s ) );
+ mImages.put( state( switchName, false ), mouseReleased );
+ }
+
+ mImages.put( state( MOUSE_LR, true ), mouseImage( "1-3" ) );
+ mImages.put( state( MOUSE_LR, false ), mouseReleased );
+
+ mImages.put( state( KEY_ALT, true ), keyDnImage( "medium" ) );
+ mImages.put( state( KEY_ALT, false ), keyUpImage( "medium" ) );
+ mImages.put( state( KEY_CTRL, true ), keyDnImage( "medium" ) );
+ mImages.put( state( KEY_CTRL, false ), keyUpImage( "medium" ) );
+ mImages.put( state( KEY_SHIFT, true ), keyDnImage( "long" ) );
+ mImages.put( state( KEY_SHIFT, false ), keyUpImage( "long" ) );
+ mImages.put( state( KEY_REGULAR, true ), keyDnImage( "short" ) );
+ mImages.put( state( KEY_REGULAR, false ), keyUpImage( "short" ) );
+ }
+
+ public Image get( final HardwareState state ) {
+ return mImages.get( state );
+ }
+
+ public static HardwareState state( final SwitchName name, final boolean state ) {
+ return new HardwareState( name, state );
+ }
+
+ private Image mouseImage( final String prefix ) {
+ return createImage( format( "%s/%s", DIR_IMAGES_MOUSE, prefix ) );
+ }
+
+ private Image keyImage(
+ final String state, final String prefix ) {
+ return createImage(
+ format( "%s/%s/%s", DIR_IMAGES_KEYBOARD, state, prefix )
+ );
+ }
+
+ private Image keyUpImage( final String prefix ) {
+ return keyImage( "up", prefix );
+ }
+
+ private Image keyDnImage( final String prefix ) {
+ return keyImage( "dn", prefix );
+ }
+
+ private Image createImage( final String path ) {
+ assert mDimension != null;
+
+ return sRasterizer.rasterize( format( "%s.svg", path ), mDimension );
+ }
+}
src/main/com/whitemagicsoftware/kmcaster/ImageComponent.java
}
+ public Image getImage() {
+ return mImage;
+ }
+
/**
* Repaints this component using the given image. This is a mutable
src/main/com/whitemagicsoftware/kmcaster/KeyState.java
-/*
- * Copyright 2020 White Magic Software, Ltd.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * o Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * o 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
- * HOLDER 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 com.whitemagicsoftware.kmcaster;
-
-import com.whitemagicsoftware.kmcaster.listeners.Key;
-
-import static java.lang.Boolean.parseBoolean;
-
-public class KeyState {
- private final Key mKey;
- private final String mState;
-
- public KeyState( final Key key, final boolean pressed ) {
- assert key != null;
-
- mKey = key;
- mState = Boolean.toString( pressed );
- }
-
- public KeyState( final Key key, final String pressed ) {
- this( key, parseBoolean( pressed ) );
- }
-
- public Key getKey() {
- return mKey;
- }
-
- @Override
- public boolean equals( final Object o ) {
- if( this == o ) {
- return true;
- }
- if( o == null || getClass() != o.getClass() ) {
- return false;
- }
-
- final KeyState keyState = (KeyState) o;
-
- if( mKey != keyState.mKey ) {
- return false;
- }
- return mState.equals( keyState.mState );
- }
-
- @Override
- public int hashCode() {
- int result = mKey.hashCode();
- result = 31 * result + mState.hashCode();
- return result;
- }
-}
src/main/com/whitemagicsoftware/kmcaster/KmCaster.java
package com.whitemagicsoftware.kmcaster;
-import com.whitemagicsoftware.kmcaster.listeners.Key;
import com.whitemagicsoftware.kmcaster.listeners.KeyboardListener;
import com.whitemagicsoftware.kmcaster.listeners.MouseListener;
import org.jnativehook.GlobalScreen;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.logging.Level;
+import static java.lang.Boolean.parseBoolean;
import static java.util.logging.Logger.getLogger;
import static javax.swing.SwingUtilities.invokeLater;
}
- private KeyState createKeyState( final String name, final Object bool ) {
- final var key = Key.valueFrom( name );
- final var state = bool.toString();
+ private HardwareState createKeyState( final String name, final Object bool ) {
+ assert name != null;
+ assert bool != null;
- return new KeyState( key, state );
+ final var key = SwitchName.valueFrom( name );
+ final var state = parseBoolean( bool.toString() );
+
+ return new HardwareState( key, state );
}
src/main/com/whitemagicsoftware/kmcaster/SvgRasterizer.java
+/*
+ * Copyright 2020 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o 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
+ * HOLDER 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 com.whitemagicsoftware.kmcaster;
+
+import com.kitfox.svg.SVGDiagram;
+import com.kitfox.svg.SVGException;
+import com.kitfox.svg.SVGUniverse;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.net.URL;
+import java.util.Map;
+
+import static com.whitemagicsoftware.kmcaster.KmCaster.rethrow;
+import static java.awt.RenderingHints.*;
+import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
+import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
+
+/**
+ * Responsible for converting SVG images into rasterized PNG images.
+ */
+public class SvgRasterizer {
+ public final static Map<Object, Object> RENDERING_HINTS = Map.of(
+ KEY_ANTIALIASING,
+ VALUE_ANTIALIAS_ON,
+ KEY_ALPHA_INTERPOLATION,
+ VALUE_ALPHA_INTERPOLATION_QUALITY,
+ KEY_COLOR_RENDERING,
+ VALUE_COLOR_RENDER_QUALITY,
+ KEY_DITHERING,
+ VALUE_DITHER_DISABLE,
+ KEY_FRACTIONALMETRICS,
+ VALUE_FRACTIONALMETRICS_ON,
+ KEY_INTERPOLATION,
+ VALUE_INTERPOLATION_BICUBIC,
+ KEY_RENDERING,
+ VALUE_RENDER_QUALITY,
+ KEY_STROKE_CONTROL,
+ VALUE_STROKE_PURE,
+ KEY_TEXT_ANTIALIASING,
+ VALUE_TEXT_ANTIALIAS_ON
+ );
+
+ private final static SVGUniverse sRenderer = new SVGUniverse();
+
+ /**
+ * Rasterizes a vector graphic to a given size using a {@link BufferedImage}.
+ * The rendering hints are set to produce high quality output.
+ *
+ * @param path Fully qualified path to the image resource to rasterize.
+ * @param dstDim The output image dimensions.
+ * @return The rasterized {@link Image}.
+ */
+ public Image rasterize( final String path, final Dimension dstDim ) {
+ final var diagram = loadDiagram( path );
+ final var diaWidth = diagram.getWidth();
+ final var diaHeight = diagram.getHeight();
+ final var srcDim = new Dimension( (int) diaWidth, (int) diaHeight );
+
+ final var scaledDim = scale( srcDim, dstDim );
+ final var w = (int) scaledDim.getWidth();
+ final var h = (int) scaledDim.getHeight();
+
+ final var image = new BufferedImage( w, h, TYPE_INT_ARGB );
+
+ try {
+ final Graphics2D g = image.createGraphics();
+ g.setRenderingHints( RENDERING_HINTS );
+
+ final AffineTransform transform = g.getTransform();
+ transform.setToScale( w / diaWidth, h / diaHeight );
+
+ g.setTransform( transform );
+ diagram.render( g );
+ g.dispose();
+ } catch( final SVGException e ) {
+ rethrow( e );
+ }
+
+ return image;
+ }
+
+ private URL getResourceUrl( final String path ) {
+ return HardwareSwitches.class.getResource( path );
+ }
+
+ private SVGDiagram loadDiagram( final String path ) {
+ final var url = getResourceUrl( path );
+ return applySettings( sRenderer.getDiagram( sRenderer.loadSVG( url ) ) );
+ }
+
+ private SVGDiagram applySettings( final SVGDiagram diagram ) {
+ diagram.setIgnoringClipHeuristic( true );
+ return diagram;
+ }
+
+ private Dimension scale( final Dimension src, final Dimension dst ) {
+ final var srcWidth = src.getWidth();
+ final var srcHeight = src.getHeight();
+ final var dstHeight = dst.getHeight();
+
+ var newWidth = srcWidth;
+ var newHeight = srcHeight;
+
+ if( newHeight < dstHeight ) {
+ newHeight = dstHeight;
+ newWidth = (newHeight * srcWidth) / srcHeight;
+ }
+
+ return new Dimension( (int) newWidth, (int) newHeight );
+ }
+}
src/main/com/whitemagicsoftware/kmcaster/SwitchName.java
+/*
+ * Copyright 2020 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o 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
+ * HOLDER 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 com.whitemagicsoftware.kmcaster;
+
+/**
+ * Used for compile-time binding between change listeners input events.
+ */
+public enum SwitchName {
+ KEY_ALT( "alt" ),
+ KEY_CTRL( "ctrl" ),
+ KEY_SHIFT( "shift" ),
+ KEY_REGULAR( "regular" ),
+ MOUSE_LEFT( "button 1" ),
+ MOUSE_WHEEL( "button 2" ),
+ MOUSE_RIGHT( "button 3" ),
+ MOUSE_LR( "button 1-3" );
+
+ private final String mName;
+
+ SwitchName( final String name ) {
+ mName = name;
+ }
+
+ public boolean isName( final String name ) {
+ return mName.equalsIgnoreCase( name );
+ }
+
+ /**
+ * Looks up the key that matches the given name, case-insensitively.
+ *
+ * @param name The name of the key to find in this enum.
+ * @return The {@link SwitchName} object that matches the name.
+ */
+ public static SwitchName valueFrom( final String name ) {
+ for( final var b : SwitchName.values() ) {
+ if( b.isName( name ) ) {
+ return b;
+ }
+ }
+
+ return KEY_REGULAR;
+ }
+
+ @Override
+ public String toString() {
+ return mName;
+ }
+}
src/main/com/whitemagicsoftware/kmcaster/listeners/Key.java
-/*
- * Copyright 2020 White Magic Software, Ltd.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * o Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * o 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
- * HOLDER 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 com.whitemagicsoftware.kmcaster.listeners;
-
-/**
- * Used for compile-time binding between change listeners and keyboard
- * events.
- */
-public enum Key {
- KEY_ALT( "alt" ),
- KEY_CTRL( "ctrl" ),
- KEY_SHIFT( "shift" ),
- KEY_REGULAR( "regular" );
-
- private final String mName;
-
- Key( final String name ) {
- mName = name;
- }
-
- public boolean isName( final String name ) {
- return mName.equalsIgnoreCase( name );
- }
-
- /**
- * Looks up the key that matches the given name, case-insensitively.
- *
- * @param name The name of the key to find in this enum.
- * @return The {@link Key} object that matches the name.
- */
- public static Key valueFrom( final String name ) {
- for( final var b : Key.values() ) {
- if( b.isName( name ) ) {
- return b;
- }
- }
-
- return KEY_REGULAR;
- }
-
- @Override
- public String toString() {
- return mName;
- }
-}
src/main/com/whitemagicsoftware/kmcaster/listeners/KeyboardListener.java
package com.whitemagicsoftware.kmcaster.listeners;
+import com.whitemagicsoftware.kmcaster.SwitchName;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.List;
import java.util.Map;
-import static com.whitemagicsoftware.kmcaster.listeners.Key.*;
+import static com.whitemagicsoftware.kmcaster.SwitchName.*;
import static java.util.Map.entry;
import static org.jnativehook.NativeInputEvent.*;
* @param n New property value.
*/
- private void tryFire( final Key key, final String o, final String n ) {
+ private void tryFire( final SwitchName key, final String o, final String n ) {
if( !o.equals( n ) ) {
mDispatcher.firePropertyChange( key.toString(), o, n );
}
}
/**
- * Delegates to {@link #tryFire(Key, String, String)} with {@link Boolean}
+ * Delegates to {@link #tryFire(SwitchName, String, String)} with {@link Boolean}
* values as strings.
*
* @param key The name of the property that has changed.
* @param o Old property value.
* @param n New property value.
*/
- private void tryFire( final Key key, final boolean o, final boolean n ) {
+ private void tryFire( final SwitchName key, final boolean o, final boolean n ) {
tryFire( key, Boolean.toString( o ), Boolean.toString( n ) );
}
src/main/com/whitemagicsoftware/kmcaster/listeners/KeyboardModifier.java
package com.whitemagicsoftware.kmcaster.listeners;
+import com.whitemagicsoftware.kmcaster.SwitchName;
import org.jnativehook.keyboard.NativeKeyEvent;
/**
* Responsible for tracking the state of modifier keys.
*/
class KeyboardModifier {
private boolean mHeld;
private final int mMask;
- private final Key mKey;
+ private final SwitchName mKey;
- KeyboardModifier( final Key key, final int mask ) {
+ KeyboardModifier( final SwitchName key, final int mask ) {
assert key != null;
}
- public Key getKey() {
+ public SwitchName getKey() {
return mKey;
}

Consolidate mouse and keyboard into switches

Author DaveJarvis <email>
Date 2020-07-17 00:00:20 GMT-0700
Commit 57413d222f2be0151cb8575994bdf95eb7b31139
Parent 620583d
Delta 458 lines added, 388 lines removed, 70-line increase