Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/kmcaster.git

Display scroll events

AuthorDaveJarvis <email>
Date2020-08-03 18:01:33 GMT-0700
Commit6d53434084967b7aac127bccc2f9fabd03361bae
Parentd961a97
README.md
```
+To see the configuration options, run the program as follows:
+
+``` bash
+java -jar kmcaster.jar -h
+```
+
+To quit the application:
+
+1. Click the application to give it focus.
+1. Press `Alt+F4` to exit.
+
## Error Messages
src/main/com/whitemagicsoftware/kmcaster/EventHandler.java
import java.util.Map;
-import static com.whitemagicsoftware.kmcaster.HardwareState.SWITCH_PRESSED;
-import static com.whitemagicsoftware.kmcaster.HardwareState.SWITCH_RELEASED;
-import static com.whitemagicsoftware.kmcaster.HardwareSwitch.KEY_REGULAR;
-import static com.whitemagicsoftware.kmcaster.HardwareSwitch.MOUSE_UNDEFINED;
+import static com.whitemagicsoftware.kmcaster.HardwareState.*;
+import static com.whitemagicsoftware.kmcaster.HardwareSwitch.*;
import static com.whitemagicsoftware.kmcaster.LabelConfig.*;
import static com.whitemagicsoftware.kmcaster.ui.Constants.*;
*/
private static final HardwareSwitchState MOUSE_RELEASED =
- new HardwareSwitchState( MOUSE_UNDEFINED, SWITCH_RELEASED );
+ new HardwareSwitchState( MOUSE_EXTRA, SWITCH_RELEASED );
private final HardwareImages mHardwareImages;
private final AutofitLabel[] mLabels = new AutofitLabel[ LabelConfig.size() ];
private final Map<HardwareSwitch, ResetTimer> mTimers = new HashMap<>();
public EventHandler(
- final HardwareImages hardwareImages, final UserSettings userSettings ) {
+ final HardwareImages hardwareImages, final Settings userSettings ) {
mHardwareImages = hardwareImages;
mLabels[ config.ordinal() ] = label;
- config.getHardwareSwitch().ifPresentOrElse(
+ final var hwSwitch = config.getHardwareSwitch();
+
+ hwSwitch.ifPresentOrElse(
s -> mHardwareImages.get( s ).add( label ),
() -> mHardwareImages.get( KEY_REGULAR ).add( label )
);
- }
-
- final var delayModifier = userSettings.getDelayKeyModifier();
- final var delayRegular = userSettings.getDelayKeyRegular();
- final var delayButton = userSettings.getDelayMouseButton();
-
- for( final var key : HardwareSwitch.keyboardSwitches() ) {
- final var delay = key.isModifier() ? delayModifier : delayRegular;
-
- mTimers.put( key, new ResetTimer( delay ) );
}
- for( final var key : HardwareSwitch.mouseSwitches() ) {
- mTimers.put( key, new ResetTimer( delayButton ) );
- }
+ putTimers( modifierSwitches(), userSettings.getDelayKeyModifier() );
+ putTimers( regularSwitches(), userSettings.getDelayKeyRegular() );
+ putTimers( mouseSwitches(), userSettings.getDelayMouseButton() );
+ putTimers( scrollSwitches(), userSettings.getDelayMouseScroll() );
}
}
- private final Deque<HardwareSwitch> mMousePressed = new LinkedList<>();
+ private final Deque<HardwareSwitch> mMouseActions = new LinkedList<>();
/**
else {
if( hwState == SWITCH_RELEASED ) {
- mMousePressed.remove( hwSwitch );
+ mMouseActions.remove( hwSwitch );
timer.addActionListener(
( event ) -> updateMouseStatus( switchState )
);
}
else {
timer.stop();
- mMousePressed.add( hwSwitch );
+ mMouseActions.add( hwSwitch );
updateMouseStatus( switchState );
+
+ if( hwSwitch.isScroll() ) {
+ timer.addActionListener(
+ ( action ) -> {
+ final var sauce = e.getSource();
+ final var name = e.getPropertyName();
+ final var event = new PropertyChangeEvent(
+ sauce, name, true, false );
+
+ update( event );
+ }
+ );
+ }
}
}
private void updateMouseStatus( final HardwareSwitchState switchState ) {
- final var container = getHardwareComponent( MOUSE_RELEASED );
- final var rm = currentManager( container );
- final var button = getLabel( LABEL_MOUSE_UNDEFINED );
final var hwSwitch = switchState.getHardwareSwitch();
final var hwState = switchState.getHardwareState();
- if( hwSwitch == MOUSE_UNDEFINED ) {
+ if( hwSwitch == MOUSE_EXTRA ) {
+ final var config = LabelConfig.valueFrom( hwSwitch );
+ final var button = getLabel( config );
+
if( hwState == SWITCH_PRESSED ) {
button.setText( switchState.getValue() );
}
- container.setState( new HardwareSwitchState( hwSwitch, SWITCH_RELEASED ) );
- rm.paintDirtyRegions();
+ final var component = getHardwareComponent( MOUSE_RELEASED );
+ final var rm = currentManager( component );
- for( final var mouseSwitch : mMousePressed ) {
- final var buttonState = new HardwareSwitchState(
- mouseSwitch, SWITCH_PRESSED );
+ component.setState( new HardwareSwitchState( hwSwitch, SWITCH_RELEASED ) );
+ rm.paintDirtyRegions();
- container.setState( buttonState );
+ for( final var action : mMouseActions ) {
+ component.setState( new HardwareSwitchState( action, SWITCH_PRESSED ) );
rm.paintDirtyRegions();
}
final HardwareSwitchState state ) {
return mHardwareImages.get( state.getHardwareSwitch() );
+ }
+
+ private void putTimers( final HardwareSwitch[] hwSwitches, final int delay ) {
+ for( final var hwSwitch : hwSwitches ) {
+ mTimers.put( hwSwitch, new ResetTimer( delay ) );
+ }
}
src/main/com/whitemagicsoftware/kmcaster/HardwareImages.java
KEY_SHIFT, new Insets( 10, 50, 12, 11 ),
KEY_REGULAR, new Insets( 3, 7, 6, 7 ),
- MOUSE_UNDEFINED, new Insets( 27, 5, 11, 5 )
+ MOUSE_EXTRA, new Insets( 27, 5, 11, 5 )
);
mSwitches = new HashMap<>();
- public HardwareImages( final UserSettings userSettings ) {
+ public HardwareImages( final Settings userSettings ) {
mAppDimensions = userSettings.createAppDimensions();
final var mouseReleased = mouseImage( "0" );
final var mouseScale = mouseReleased.getValue();
final var mouseStates =
- createHardwareComponent( MOUSE_UNDEFINED, mouseScale );
+ createHardwareComponent( MOUSE_EXTRA, mouseScale );
- for( final var key : HardwareSwitch.mouseSwitches() ) {
- final var stateOn = state( key, SWITCH_PRESSED );
- final var stateOff = state( key, SWITCH_RELEASED );
+ for( final var hwSwitch : mouseSwitches() ) {
+ final var stateOn = state( hwSwitch, SWITCH_PRESSED );
+ final var stateOff = state( hwSwitch, SWITCH_RELEASED );
+ final var imageDn = mouseImage( hwSwitch.toString() );
- final var imageDn = mouseImage( key.toString() );
mouseStates.put( stateOn, imageDn.getKey() );
mouseStates.put( stateOff, mouseReleased.getKey() );
- mSwitches.put( key, mouseStates );
+ mSwitches.put( hwSwitch, mouseStates );
}
- for( final var key : HardwareSwitch.keyboardSwitches() ) {
+ for( final var key : keyboardSwitches() ) {
final var stateOn = state( key, SWITCH_PRESSED );
final var stateOff = state( key, SWITCH_RELEASED );
final var imageDn = keyDnImage( FILE_NAME_PREFIXES.get( key ) );
final var imageUp = keyUpImage( FILE_NAME_PREFIXES.get( key ) );
final var scale = imageDn.getValue();
final var keyStates = createHardwareComponent( key, scale );
keyStates.put( stateOn, imageDn.getKey() );
keyStates.put( stateOff, imageUp.getKey() );
-
mSwitches.put( key, keyStates );
}
src/main/com/whitemagicsoftware/kmcaster/HardwareState.java
package com.whitemagicsoftware.kmcaster;
-import static java.lang.Boolean.*;
+import static java.lang.Boolean.FALSE;
/**
* Responsible for defining hardware switch states.
*/
public enum HardwareState {
/**
- * Defines when a hardware switch is down.
+ * Indicates a hardware switch is down.
*/
SWITCH_PRESSED,
/**
- * Defines when a hardware switch is up.
+ * Indicates a hardware switch is up.
*/
SWITCH_RELEASED;
src/main/com/whitemagicsoftware/kmcaster/HardwareSwitch.java
MOUSE_MIDDLE( "2" ),
MOUSE_RIGHT( "3" ),
- MOUSE_UNDEFINED( "undefined" ),
+ MOUSE_EXTRA( "extra" ),
+ MOUSE_SCROLL_U( "u" ),
+ MOUSE_SCROLL_D( "d" ),
+ MOUSE_SCROLL_L( "l" ),
+ MOUSE_SCROLL_R( "r" ),
KEY_SHIFT( "shift", SHIFT_MASK ),
KEY_CTRL( "ctrl", CTRL_MASK ),
KEY_ALT( "alt", ALT_MASK ),
KEY_REGULAR( "regular" );
+
+ private final static HardwareSwitch[] mMouseSwitches = {
+ MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, MOUSE_EXTRA,
+ MOUSE_SCROLL_U, MOUSE_SCROLL_D, MOUSE_SCROLL_L, MOUSE_SCROLL_R
+ };
+
+ private final static HardwareSwitch[] mScrollSwitches = {
+ MOUSE_SCROLL_U, MOUSE_SCROLL_D, MOUSE_SCROLL_L, MOUSE_SCROLL_R
+ };
+
+ private final static HardwareSwitch[] mKeyboardSwitches =
+ {KEY_SHIFT, KEY_CTRL, KEY_ALT, KEY_REGULAR};
+
+ private final static HardwareSwitch[] mModifierSwitches =
+ {KEY_SHIFT, KEY_CTRL, KEY_ALT};
+
+ private final static HardwareSwitch[] mRegularSwitches =
+ {KEY_REGULAR};
/**
*/
public boolean isKeyboard() {
- return name().startsWith( "KEY" );
+ return isPrefix( "KEY" );
+ }
+
+ /**
+ * Answers whether this hardware switch represents a scroll "button".
+ *
+ * @return {@code true} to indicate a scrolling action occurred.
+ */
+ public boolean isScroll() {
+ return isPrefix( "MOUSE_SCROLL" );
+ }
+
+ private boolean isPrefix( final String key ) {
+ return name().startsWith( key );
}
*/
public static HardwareSwitch[] keyboardSwitches() {
- return new HardwareSwitch[]{KEY_SHIFT, KEY_CTRL, KEY_ALT, KEY_REGULAR};
+ return mKeyboardSwitches;
}
public static HardwareSwitch[] modifierSwitches() {
- return new HardwareSwitch[]{KEY_SHIFT, KEY_CTRL, KEY_ALT};
+ return mModifierSwitches;
+ }
+
+ public static HardwareSwitch[] regularSwitches() {
+ return mRegularSwitches;
}
/**
* Returns a list of mouse buttons.
*
- * @return The complete list of mouse buttons.
+ * @return The complete list of mouse and scroll buttons.
*/
public static HardwareSwitch[] mouseSwitches() {
- return new HardwareSwitch[]{
- MOUSE_LEFT, MOUSE_MIDDLE, MOUSE_RIGHT, MOUSE_UNDEFINED
- };
+ return mMouseSwitches;
+ }
+
+ /**
+ * Returns a list of scrolling direction indicators.
+ *
+ * @return The complete list of scroll direction indicators.
+ */
+ public static HardwareSwitch[] scrollSwitches() {
+ return mScrollSwitches;
}
src/main/com/whitemagicsoftware/kmcaster/KmCaster.java
public final class KmCaster extends JFrame {
- private final UserSettings mUserSettings = new UserSettings( this );
+ private final Settings mUserSettings = new Settings( this );
/**
}
- private UserSettings getUserSettings() {
+ private Settings getUserSettings() {
return mUserSettings;
}
src/main/com/whitemagicsoftware/kmcaster/LabelConfig.java
import javax.swing.*;
+import java.util.NoSuchElementException;
import java.util.Optional;
LABEL_REGULAR_NUM_SUPERSCRIPT( TOP, LEFT ),
LABEL_REGULAR_COUNTER( TOP, RIGHT ),
- LABEL_MOUSE_UNDEFINED( MOUSE_UNDEFINED );
+ LABEL_MOUSE_OTHER( MOUSE_EXTRA );
/**
mVerticalAlign = vAlign;
mHorizontalAlign = hAlign;
+ }
+
+ static LabelConfig valueFrom( final HardwareSwitch hwSwitch ) {
+ for( final var lc : values() ) {
+ if( lc.isHardwareSwitch( hwSwitch ) ) {
+ return lc;
+ }
+ }
+
+ throw new NoSuchElementException( hwSwitch.toTitleCase() );
}
String toTitleCase() {
return mHardwareSwitch == null ? " " : mHardwareSwitch.toTitleCase();
+ }
+
+ private boolean isHardwareSwitch( final HardwareSwitch hwSwitch ) {
+ final var os = getHardwareSwitch();
+ return os.isPresent() && os.get() == hwSwitch;
}
src/main/com/whitemagicsoftware/kmcaster/Settings.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 picocli.CommandLine;
+
+import java.awt.*;
+import java.util.concurrent.Callable;
+
+@CommandLine.Command(
+ name = "KmCaster",
+ mixinStandardHelpOptions = true,
+ description = "Displays key presses and mouse clicks on the screen."
+)
+@SuppressWarnings("FieldMayBeFinal")
+public final class Settings implements Callable<Integer> {
+ /**
+ * Minimum application height, in pixels.
+ */
+ private static final int MIN_HEIGHT_PX = 20;
+
+ /**
+ * Executable class.
+ */
+ private final KmCaster mKmCaster;
+
+ /**
+ * Application height in pixels. Images are scaled to this height, maintaining
+ * aspect ratio. The height constrains the width, so as long as the width
+ * is large enough, the application's window will adjust to fit.
+ */
+ @CommandLine.Option(
+ names = {"-d", "--dimension"},
+ description =
+ "Application height (${DEFAULT-VALUE} pixels)",
+ paramLabel = "height",
+ defaultValue = "100"
+ )
+ private int mHeight = 100;
+
+ /**
+ * Milliseconds to wait before releasing (clearing) a regular key.
+ */
+ @CommandLine.Option(
+ names = {"-a", "--delay-alphanum"},
+ description =
+ "Regular key release delay (${DEFAULT-VALUE} milliseconds)",
+ paramLabel = "delay",
+ defaultValue = "250"
+ )
+ private int mDelayKeyRegular = 250;
+
+ /**
+ * Milliseconds to wait before releasing (clearing) any modifier key.
+ */
+ @CommandLine.Option(
+ names = {"-m", "--delay-modifier"},
+ description =
+ "Modifier key release delay (${DEFAULT-VALUE} milliseconds)",
+ paramLabel = "delay",
+ defaultValue = "150"
+ )
+ private int mDelayKeyModifier = 150;
+
+ /**
+ * Milliseconds to wait before releasing (clearing) a mouse button.
+ */
+ @CommandLine.Option(
+ names = {"-b", "--delay-button"},
+ description =
+ "Mouse button release delay (${DEFAULT-VALUE} milliseconds)",
+ paramLabel = "delay",
+ defaultValue = "100"
+ )
+ private int mDelayMouseButton = 100;
+
+ /**
+ * Milliseconds to wait before releasing (clearing) a mouse scroll event.
+ */
+ @CommandLine.Option(
+ names = {"-s", "--delay-scroll"},
+ description =
+ "Mouse scroll release delay (${DEFAULT-VALUE} milliseconds)",
+ paramLabel = "delay",
+ defaultValue = "300"
+ )
+ private int mDelayMouseScroll = 300;
+
+ public Settings( final KmCaster kmCaster ) {
+ assert kmCaster != null;
+
+ mKmCaster = kmCaster;
+ }
+
+ /**
+ * Invoked after the command-line arguments are parsed to launch the
+ * application.
+ *
+ * @return Exit level zero.
+ */
+ @Override
+ public Integer call() {
+ mKmCaster.init();
+ return 0;
+ }
+
+ public int getDelayKeyRegular() {
+ return mDelayKeyRegular;
+ }
+
+ public int getDelayKeyModifier() {
+ return mDelayKeyModifier;
+ }
+
+ public int getDelayMouseButton() {
+ return mDelayMouseButton;
+ }
+
+ public int getDelayMouseScroll() {
+ return mDelayMouseScroll;
+ }
+
+ public Dimension createAppDimensions() {
+ return new Dimension( 1024 + getHeight(), getHeight() );
+ }
+
+ /**
+ * This will return the user-specified height
+ *
+ * @return The application height, in pixels.
+ */
+ private int getHeight() {
+ return mHeight < MIN_HEIGHT_PX ? MIN_HEIGHT_PX : mHeight;
+ }
+}
src/main/com/whitemagicsoftware/kmcaster/UserSettings.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 picocli.CommandLine;
-
-import java.awt.*;
-import java.util.concurrent.Callable;
-
-@CommandLine.Command(
- name = "KmCaster",
- mixinStandardHelpOptions = true,
- description = "Displays key presses and mouse clicks on the screen."
-)
-@SuppressWarnings("FieldMayBeFinal")
-public final class UserSettings implements Callable<Integer> {
- /**
- * Minimum application height, in pixels.
- */
- private static final int MIN_HEIGHT_PX = 20;
-
- /**
- * Executable class.
- */
- private final KmCaster mKmCaster;
-
- /**
- * Application height in pixels. Images are scaled to this height, maintaining
- * aspect ratio. The height constrains the width, so as long as the width
- * is large enough, the application's window will adjust to fit.
- */
- @CommandLine.Option(
- names = {"-s", "--size"},
- description =
- "Application size (${DEFAULT-VALUE} pixels)",
- paramLabel = "height",
- defaultValue = "100"
- )
- private int mHeight = 100;
-
- /**
- * Milliseconds to wait before releasing (clearing) a regular key.
- */
- @CommandLine.Option(
- names = {"-a", "--delay-alphanum"},
- description =
- "Regular key release delay (${DEFAULT-VALUE} milliseconds)",
- paramLabel = "delay",
- defaultValue = "250"
- )
- private int mDelayKeyRegular = 250;
-
- /**
- * Milliseconds to wait before releasing (clearing) any modifier key.
- */
- @CommandLine.Option(
- names = {"-m", "--delay-modifier"},
- description =
- "Modifier key release delay (${DEFAULT-VALUE} milliseconds)",
- paramLabel = "delay",
- defaultValue = "150"
- )
- private int mDelayKeyModifier = 150;
-
- /**
- * Milliseconds to wait before releasing (clearing) a mouse button.
- */
- @CommandLine.Option(
- names = {"-b", "--delay-button"},
- description =
- "Mouse button release delay (${DEFAULT-VALUE} milliseconds)",
- paramLabel = "delay",
- defaultValue = "100"
- )
- private int mDelayMouseButton = 100;
-
- public UserSettings( final KmCaster kmCaster ) {
- assert kmCaster != null;
-
- mKmCaster = kmCaster;
- }
-
- /**
- * Invoked after the command-line arguments are parsed to launch the
- * application.
- *
- * @return Exit level zero.
- */
- @Override
- public Integer call() {
- mKmCaster.init();
- return 0;
- }
-
- public int getDelayKeyRegular() {
- return mDelayKeyRegular;
- }
-
- public int getDelayKeyModifier() {
- return mDelayKeyModifier;
- }
-
- public int getDelayMouseButton() {
- return mDelayMouseButton;
- }
-
- public Dimension createAppDimensions() {
- return new Dimension( 1024 + getHeight(), getHeight() );
- }
-
- /**
- * This will return the user-specified height
- *
- * @return The application height, in pixels.
- */
- private int getHeight() {
- return mHeight < MIN_HEIGHT_PX ? MIN_HEIGHT_PX : mHeight;
- }
-}
src/main/com/whitemagicsoftware/kmcaster/listeners/MouseListener.java
import com.whitemagicsoftware.kmcaster.HardwareSwitch;
+import com.whitemagicsoftware.kmcaster.util.Pair;
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseInputListener;
import org.jnativehook.mouse.NativeMouseWheelEvent;
import org.jnativehook.mouse.NativeMouseWheelListener;
import java.util.HashMap;
import java.util.Map;
-import static com.whitemagicsoftware.kmcaster.HardwareSwitch.MOUSE_UNDEFINED;
-import static com.whitemagicsoftware.kmcaster.HardwareSwitch.mouseSwitches;
+import static com.whitemagicsoftware.kmcaster.HardwareSwitch.*;
import static java.util.Map.entry;
+import static org.jnativehook.mouse.NativeMouseWheelEvent.WHEEL_HORIZONTAL_DIRECTION;
+import static org.jnativehook.mouse.NativeMouseWheelEvent.WHEEL_VERTICAL_DIRECTION;
/**
* Listens for all mouse events: clicks and mouse wheel scrolls.
*/
public final class MouseListener
extends PropertyDispatcher<HardwareSwitch>
implements NativeMouseInputListener, NativeMouseWheelListener {
- private final static Map<Integer, String> SCROLL_CODES =
- Map.ofEntries(
- entry( 1, "↑" ),
- entry( -1, "↓" )
- );
+ private final static Map<Pair<Integer, Integer>, HardwareSwitch>
+ SCROLL_CODES = Map.ofEntries(
+ entry( new Pair<>( WHEEL_VERTICAL_DIRECTION, -1 ), MOUSE_SCROLL_U ),
+ entry( new Pair<>( WHEEL_VERTICAL_DIRECTION, 1 ), MOUSE_SCROLL_D ),
+ entry( new Pair<>( WHEEL_HORIZONTAL_DIRECTION, -1 ), MOUSE_SCROLL_L ),
+ entry( new Pair<>( WHEEL_HORIZONTAL_DIRECTION, 1 ), MOUSE_SCROLL_R )
+ );
+
+ /**
+ * Most recently pressed non-mapped button value, empty signifies release.
+ */
+ private String mExtra = "";
/**
* Stores the state of button presses. The contents of the map reflect the
* state of each switch, so the reference can be final but not its contents.
*/
private final Map<HardwareSwitch, Boolean> mSwitches = new HashMap<>();
+ /**
+ * Initializes the mouse switches to a released state.
+ */
public MouseListener() {
for( final var key : mouseSwitches() ) {
mSwitches.put( key, false );
}
}
public void nativeMousePressed( final NativeMouseEvent e ) {
- dispatchMouseEvent( e, true );
+ dispatchButtonEvent( e, true );
}
public void nativeMouseReleased( final NativeMouseEvent e ) {
- dispatchMouseEvent( e, false );
+ dispatchButtonEvent( e, false );
}
public void nativeMouseWheelMoved( final NativeMouseWheelEvent e ) {
- //dispatchMouseEvent( e, e.getWheelRotation() );
- }
+ final var pair = new Pair<>( e.getWheelDirection(), e.getWheelRotation() );
+ final var scrollSwitch = SCROLL_CODES.get( pair );
- /**
- * Most recently pressed non-mapped button value, empty signifies release.
- */
- private String mUndefined = "";
+ for( final var hwSwitch : scrollSwitches() ) {
+ if( mSwitches.get( hwSwitch ) ) {
+ tryFire( hwSwitch, true, false );
+ mSwitches.put( hwSwitch, false );
+ }
+ }
+
+ tryFire( scrollSwitch, mSwitches.get( scrollSwitch ), true );
+ mSwitches.put( scrollSwitch, true );
+ }
/**
* Called to send a mouse event to all listeners.
*
* @param e The mouse event that was most recently triggered.
* @param pressed {@code true} means pressed, {@code false} means released.
*/
- private void dispatchMouseEvent(
+ private void dispatchButtonEvent(
final NativeMouseEvent e, final boolean pressed ) {
final var hwSwitch = getMouseSwitch( e );
// Percolate the button number as a string for any undefined (unmapped)
// mouse buttons that are clicked. This enables additional mouse
// buttons beyond two to appear, without an image representation.
- if( hwSwitch == MOUSE_UNDEFINED ) {
+ if( hwSwitch == MOUSE_EXTRA ) {
final var button = Integer.toString( e.getButton() );
final var n = pressed ? button : "";
- final var o = pressed ? mUndefined : button;
+ final var o = pressed ? mExtra : button;
fire( hwSwitch, o, n );
- mUndefined = n;
+ mExtra = n;
}
else {
return switch( button ) {
case 1, 2, 3 -> HardwareSwitch.valueFrom( Integer.toString( button ) );
- default -> MOUSE_UNDEFINED;
+ default -> MOUSE_EXTRA;
};
}
src/main/resources/images/mouse/0.svg
-<svg viewBox="0 0 35 60" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><radialGradient id="a" cx="193.4" cy="181.62" gradientTransform="matrix(.13524 0 0 .34162 8.5772 -48.069)" gradientUnits="userSpaceOnUse" r="68.141" spreadMethod="reflect" xlink:href="#b"/><linearGradient id="b"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#666"/></linearGradient><radialGradient id="c" cx="85.528" cy="170.14" gradientTransform="matrix(.14849 0 0 .25527 8.1707 -36.461)" gradientUnits="userSpaceOnUse" r="252.08" spreadMethod="reflect" xlink:href="#b"/><linearGradient id="d" gradientTransform="matrix(.13405 0 0 .2832 8.3022 -37.262)" gradientUnits="userSpaceOnUse" spreadMethod="reflect" x1="193.63" x2="193.63" y1="161.65" y2="162.42"><stop offset="0" stop-color="#333"/><stop offset="1" stop-color="#fff"/></linearGradient><radialGradient id="e" cx="158.03" cy="169.2" gradientTransform="matrix(.13493 0 0 .28136 8.3022 -37.262)" gradientUnits="userSpaceOnUse" r="31.163" spreadMethod="reflect"><stop offset="0" stop-color="#b3b3eb" stop-opacity="0"/><stop offset="1"/></radialGradient><g transform="translate(-14.6 .6541)"><path d="m32.103 59.075c-14.905 0-17.159-12.11-17.004-15.947.22946-3.6188.42034-18.176-.23806-30.434.16776-13.396 11.35-13.076 17.24-13.076 5.8896 0 17.072-.32021 17.24 13.076-.65838 12.258-.46751 26.815-.23806 30.433.1542 3.8367-2.0993 15.947-17.004 15.947" style="fill-rule:evenodd;stroke:#000;stroke-linejoin:round;stroke-opacity:.19772;stroke-width:.53116;fill:url(#c)"/><ellipse cx="32.083" cy="10.963" fill="url(#a)" fill-rule="evenodd" rx="3.1799" ry="8.0323"/><g fill="none" stroke="#484848"><path d="m32.105 21.772c-8.1608 0-12.278.18287-14.374.37127-2.0963.1884-2.0388.39852-2.2514.40444" stroke-width=".53125"/><path d="m32.104 21.772c8.1608 0 12.278.18287 14.374.37127 2.0963.1884 2.0388.39852 2.2514.40444" stroke-width=".53125"/><path d="m32.098-.10793v21.716" stroke-width=".53116"/></g><g fill-rule="evenodd"><path d="m34.434 11.065a2.3354 4.9339 0 1 1 -4.6708 0 2.3354 4.9339 0 1 1 4.6708 0z" fill="url(#d)"/><path d="m34.434 11.065a2.3354 4.9339 0 1 1 -4.6708 0 2.3354 4.9339 0 1 1 4.6708 0z" fill="url(#e)" stroke="#000" stroke-width=".10716"/></g></g></svg>
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" viewBox="0 0 35 60" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <radialGradient id="a" cx="193.4" cy="181.62" r="68.141" gradientTransform="matrix(.13524 0 0 .34162 -6.0078 -47.415)" gradientUnits="userSpaceOnUse" spreadMethod="reflect" xlink:href="#b"/>
+ <linearGradient id="b">
+ <stop stop-color="#fff" offset="0"/>
+ <stop stop-color="#666" offset="1"/>
+ </linearGradient>
+ <radialGradient id="c" cx="85.528" cy="170.14" r="252.08" gradientTransform="matrix(.14849 0 0 .25527 -6.4293 -35.807)" gradientUnits="userSpaceOnUse" spreadMethod="reflect" xlink:href="#b"/>
+ <linearGradient id="d" x1="193.63" x2="193.63" y1="161.65" y2="162.42" gradientTransform="matrix(.13405 0 0 .2832 -6.2984 -36.608)" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
+ <stop stop-color="#333" offset="0"/>
+ <stop stop-color="#fff" offset="1"/>
+ </linearGradient>
+ <radialGradient id="e" cx="158.03" cy="169.2" r="31.163" gradientTransform="matrix(.13493 0 0 .28136 -6.2984 -36.608)" gradientUnits="userSpaceOnUse" spreadMethod="reflect">
+ <stop stop-color="#b3b3eb" stop-opacity="0" offset="0"/>
+ <stop offset="1"/>
+ </radialGradient>
+ <path d="m17.503 59.729c-14.905 0-17.159-12.11-17.004-15.947 0.22946-3.6188 0.42034-18.176-0.23806-30.434 0.16776-13.396 11.35-13.076 17.24-13.076 5.8896 0 17.072-0.32021 17.24 13.076-0.65838 12.258-0.46751 26.815-0.23806 30.433 0.1542 3.8367-2.0993 15.947-17.004 15.947" fill="url(#c)" fill-rule="evenodd" stroke="#000" stroke-linejoin="round" stroke-opacity=".19772" stroke-width=".53116"/>
+ <ellipse cx="17.498" cy="11.617" rx="3.1799" ry="8.0323" fill="url(#a)" fill-rule="evenodd"/>
+ <g fill="none" stroke="#484848">
+ <path d="m17.505 22.426c-8.1608 0-12.278 0.18287-14.374 0.37127-2.0963 0.1884-2.0388 0.39852-2.2514 0.40444" stroke-width=".53125"/>
+ <path d="m17.504 22.426c8.1608 0 12.278 0.18287 14.374 0.37127 2.0963 0.1884 2.0388 0.39852 2.2514 0.40444" stroke-width=".53125"/>
+ <path d="m17.498 0.54617v21.716" stroke-width=".53116"/>
+ </g>
+ <path d="m19.833 11.719a2.3354 4.9339 0 1 1-4.6708 0 2.3354 4.9339 0 1 1 4.6708 0z" fill="url(#d)" fill-rule="evenodd"/>
+ <path d="m19.833 11.719a2.3354 4.9339 0 1 1-4.6708 0 2.3354 4.9339 0 1 1 4.6708 0z" fill="url(#e)" fill-rule="evenodd" stroke="#000" stroke-width=".10716"/>
+</svg>
+
src/main/resources/images/mouse/d.svg
+<svg viewBox="0 0 35 60" xmlns="http://www.w3.org/2000/svg"><path d="m9.4655 10.991h4.9429v-5.6695h6.1788v5.6743h4.9432l-8.0327 6.9166z" fill="#333" fill-opacity=".8"/></svg>
src/main/resources/images/mouse/extra.svg
-
+<svg viewBox="0 0 35 60" xmlns="http://www.w3.org/2000/svg"><path d="m17.502 59.388c-14.667 0-16.886-11.917-16.733-15.693.2258-3.5611.06598-20.108.06598-20.108s-.03406-.98114 16.665-.98698c16.626 0 16.665.98698 16.665.98698s-.15981 16.547.06598 20.107c.15174 3.7756-2.0658 15.693-16.733 15.693" fill="#feff00" fill-opacity=".25098" fill-rule="evenodd"/></svg>
src/main/resources/images/mouse/l.svg
+<svg viewBox="0 0 35 60" xmlns="http://www.w3.org/2000/svg"><path d="m18.124 19.65v-4.9429h5.6695v-6.1788h-5.6743v-4.9432l-6.9166 8.0327z" fill="#333" fill-opacity=".8"/></svg>
src/main/resources/images/mouse/r.svg
+<svg viewBox="0 0 35 60" xmlns="http://www.w3.org/2000/svg"><path d="m16.872 19.65v-4.9429h-5.6695v-6.1788h5.6743v-4.9432l6.9166 8.0327z" fill="#333" fill-opacity=".8"/></svg>
src/main/resources/images/mouse/u.svg
+<svg viewBox="0 0 35 60" xmlns="http://www.w3.org/2000/svg"><path d="m9.4655 12.243h4.9429v5.6695h6.1788v-5.6743h4.9432l-8.0327-6.9166z" fill="#333" fill-opacity=".8"/></svg>
src/main/resources/images/mouse/undefined.svg
-<svg viewBox="0 0 35 60" xmlns="http://www.w3.org/2000/svg"><path d="m17.502 59.388c-14.667 0-16.886-11.917-16.733-15.693.2258-3.5611.06598-20.108.06598-20.108s-.03406-.98114 16.665-.98698c16.626 0 16.665.98698 16.665.98698s-.15981 16.547.06598 20.107c.15174 3.7756-2.0658 15.693-16.733 15.693" fill="#feff00" fill-opacity=".25098" fill-rule="evenodd"/></svg>
+
Delta370 lines added, 224 lines removed, 146-line increase