I'm looking into <an issue> where `PointerButton` ...
# compose-desktop
e
I'm looking into an issue where
PointerButton
isn't mapped to the values that Compose expects it to be on Ubuntu with an MX Master 3 mouse. I'd greatly appreciate it if anyone could try this Modifier with other combinations of mice and OSes and report if they have similar or different results šŸ™
Copy code
Modifier
    .onClick(matcher = PointerMatcher.mouse(PointerButton(0)), onClick = { println("Mouse Left") })
    .onClick(matcher = PointerMatcher.mouse(PointerButton(1)), onClick = { println("Mouse Right") })
    .onClick(matcher = PointerMatcher.mouse(PointerButton(2)), onClick = { println("Mouse Middle") })
    .onClick(matcher = PointerMatcher.mouse(PointerButton(3)), onClick = { println("Horizontal Scroll Right") })
    .onClick(matcher = PointerMatcher.mouse(PointerButton(4)), onClick = { println("Horizontal Scroll Left") })
    .onClick(matcher = PointerMatcher.mouse(PointerButton(5)), onClick = { println("Mouse Back") })
    .onClick(matcher = PointerMatcher.mouse(PointerButton(6)), onClick = { println("Mouse Front") })
    .onClick(matcher = PointerMatcher.mouse(PointerButton(7)), onClick = { println("Mouse Thumb") })
o
Thanks for adding a case with onClick. Would you please add here the details about what results you have with your OS and your mouse when you try the snippet with onClick?
e
Yes, I'll update when I try with different mice and OSes
c
I’ve got this mouse, I’ll give it a try on Macos Monterey
From what I can tell, the mouse buttons themselves work correctly if you configure them in Logi Options+, but if you leave it with the ā€œforwardā€ and ā€œbackā€ actions, I hit a native error (
Bad JNI lookup handleGestureFromNative
). I’ll post the full stacktrace in the Github issue
e
I'm getting a bunch of different mouse models to try, and I'll create a spreadsheet with the results.
I updated the
Modifier
to test handling different values for
PointerButton
across OSes (and potentially mice). Still only works on jvm:
Copy code
@OptIn(ExperimentalFoundationApi::class)
actual fun Modifier.onDesktopMouseEvent(
  keyboardModifiers: PointerKeyboardModifiers.() -> Boolean,
  onMouseLeftClick: (() -> Unit)?,
  onMouseLeftDoubleClick: (() -> Unit)?,
  onMouseLeftLongClick: (() -> Unit)?,
  mouseLeftKeyboardModifier: (PointerKeyboardModifiers.() -> Boolean)?,
  onMouseRightClick: (() -> Unit)?,
  onMouseRightDoubleClick: (() -> Unit)?,
  onMouseRightLongClick: (() -> Unit)?,
  mouseRightKeyboardModifier: (PointerKeyboardModifiers.() -> Boolean)?,
  onMouseMiddleClick: (() -> Unit)?,
  onMouseMiddleDoubleClick: (() -> Unit)?,
  onMouseMiddleLongClick: (() -> Unit)?,
  mouseMiddleKeyboardModifier: (PointerKeyboardModifiers.() -> Boolean)?,
  onMouseHorizontalLeftScrollClick: (() -> Unit)?,
  onMouseHorizontalLeftScrollDoubleClick: (() -> Unit)?,
  onMouseHorizontalLeftScrollLongClick: (() -> Unit)?,
  mouseHorizontalLeftKeyboardModifier: (PointerKeyboardModifiers.() -> Boolean)?,
  onMouseHorizontalRightScrollClick: (() -> Unit)?,
  onMouseHorizontalRightScrollDoubleClick: (() -> Unit)?,
  onMouseHorizontalRightScrollLongClick: (() -> Unit)?,
  mouseHorizontalRightKeyboardModifier: (PointerKeyboardModifiers.() -> Boolean)?,
  onMouseBackClick: (() -> Unit)?,
  onMouseBackDoubleClick: (() -> Unit)?,
  onMouseBackLongClick: (() -> Unit)?,
  mouseBackKeyboardModifier: (PointerKeyboardModifiers.() -> Boolean)?,
  onMouseForwardClick: (() -> Unit)?,
  onMouseForwardDoubleClick: (() -> Unit)?,
  onMouseForwardLongClick: (() -> Unit)?,
  mouseForwardKeyboardModifier: (PointerKeyboardModifiers.() -> Boolean)?,
  onMouseThumbClick: (() -> Unit)?,
  onMouseThumbDoubleClick: (() -> Unit)?,
  onMouseThumbLongClick: (() -> Unit)?,
  mouseThumbKeyboardModifier: (PointerKeyboardModifiers.() -> Boolean)?
): Modifier {
  fun Modifier.nextModifier(
    button: PointerButton,
    buttonKeyboardModifiers: (PointerKeyboardModifiers.() -> Boolean)?,
    click: (() -> Unit)?,
    doubleClick: (() -> Unit)?,
    longClick: (() -> Unit)?
  ) = if(click != null || doubleClick != null || longClick != null) {
    onClick(
      matcher = PointerMatcher.mouse(button),
      keyboardModifiers = buttonKeyboardModifiers ?: keyboardModifiers,
      onClick = click ?: {},
      onDoubleClick = doubleClick,
      onLongClick = longClick
    )
  }
  else {
    this
  }

  @Suppress("MaxChainedCallsOnSameLine")
  return nextModifier(
    button = PointerButton(0),
    buttonKeyboardModifiers = mouseLeftKeyboardModifier,
    click = onMouseLeftClick,
    doubleClick = onMouseLeftDoubleClick,
    longClick = onMouseLeftLongClick
  ).nextModifier(
    button = PointerButton(1),
    buttonKeyboardModifiers = mouseRightKeyboardModifier,
    click = onMouseRightClick,
    doubleClick = onMouseRightDoubleClick,
    longClick = onMouseRightLongClick
  ).nextModifier(
    button = PointerButton(2),
    buttonKeyboardModifiers = mouseMiddleKeyboardModifier,
    click = onMouseMiddleClick,
    doubleClick = onMouseMiddleDoubleClick,
    longClick = onMouseMiddleLongClick
  ).nextModifier(
    button = PointerButton(if(getOS() == OS.LINUX) 3 else 5),
    buttonKeyboardModifiers = mouseHorizontalLeftKeyboardModifier,
    click = onMouseHorizontalLeftScrollClick,
    doubleClick = onMouseHorizontalLeftScrollDoubleClick,
    longClick = onMouseHorizontalLeftScrollLongClick
  ).nextModifier(
    button = PointerButton(if(getOS() == OS.LINUX) 4 else 6),
    buttonKeyboardModifiers = mouseHorizontalRightKeyboardModifier,
    click = onMouseHorizontalRightScrollClick,
    doubleClick = onMouseHorizontalRightScrollDoubleClick,
    longClick = onMouseHorizontalRightScrollLongClick
  ).nextModifier(
    button = PointerButton(if(getOS() == OS.LINUX) 5 else 3),
    buttonKeyboardModifiers = mouseBackKeyboardModifier,
    click = onMouseBackClick,
    doubleClick = onMouseBackDoubleClick,
    longClick = onMouseBackLongClick
  ).nextModifier(
    button = PointerButton(if(getOS() == OS.LINUX) 6 else 4),
    buttonKeyboardModifiers = mouseForwardKeyboardModifier,
    click = onMouseForwardClick,
    doubleClick = onMouseForwardDoubleClick,
    longClick = onMouseForwardLongClick
  ).nextModifier(
    button = PointerButton(7),
    buttonKeyboardModifiers = mouseThumbKeyboardModifier,
    click = onMouseThumbClick,
    doubleClick = onMouseThumbDoubleClick,
    longClick = onMouseThumbLongClick
  ).nextModifier(
    button = PointerButton(8),
    buttonKeyboardModifiers = mouseThumbKeyboardModifier,
    click = onMouseThumbClick,
    doubleClick = onMouseThumbDoubleClick,
    longClick = onMouseThumbLongClick
  )
}

