Important Notice - Forums is archived
To simplify things and help our users to be more productive, we have archived the current forum and focus our efforts on helping developers on Stack Overflow. You can post new questions on Stack Overflow or join our Discord channel.

Vaadin lets you build secure, UX-first PWAs entirely in Java.
Free ebook & tutorial.
Many click events while key down on a Button
Hallo,
when you have a Button and you press a key without releasing it you get a lot of click events (ClickListener is activated). Is there any possibility to change this behaviour? I only want to have one click event, if the key is down for a second or for five minutes.
Thanks for any hints,
Philipp
I think this is the standard behaviour of key down event.
As a workaround you can try to use a client side extension that checks the repeated attribute of the keydown event;
beware that this may not work on all browsers (as stated in Event class javadocs)
public class UIExtension extends AbstractExtension {
public UIExtension(UI target) { super(target); }
}
@Connect(UIExtension.class)
public class UIExtensionConnector extends AbstractExtensionConnector {
@Override protected void extend(ServerConnector target) {
UIConnector uiConnector = (UIConnector)target;
uiConnector.getWidget().actionHandler = new MyShortcuActionHandler( target.getConnectorId(), getConnection());
}
}
class MyShortcuActionHandler extends ShortcutActionHandler {
public MyShortcuActionHandler(String pid, ApplicationConnection c) {
super(pid, c);
}
@Override
public void handleKeyboardEvent(Event event, ComponentConnector target) {
if (!event.getRepeat()) {
super.handleKeyboardEvent(event, target);
}
}
}
and then extend your UI
protected void init(VaadinRequest vaadinRequest) {
...
new UIExtension(this);
...
}
HTH
Marco
Thanks,
it is a nice solution and so far I had no knowledge about UIExtension. But if it is not working on all browsers it is worthless :-(
I also created a workaround for that problem. It also has the feature that you can add a handler for button down and button up (standard click handler is still available). It also has the feature like many desktop buttons, if you press mouse down on the button, move the mouse somewhere else and release it afterwards, the button up handler is not informed.
For that I extended Button on server side and ButtonConnector on client side:
The ButtonConnector extension (most interesting part according the asked question):
@Connect( MyButton.class )
public class MyButtonConnectorConnector
extends ButtonConnector
implements MouseDownHandler, MouseUpHandler, KeyDownHandler, KeyUpHandler
{
private final MyButtonRpcRpc vRpc = RpcProxy.create( MyButtonRpcRpc.class, this );
private boolean vButtonDown;
private static final int C_KEYCODE_SPACE = 32;
public MyButtonConnectorConnector()
{
super();
vButtonDown = false;
}
@Override
public void init()
{
super.init();
getWidget().addMouseDownHandler( this );
getWidget().addMouseUpHandler( this );
getWidget().addKeyDownHandler( this );
getWidget().addKeyUpHandler( this );
}
@Override
public void onMouseDown( final MouseDownEvent pEvent )
{
final boolean buttonDownBefore = setButtonDown( true );
if ( buttonDownBefore ) {
return;
}
final MouseEventDetails details = MouseEventDetailsBuilder.buildMouseEventDetails(
pEvent.getNativeEvent(), getWidget().getElement() );
vRpc.down( details );
}
@Override
public void onMouseUp( final MouseUpEvent pEvent )
{
final int yRelativeButton = pEvent.getRelativeY( this.getWidget().getElement() );
final int xRelativeButton = pEvent.getRelativeX( this.getWidget().getElement() );
final boolean buttonDownBefore = setButtonDown( false );
final int width = getWidget().getOffsetWidth();
final int height = getWidget().getOffsetHeight();
// Befindet sich die Maus noch ĂĽber dem Knopf?
if ( yRelativeButton >= 0 && yRelativeButton <= height
&& xRelativeButton >= 0 && xRelativeButton <= width )
{
if ( !buttonDownBefore ) {
return;
}
final MouseEventDetails details = MouseEventDetailsBuilder.buildMouseEventDetails(
pEvent.getNativeEvent(), getWidget().getElement() );
vRpc.up( details );
}
else {
setButtonDown( true );
}
}
@Override
public void onKeyDown( final KeyDownEvent pEvent )
{
if ( pEvent.getNativeKeyCode() == KeyCodes.KEY_ENTER
|| pEvent.getNativeKeyCode() == C_KEYCODE_SPACE )
{
final boolean buttonDownBefore = setButtonDown( true );
if ( buttonDownBefore ) {
return;
}
final MouseEventDetails details = MouseEventDetailsBuilder.buildMouseEventDetails(
pEvent.getNativeEvent(), getWidget().getElement() );
vRpc.down( details );
}
}
@Override
public void onKeyUp( final KeyUpEvent pEvent )
{
if ( pEvent.getNativeKeyCode() == KeyCodes.KEY_ENTER
|| pEvent.getNativeKeyCode() == C_KEYCODE_SPACE )
{
final boolean buttonDownBefore = setButtonDown( false );
if ( !buttonDownBefore ) {
return;
}
final MouseEventDetails details = MouseEventDetailsBuilder.buildMouseEventDetails(
pEvent.getNativeEvent(), getWidget().getElement() );
vRpc.up( details );
}
}
private synchronized boolean setButtonDown( final boolean pButtonDown )
{
final boolean old = vButtonDown;
vButtonDown = pButtonDown;
return old;
}
}
ServerRpc:
public interface MyButtonRpcRpc
extends ServerRpc
{
public void down( MouseEventDetails pDetails );
public void up( MouseEventDetails pDetails );
}
Button extension:
public class MyButton
extends Button
{
private final MyButtonRpcRpc vRpc = new MyButtonRpcRpc()
{
@Override
public void down( final MouseEventDetails pDetails )
{
fireButtonDown( pDetails );
}
@Override
public void up( final MouseEventDetails pDetails )
{
fireButtonUp( pDetails );
}
};
public MyButton()
{
super();
registerRpc( vRpc );
}
public MyButton( final String pCaption )
{
super( pCaption );
registerRpc( vRpc );
}
public MyButton(
final String pCaption,
final MyButtonUpListener pListener )
{
this( pCaption );
addButtonUpListener( pListener );
}
/**
* @deprecated Instead use {@link #adButtonDownListener(MyButtonDownListener)}
* or {@link #addButtonUpListener(MyButtonUpListener)}
*
* @see #adButtonDownListener(MyButtonDownListener)
* @see #addButtonUpListener(MyButtonUpListener)
*/
@Override
@Deprecated
public void addClickListener( final ClickListener pListener )
{
super.addClickListener( pListener );
}
public void adButtonDownListener( final MyButtonDownListener pListener )
{
addListener( MyButtonDownEvent.class, pListener, MyButtonDownListener.BUTTON_DOWN_METHOD );
}
public void removeButtonDownListener( final MyButtonDownListener pListener )
{
removeListener( MyButtonDownEvent.class, pListener, MyButtonDownListener.BUTTON_DOWN_METHOD );
}
public void removeButtonDownListeners()
{
final Collection<?> listeners = getListeners( MyButtonDownEvent.class );
for ( final Object listener : listeners )
{
removeButtonDownListener( (MyButtonDownListener)listener );
}
listeners.clear();
}
public void addButtonUpListener( final MyButtonUpListener pListener )
{
addListener( MyButtonUpEvent.class, pListener, MyButtonUpListener.BUTTON_UP_METHOD );
}
public void removeButtonUpListener( final MyButtonUpListener pListener )
{
removeListener(
MyButtonUpEvent.class, pListener, MyButtonUpListener.BUTTON_UP_METHOD );
}
public void removeButtonUpListeners()
{
final Collection<?> listeners = getListeners( MyButtonUpEvent.class );
for ( final Object listener : listeners )
{
removeButtonUpListener( (MyButtonUpListener)listener );
}
listeners.clear();
}
protected void fireButtonDown( final MouseEventDetails pDetails )
{
fireEvent( new MyButtonDownEvent( this, pDetails ) );
}
protected void fireButtonUp( final MouseEventDetails pDetails )
{
fireEvent( new MyButtonUpEvent( this, pDetails ) );
}
public interface MyButtonDownListener
extends Serializable
{
public static final Method BUTTON_DOWN_METHOD = ReflectTools.findMethod(
MyButtonDownListener.class,
"buttonDown",
MyButtonDownEvent.class );
public void buttonDown( final MyButtonDownEvent pEvent );
}
public interface MyButtonUpListener
extends Serializable
{
public static final Method BUTTON_UP_METHOD = ReflectTools.findMethod(
MyButtonUpListener.class,
"buttonUp",
MyButtonUpEvent.class );
public void buttonUp( final MyButtonUpEvent pEvent );
}
public static class MyButtonDownEvent
extends Component.Event
{
private final MouseEventDetails vDetails;
public MyButtonDownEvent(
final Component pSource )
{
super( pSource );
vDetails = null;
}
public MyButtonDownEvent(
final Component pSource,
final MouseEventDetails pDetails )
{
super( pSource );
vDetails = pDetails;
}
public MyButton getButton()
{
return (MyButton)getSource();
}
public int getClientX()
{
if ( null != vDetails ) {
return vDetails.getClientX();
}
else {
return -1;
}
}
public int getClientY()
{
if ( null != vDetails ) {
return vDetails.getClientY();
}
else {
return -1;
}
}
public int getRelativeX()
{
if ( null != vDetails ) {
return vDetails.getRelativeX();
}
else {
return -1;
}
}
public int getRelativeY()
{
if ( null != vDetails ) {
return vDetails.getRelativeY();
}
else {
return -1;
}
}
public boolean isAltKey()
{
if ( null != vDetails ) {
return vDetails.isAltKey();
}
else {
return false;
}
}
public boolean isCtrlKey()
{
if ( null != vDetails )
{
return vDetails.isCtrlKey();
}
else {
return false;
}
}
public boolean isMetaKey()
{
if ( null != vDetails ) {
return vDetails.isMetaKey();
}
else {
return false;
}
}
public boolean isShiftKey()
{
if ( null != vDetails ) {
return vDetails.isShiftKey();
}
else {
return false;
}
}
}
public static class MyButtonUpEvent
extends Component.Event
{
private final MouseEventDetails vDetails;
public MyButtonUpEvent(
final Component pSource )
{
super( pSource );
vDetails = null;
}
public MyButtonUpEvent(
final Component pSource,
final MouseEventDetails pDetails )
{
super( pSource );
vDetails = pDetails;
}
public MyButton getButton()
{
return (MyButton)getSource();
}
public int getClientX()
{
if ( null != vDetails ) {
return vDetails.getClientX();
}
else {
return -1;
}
}
public int getClientY()
{
if ( null != vDetails ) {
return vDetails.getClientY();
}
else {
return -1;
}
}
public int getRelativeX()
{
if ( null != vDetails ) {
return vDetails.getRelativeX();
}
else {
return -1;
}
}
public int getRelativeY()
{
if ( null != vDetails ) {
return vDetails.getRelativeY();
}
else {
return -1;
}
}
public boolean isAltKey()
{
if ( null != vDetails ) {
return vDetails.isAltKey();
}
else {
return false;
}
}
public boolean isCtrlKey()
{
if ( null != vDetails )
{
return vDetails.isCtrlKey();
}
else {
return false;
}
}
public boolean isMetaKey()
{
if ( null != vDetails ) {
return vDetails.isMetaKey();
}
else {
return false;
}
}
public boolean isShiftKey()
{
if ( null != vDetails ) {
return vDetails.isShiftKey();
}
else {
return false;
}
}
}
}
Very interesting solution; could be an idea for an addon
Best regards
Marco
Thanks.
If you have a nice name for the addon/button and you think it is also needed by others I can try to build an "official" addon. I also would add some comments. Something more?