private enum class OS {
  WINDOWS, LINUX, MAC, UNKNOWN
}

private fun getOS(): OS {
  val os = System.getProperty("os.name").lowercase(<http://Locale.US|Locale.US>)
  return when {
    os.contains("win") -> {
      OS.WINDOWS
    }

    os.contains("nix") || os.contains("nux") || os.contains("aix") -> {
      OS.LINUX
    }

    os.contains("mac") -> {
      OS.MAC
    }

    else -> OS.UNKNOWN
  }
}
Usage:
Copy code
modifier = Modifier.onDesktopMouseEvent(
        onMouseLeftClick = {
          println("onMouseLeftClick")
        },
        onMouseLeftDoubleClick = {
          println("onMouseLeftDoubleClick")
        },
        onMouseLeftLongClick = {
          println("onMouseLeftLongClick")
        },
        onMouseRightClick = {
          println("onMouseRightClick")
        },
        onMouseRightDoubleClick = {
          println("onMouseRightDoubleClick")
        },
        onMouseRightLongClick = {
          println("onMouseRightLongClick")
        },
        onMouseMiddleClick = {
          println("onMouseMiddleClick")
        },
        onMouseMiddleDoubleClick = {
          println("onMouseMiddleDoubleClick")
        },
        onMouseMiddleLongClick = {
          println("onMouseMiddleLongClick")
        },
        onMouseHorizontalLeftScrollClick = {
          println("onMouseHorizontalLeftScrollClick")
        },
        onMouseHorizontalLeftScrollDoubleClick = {
          println("onMouseHorizontalLeftScrollDoubleClick ")
        },
        onMouseHorizontalLeftScrollLongClick = {
          println("onMouseHorizontalLeftScrollLongClick ")
        },
        onMouseHorizontalRightScrollClick = {
          println("onMouseHorizontalRightScrollClick ")
        },
        onMouseHorizontalRightScrollDoubleClick = {
          println("onMouseHorizontalRightScrollDoubleClick ")
        },
        onMouseHorizontalRightScrollLongClick = {
          println("onMouseHorizontalRightScrollLongClick ")
        },
        onMouseBackClick = {
          println("onMouseBackClick")
        },
        onMouseBackDoubleClick = {
          println("onMouseBackDoubleClick")
        },
        onMouseBackLongClick = {
          println("onMouseBackLongClick")
        },
        onMouseForwardClick = {
          println("onMouseForwardClick")
        },
        onMouseForwardDoubleClick = {
          println("onMouseForwardDoubleClick")
        },
        onMouseForwardLongClick = {
          println("onMouseForwardLongClick")
        },
        onMouseThumbClick = {
          println("onMouseThumbClick")
        },
        onMouseThumbDoubleClick = {
          println("onMouseThumbDoubleClick")
        },
        onMouseThumbLongClick = {
          println("onMouseThumbLongClick")
        }
)
Trying this again over a year later in Compose 1.6.0 alpha and now mouse forward and back buttons don't work on Linux at all 😬