Compare commits

..

1 Commits

Author SHA1 Message Date
Vitaly Provodin
8b739ff937 update exclude list on results of 21.0.4_b620.4 test runs 2024-10-07 08:12:19 +04:00
18 changed files with 505 additions and 712 deletions

View File

@@ -0,0 +1,43 @@
# NOTE: This Dockerfile is meant to be used from the mkdocker_musl_aarch64.sh script.
# Pull a concrete version of Linux that does NOT recieve updates after it's
# been created. This is so that the image is as stable as possible to make
# image creation reproducible.
# NB: this also means there may be no security-related fixes there, need to
# move the version to the next manually.
FROM arm64v8/alpine:3.14
# Install the necessary build tools
RUN apk --no-cache add --update \
alsa-lib-dev=1.2.5-r2 \
autoconf=2.71-r0 \
bash=5.1.16-r0 \
build-base=0.5-r3 \
bzip2=1.0.8-r1 \
cups-dev=2.3.3-r3 \
file=5.40-r1 \
fontconfig=2.13.1-r4 \
fontconfig-dev=2.13.1-r4 \
freetype-dev=2.10.4-r3 \
git=2.32.7-r0 \
grep=3.7-r0 \
libx11-dev=1.7.3.1-r0 \
libxext-dev=1.3.4-r0 \
libxrandr-dev=1.5.2-r1 \
libxrender-dev=0.9.10-r3 \
libxt-dev=1.2.1-r0 \
libxtst-dev=1.2.3-r3 \
linux-headers=5.10.41-r0 \
rsync=3.2.5-r0 \
tar=1.34-r1 \
wayland-dev=1.19.0-r0 \
zip=3.0-r9
# Set up boot JDK for building
COPY boot_jdk_musl_aarch64.tar.gz /jdk20/
RUN cd /jdk20 && tar --strip-components=1 -xzf boot_jdk_musl_aarch64.tar.gz && rm /jdk20/boot_jdk_musl_aarch64.tar.gz
ENV BOOT_JDK=/jdk20
RUN git config --global user.email "teamcity@jetbrains.com" && \
git config --global user.name "builduser" && \
git config --global --add safe.directory '*'

View File

@@ -1,4 +1,4 @@
# NOTE: This Dockerfile is meant to be used from the mkdocker_musl_<arch>.sh script.
# NOTE: This Dockerfile is meant to be used from the mkdocker_musl_x64.sh script.
# Pull a concrete version of Linux that does NOT recieve updates after it's
# been created. This is so that the image is as stable as possible to make
@@ -31,12 +31,12 @@ RUN apk --no-cache add --update \
rsync=3.2.5-r0 \
tar=1.34-r1 \
wayland-dev=1.19.0-r0 \
zip=3.0-r9 \
vulkan-headers=1.2.170-r0 \
vulkan-loader-dev=1.2.170-r1 \
glslang=8.13.3743-r1
zip=3.0-r9
# Set up boot JDK for building
COPY boot_jdk_musl_amd64.tar.gz /jdk20/
RUN cd /jdk20 && tar --strip-components=1 -xzf boot_jdk_musl_amd64.tar.gz && rm /jdk20/boot_jdk_musl_amd64.tar.gz
ENV BOOT_JDK=/jdk20
RUN git config --global user.email "teamcity@jetbrains.com" && \
git config --global user.name "builduser" && \
git config --global --add safe.directory '*' && \
git config --global http.postBuffer 524288000
git config --global user.name "builduser"

View File

@@ -1,63 +0,0 @@
# NOTE: This Dockerfile is meant to be used from the mkdocker_<arch>.sh script.
# Pull a concrete version of Linux that does NOT recieve updates after it's
# been created. This is so that the image is as stable as possible to make
# image creation reproducible.
# NB: this also means there may be no security-related fixes there, need to
# move the version to the next manually.
FROM oraclelinux:8
# Install the necessary build tools
RUN yum -y update; \
yum -y install gcc-toolset-10-10.1-0.el8; \
yum -y install \
alsa-lib-devel-1.1.9-4.el8 \
autoconf-2.69-29.el8_10.1 \
automake-1.16.1-6.el8 \
bzip2-libs-1.0.6-26.el8 \
cups-devel-2.2.6-60.el8_10 \
file-5.33-26.el8 \
fontconfig-devel-2.13.1-4.el8 \
freetype-devel-2.9.1-9.el8 \
gcc-c++-8.5.0-22.0.1.el8_10 \
git-2.43.5-1.el8_10 \
git-core-2.43.5-1.el8_10 \
libtool-2.4.6-25.el8 \
libXi-devel-1.7.10-1.el8 \
libXrandr-devel-1.5.2-1.el8 \
libXrender-devel-0.9.10-7.el8 \
libXt-devel-1.1.5-12.el8 \
libXtst-devel-1.2.3-7.el8 \
make-devel-4.2.1-11.el8 \
rsync-3.1.3-19.el8_7.1 \
unzip-6.0-46.el8 \
wayland-devel-1.21.0-1.el8 \
python36-3.6.8-39.module+el8.10.0+90274+07ba55de \
cmake-3.26.5-2.el8 \
vulkan-headers-1.3.250.1-1.el8 \
vulkan-loader-devel-1.3.250.1-1.el8 \
vulkan-validation-layers-1.3.250.1-1.el8; \
yum -y clean all
RUN git config --global user.email "teamcity@jetbrains.com" && \
git config --global user.name "builduser" && \
git config --global --add safe.directory '*' && \
git config --global http.postBuffer 524288000
# Build GLSLC
RUN git clone https://github.com/google/shaderc --branch v2023.6 \
&& cd shaderc \
&& ./utils/git-sync-deps \
&& mkdir build \
&& cd build \
&& cmake \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DSHADERC_SKIP_TESTS=ON \
-DSHADERC_SKIP_EXAMPLES=ON \
-DSHADERC_SKIP_COPYRIGHT_CHECK=ON \
-DSPIRV_SKIP_EXECUTABLES=ON \
-DENABLE_SPVREMAPPER=OFF \
.. \
&& make install

View File

@@ -0,0 +1,44 @@
# NOTE: This Dockerfile is meant to be used from the mkdocker_aarch64.sh script.
# Pull a concrete version of Linux that does NOT recieve updates after it's
# been created. This is so that the image is as stable as possible to make
# image creation reproducible.
# NB: this also means there may be no security-related fixes there, need to
# move the version to the next manually.
FROM arm64v8/oraclelinux:8
# Install the necessary build tools
RUN yum -y update; \
yum -y install gcc-toolset-10-10.1-0.el8.aarch64; \
yum -y install \
alsa-lib-devel-1.1.9-4.el8.aarch64 \
autoconf-2.69-29.el8_10.1.noarch \
automake-1.16.1-6.el8.noarch \
bzip2-libs-1.0.6-26.el8.aarch64 \
cups-devel-2.2.6-60.el8_10.aarch64 \
file-5.33-26.el8.aarch64 \
fontconfig-devel-2.13.1-4.el8.aarch64 \
freetype-devel-2.9.1-9.el8.aarch64 \
gcc-c++-8.5.0-22.0.1.el8_10.aarch64 \
git-2.43.5-1.el8_10.aarch64 \
git-core-2.43.5-1.el8_10.aarch64 \
libtool-2.4.6-25.el8.aarch64 \
libXi-devel-1.7.10-1.el8.aarch64 \
libXrandr-devel-1.5.2-1.el8.aarch64 \
libXrender-devel-0.9.10-7.el8.aarch64 \
libXt-devel-1.1.5-12.el8.aarch64 \
libXtst-devel-1.2.3-7.el8.aarch64 \
make-devel-4.2.1-11.el8.aarch64 \
rsync-3.1.3-19.el8_7.1.aarch64 \
unzip-6.0-46.el8.aarch64 \
wayland-devel-1.21.0-1.el8.aarch64; \
yum -y clean all
RUN git config --global user.email "teamcity@jetbrains.com" && \
git config --global user.name "builduser"
ENV PATH="/opt/rh/devtoolset-10/root/usr/bin:${PATH}"
ENV LD_LIBRARY_PATH="/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib"
ENV PKG_CONFIG_PATH="/opt/rh/devtoolset-10/root/usr/lib64/pkgconfig"

View File

@@ -0,0 +1,45 @@
# NOTE: This Dockerfile is meant to be used from the mkdocker_x86_64.sh script.
# Pull a concrete version of Linux that does NOT recieve updates after it's
# been created. This is so that the image is as stable as possible to make
# image creation reproducible.
# NB: this also means there may be no security-related fixes there, need to
# move the version to the next manually.
FROM amd64/oraclelinux:8
# Install the necessary build tools
RUN yum -y update; \
yum -y install gcc-toolset-10-10.1-0.el8.x86_64; \
yum -y install \
alsa-lib-devel-1.1.9-4.el8.x86_64 \
autoconf-2.69-29.el8_10.1.noarch \
automake-1.16.1-6.el8.noarch \
bzip2-libs-1.0.6-26.el8.x86_64 \
cups-devel-2.2.6-60.el8_10.x86_64 \
file-5.33-26.el8.x86_64 \
fontconfig-devel-2.13.1-4.el8.x86_64 \
freetype-devel-2.9.1-9.el8.x86_64 \
gcc-c++-8.5.0-22.0.1.el8_10.x86_64 \
git-2.43.5-1.el8_10.x86_64 \
git-core-2.43.5-1.el8_10.x86_64 \
libtool-2.4.6-25.el8.x86_64 \
libXi-devel-1.7.10-1.el8.x86_64 \
libXrandr-devel-1.5.2-1.el8.x86_64 \
libXrender-devel-0.9.10-7.el8.x86_64 \
libXt-devel-1.1.5-12.el8.x86_64 \
libXtst-devel-1.2.3-7.el8.x86_64 \
make-devel-4.2.1-11.el8.x86_64 \
rsync-3.1.3-19.el8_7.1.x86_64 \
unzip-6.0-46.el8.x86_64 \
wayland-devel-1.21.0-1.el8.x86_64 \
python36-3.6.8-39.module+el8.10.0+90274+07ba55de; \
yum -y clean all
RUN git config --global user.email "teamcity@jetbrains.com" && \
git config --global user.name "builduser" && \
git config --global --add safe.directory '*'
ENV PATH="/opt/rh/devtoolset-10/root/usr/bin:${PATH}"
ENV LD_LIBRARY_PATH="/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib:/opt/rh/devtoolset-10/root/usr/lib64/dyninst:/opt/rh/devtoolset-10/root/usr/lib/dyninst:/opt/rh/devtoolset-10/root/usr/lib64:/opt/rh/devtoolset-10/root/usr/lib"
ENV PKG_CONFIG_PATH="/opt/rh/devtoolset-10/root/usr/lib64/pkgconfig"

View File

@@ -46,5 +46,10 @@ RUN linux32 \
apt-get clean -qy && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Set up boot JDK for building
COPY boot_jdk_x86.tar.gz /jdk17/
RUN cd /jdk17 && tar --strip-components=1 -xzf boot_jdk_x86.tar.gz && rm /jdk17/boot_jdk_x86.tar.gz
ENV BOOT_JDK=/jdk17
RUN git config --global user.email "teamcity@jetbrains.com" && \
git config --global user.name "builduser"

View File

@@ -1,10 +1,27 @@
#!/bin/bash
set -euxo pipefail
set -euo pipefail
set -x
# This script creates a Docker image suitable for building AArch64 variant
docker build --platform=linux/aarch64 -t jetbrains/runtime:oraclelinux8_aarch64 -f Dockerfile.oraclelinux .
BOOT_JDK_REMOTE_FILE=https://cdn.azul.com/zulu/bin/zulu21.36.17-ca-jdk21.0.4-linux_aarch64.tar.gz
BOOT_JDK_SHA=da3c2d7db33670bcf66532441aeb7f33dcf0d227c8dafe7ce35cee67f6829c4c
BOOT_JDK_LOCAL_FILE=boot_jdk.tar.gz
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
# Obtain "boot JDK" from outside of the container.
wget -nc https://cdn.azul.com/zulu/bin/${BOOT_JDK_REMOTE_FILE} -O $BOOT_JDK_LOCAL_FILE
else
echo "boot JDK \"$BOOT_JDK_LOCAL_FILE\" present, skipping download"
fi
# Verify that what we've downloaded can be trusted.
sha256sum -c - <<EOF
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
EOF
docker build -t jetbrains/runtime:jbr21env_oraclelinux8_aarch64 -f Dockerfile.oraclelinux_aarch64 .
# NB: the resulting container can (and should) be used without the network
# connection (--network none) during build in order to reduce the chance

View File

@@ -1,10 +1,28 @@
#!/bin/bash
set -euxo pipefail
set -euo pipefail
set -x
# This script creates a Docker image suitable for building musl AArch64 variant
# of the JetBrains Runtime version 21.
docker build --platform=linux/aarch64 -t jetbrains/runtime:alpine14_aarch64 -f Dockerfile.alpine .
BOOT_JDK_REMOTE_FILE=zulu20.32.11-ca-jdk20.0.2-linux_musl_aarch64.tar.gz
BOOT_JDK_SHA=eec57cf744c2438f695221f041d4804de3033ad33b6dba769d3359813ba3f90d
BOOT_JDK_LOCAL_FILE=boot_jdk_musl_aarch64.tar.gz
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
# Obtain "boot JDK" from outside of the container.
wget -nc https://cdn.azul.com/zulu/bin/${BOOT_JDK_REMOTE_FILE} -O $BOOT_JDK_LOCAL_FILE
else
echo "boot JDK \"$BOOT_JDK_LOCAL_FILE\" present, skipping download"
fi
# Verify that what we've downloaded can be trusted.
sha256sum -c - <<EOF
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
EOF
docker build -t jetbrains/runtime:jbr21env_musl_aarch64 -f Dockerfile.musl_aarch64 .
# NB: the resulting container can (and should) be used without the network
# connection (--network none) during build in order to reduce the chance

View File

@@ -1,10 +1,28 @@
#!/bin/bash
set -euxo pipefail
set -euo pipefail
set -x
# This script creates a Docker image suitable for building musl x64 variant
# This script creates a Docker image suitable for building musl-x64 variant
# of the JetBrains Runtime version 21.
docker build --platform=linux/amd64 -t jetbrains/runtime:alpine14_x64 -f Dockerfile.alpine .
BOOT_JDK_REMOTE_FILE=zulu20.32.11-ca-jdk20.0.2-linux_musl_x64.tar.gz
BOOT_JDK_SHA=fca5081dd6da847fcd06f5b755e58edae22d6784f21b81bf73da2b538f842c07
BOOT_JDK_LOCAL_FILE=boot_jdk_musl_amd64.tar.gz
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
# Obtain "boot JDK" from outside of the container.
wget -nc https://cdn.azul.com/zulu/bin/${BOOT_JDK_REMOTE_FILE} -O $BOOT_JDK_LOCAL_FILE
else
echo "boot JDK \"$BOOT_JDK_LOCAL_FILE\" present, skipping download"
fi
# Verify that what we've downloaded can be trusted.
sha256sum -c - <<EOF
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
EOF
docker build -t jetbrains/runtime:jbr21env_musl_x64 -f Dockerfile.musl_x64 .
# NB: the resulting container can (and should) be used without the network
# connection (--network none) during build in order to reduce the chance

View File

@@ -1,11 +0,0 @@
#!/bin/bash
set -euxo pipefail
# This script creates a Docker image suitable for building x64 variant
docker build --platform=linux/amd64 -t jetbrains/runtime:oraclelinux8_x64 -f Dockerfile.oraclelinux .
# NB: the resulting container can (and should) be used without the network
# connection (--network none) during build in order to reduce the chance
# of build contamination.

View File

@@ -1,10 +1,25 @@
#!/bin/bash
set -euxo pipefail
#!/bin/bash -x
# This script creates a Docker image suitable for building x86 variant
# of the JetBrains Runtime version 17.
docker build --platform=linux/i386 -t jetbrains/runtime:ubuntu2004_x86 -f Dockerfile.ubuntu.x86 .
BOOT_JDK_REMOTE_FILE=zulu17.34.19-ca-jdk17.0.3-linux_i686.tar.gz
BOOT_JDK_SHA=1c35c374ba0001e675d6e80819d5be900c4e141636d5e484992a8c550be14481
BOOT_JDK_LOCAL_FILE=boot_jdk_x86.tar.gz
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
# Obtain "boot JDK" from outside of the container.
wget -nc https://cdn.azul.com/zulu/bin/${BOOT_JDK_REMOTE_FILE} -O $BOOT_JDK_LOCAL_FILE
else
echo "boot JDK \"$BOOT_JDK_LOCAL_FILE\" present, skipping download"
fi
# Verify that what we've downloaded can be trusted.
sha256sum -c - <<EOF
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
EOF
docker build -t jetbrains/runtime:jbr17env_x86 -f Dockerfile.x86 .
# NB: the resulting container can (and should) be used without the network
# connection (--network none) during build in order to reduce the chance

View File

@@ -0,0 +1,28 @@
#!/bin/bash
set -euo pipefail
set -x
# This script creates a Docker image suitable for building x86-64 variant
BOOT_JDK_REMOTE_FILE=zulu21.36.17-ca-jdk21.0.4-linux_x64.tar.gz
BOOT_JDK_SHA=318d0c2ed3c876fb7ea2c952945cdcf7decfb5264ca51aece159e635ac53d544
BOOT_JDK_LOCAL_FILE=boot_jdk.tar.gz
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
# Obtain "boot JDK" from outside of the container.
wget -nc https://cdn.azul.com/zulu/bin/${BOOT_JDK_REMOTE_FILE} -O $BOOT_JDK_LOCAL_FILE
else
echo "boot JDK \"$BOOT_JDK_LOCAL_FILE\" present, skipping download"
fi
# Verify that what we've downloaded can be trusted.
sha256sum -c - <<EOF
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
EOF
docker build -t jetbrains/runtime:jbr21env_oraclelinux8_amd64 -f Dockerfile.oraclelinux_x86_64 .
# NB: the resulting container can (and should) be used without the network
# connection (--network none) during build in order to reduce the chance
# of build contamination.

View File

@@ -65,10 +65,6 @@ abstract class Mapping {
abstract void convertNonNull(AccessContext.Method context);
void cast(AccessContext.Method context) {
if (context.access().canAccess(to)) context.writer.visitTypeInsn(CHECKCAST, getInternalName(to));
}
abstract Mapping inverse();
void query(Query q) {}
@@ -150,22 +146,15 @@ abstract class Mapping {
else return new Array(m);
}
@Override
void convert(AccessContext.Method context) {
super.convert(context);
cast(context); // Explicitly cast to result type after non-null branch
}
@Override
void convertNonNull(AccessContext.Method context) {
final int TEMP_COUNTER_SLOT = 1; // Warning! We overwrite 1st local slot.
MethodVisitor m = context.writer;
Label loopStart = new Label(), loopEnd = new Label();
// Stack: fromArray -> toArray, fromArray, i=length
if (!context.access().canAccess(from)) m.visitTypeInsn(CHECKCAST, "[Ljava/lang/Object;");
m.visitInsn(DUP);
m.visitInsn(ARRAYLENGTH);
if (context.access().canAccess(to)) {
m.visitTypeInsn(ANEWARRAY, getInternalName(Objects.requireNonNull(to.componentType())));
} else context.invokeDynamic(MethodHandles.arrayConstructor(to));
if (context.access().canAccess(to)) m.visitTypeInsn(ANEWARRAY, getInternalName(to));
else context.invokeDynamic(MethodHandles.arrayConstructor(to));
m.visitInsn(SWAP);
m.visitInsn(DUP);
m.visitInsn(ARRAYLENGTH);
@@ -219,6 +208,9 @@ abstract class Mapping {
context.writer.visitMethodInsn(INVOKEINTERFACE,
"com/jetbrains/exported/JBRApiSupport$Proxy", "$getProxyTarget", "()Ljava/lang/Object;", true);
}
void cast(AccessContext.Method context) {
if (context.access().canAccess(to)) context.writer.visitTypeInsn(CHECKCAST, getInternalName(to));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

@@ -1,125 +0,0 @@
/*
* Copyright 2024 JetBrains s.r.o.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.lwawt.macosx;
import com.jetbrains.exported.JBRApi;
import java.awt.*;
import java.awt.desktop.SystemHotkey;
import java.awt.event.InputEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@JBRApi.Service
@JBRApi.Provides("SystemShortcuts")
public class JBRSystemShortcutsMacOS {
@JBRApi.Provides("SystemShortcuts.Shortcut")
public static class Shortcut {
private final int keyCode;
private final char keyChar;
private final int modifiers;
private final String id;
private final String description;
public Shortcut(int keyCode, char keyChar, int modifiers, String id, String description) {
this.keyCode = keyCode;
this.keyChar = keyChar;
this.modifiers = modifiers;
this.id = id;
this.description = description;
}
public int getKeyCode() {
return keyCode;
}
public char getKeyChar() {
return keyChar;
}
public int getModifiers() {
return modifiers;
}
public String getId() {
return id;
}
public String getDescription() {
return description;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Shortcut shortcut)) return false;
return keyCode == shortcut.keyCode && keyChar == shortcut.keyChar && modifiers == shortcut.modifiers && Objects.equals(id, shortcut.id) && Objects.equals(description, shortcut.description);
}
@Override
public int hashCode() {
return Objects.hash(keyCode, keyChar, modifiers, id, description);
}
@Override
public String toString() {
return "Shortcut{" +
"keyCode=" + keyCode +
", keyChar=" + (int)keyChar +
", modifiers=" + modifiers +
", id='" + id + '\'' +
", description='" + description + '\'' +
'}';
}
}
@JBRApi.Provided("SystemShortcuts.ChangeEventListener")
public interface ChangeEventListener {
void handleSystemShortcutsChangeEvent();
}
public Shortcut[] querySystemShortcuts() {
var hotkeys = SystemHotkey.readSystemHotkeys();
var result = new Shortcut[hotkeys.size()];
for (int i = 0; i < hotkeys.size(); ++i) {
var hotkey = hotkeys.get(i);
result[i] = new Shortcut(
hotkey.getKeyCode(),
hotkey.getKeyChar(),
hotkey.getModifiers(),
hotkey.getId(),
hotkey.getDescription()
);
}
return result;
}
public void setChangeListener(ChangeEventListener listener) {
SystemHotkey.setChangeEventHandler(listener::handleSystemShortcutsChangeEvent);
}
}

View File

@@ -36,7 +36,6 @@
#import "NSApplicationAWT.h"
#import "PropertiesUtilities.h"
#import "ApplicationDelegate.h"
#import "SystemHotkey.h"
#import "sun_lwawt_macosx_LWCToolkit.h"
@@ -250,8 +249,6 @@ static void setUpAWTAppKit(BOOL installObservers)
CFRelease(notBusyObserver);
setBusy(YES);
[SystemHotkey setUp];
}
JNIEnv* env = [ThreadUtilities getJNIEnv];

View File

@@ -1,34 +0,0 @@
// Copyright 2024 JetBrains s.r.o.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License version 2 only, as
// published by the Free Software Foundation. Oracle designates this
// particular file as subject to the "Classpath" exception as provided
// by Oracle in the LICENSE file that accompanied this code.
//
// This code is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// version 2 for more details (a copy is included in the LICENSE file that
// accompanied this code).
//
// You should have received a copy of the GNU General Public License version
// 2 along with this work; if not, write to the Free Software Foundation,
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
// or visit www.oracle.com if you need additional information or have any
// questions.
#ifndef JBR_SYSTEMHOTKEY_H
#define JBR_SYSTEMHOTKEY_H
#import <objc/NSObject.h>
@interface SystemHotkey : NSObject
+ (void)setUp;
@end
#endif //JBR_SYSTEMHOTKEY_H

View File

@@ -1,5 +1,3 @@
#include "SystemHotkey.h"
#import <Foundation/Foundation.h>
#import <Carbon/Carbon.h>
#import <Cocoa/Cocoa.h>
@@ -8,8 +6,6 @@
#import "java_awt_event_KeyEvent.h"
#include <jni.h>
#import <ThreadUtilities.h>
#import <JNIUtilities.h>
#include "jni_util.h"
@@ -117,159 +113,72 @@ static int symbolicHotKeysModifiers2java(int mask) {
return result;
}
enum ShortcutID {
Shortcut_FocusMenuBar = 7,
Shortcut_FocusDock = 8,
Shortcut_FocusActiveWindow = 9,
Shortcut_FocusToolbar = 10,
Shortcut_FocusFloatingWindow = 11,
Shortcut_ToggleKeyboardAccess = 12,
Shortcut_ChangeTabMode = 13,
Shortcut_ToggleZoom = 15,
Shortcut_ZoomIn = 17,
Shortcut_ZoomOut = 19,
Shortcut_InvertColors = 21,
Shortcut_ToggleZoomImageSmoothing = 23,
Shortcut_IncreaseContrast = 25,
Shortcut_DecreaseContrast = 26,
Shortcut_FocusNextApplicationWindow = 27,
Shortcut_ScreenshotToFile = 28,
Shortcut_ScreenshotToClipboard = 29,
Shortcut_ScreenshotAreaToFile = 30,
Shortcut_ScreenshotAreaToClipboard = 31,
Shortcut_ShowAllWindows = 32,
Shortcut_ShowApplicationWindows = 33,
Shortcut_ShowDesktop = 36,
Shortcut_ToggleDockHiding = 52,
Shortcut_DecreaseBrightness = 53,
Shortcut_IncreaseBrightness = 54,
Shortcut_FocusStatusMenu = 57,
Shortcut_ToggleVoiceOver = 59,
Shortcut_SelectPreviousInputSource = 60,
Shortcut_SelectNextInputSource = 61,
Shortcut_ShowSpotlight = 64,
Shortcut_ShowFinderSearch = 65,
Shortcut_SwitchToDesktopLeft = 79,
Shortcut_SwitchToDesktopRight = 81,
Shortcut_SwitchToDesktop1 = 118,
Shortcut_SwitchToDesktop2 = 119,
Shortcut_SwitchToDesktop3 = 120,
Shortcut_SwitchToDesktop4 = 121,
Shortcut_ShowContextualMenu = 159,
Shortcut_ShowLaunchpad = 160,
Shortcut_ShowAccessibilityControls = 162,
Shortcut_ShowNotificationCenter = 163,
Shortcut_ToggleDoNotDisturb = 175,
Shortcut_ToggleZoomFocusFollowing = 179,
Shortcut_ScreenshotOptions = 184,
Shortcut_OpenQuickNote = 190,
Shortcut_ToggleStageManager = 222,
Shortcut_TogglePresenterOverlayLarge = 223,
Shortcut_TogglePresenterOverlaySmall = 224,
Shortcut_ToggleLiveSpeech = 225,
Shortcut_ToggleLiveSpeechVisibility = 226,
Shortcut_PauseOrResumeLiveSpeech = 227,
Shortcut_CancelLiveSpeech = 228,
Shortcut_ToggleLiveSpeechPhrases = 229,
Shortcut_ToggleSpeakSelection = 230,
Shortcut_ToggleSpeakItemUnderPointer = 231,
Shortcut_ToggleTypingFeedback = 232,
};
static NSString * getAppleSymbolicHotKeysDescription(int hotKeyId) {
static NSDictionary * hotkeyId2DescMap = nil;
if (hotkeyId2DescMap == nil) {
hotkeyId2DescMap = [NSDictionary dictionaryWithObjectsAndKeys:
@"Move focus to the menu bar", [NSNumber numberWithInt:7],
@"Move focus to the Dock", [NSNumber numberWithInt:8],
@"Move focus to active or next window", [NSNumber numberWithInt:9],
@"Move focus to window toolbar", [NSNumber numberWithInt:10],
@"Move focus to floating window", [NSNumber numberWithInt:11],
@"Change the way Tab moves focus", [NSNumber numberWithInt:13],
@"Turn zoom on or off", [NSNumber numberWithInt:15],
@"Zoom in", [NSNumber numberWithInt:17],
@"Zoom out", [NSNumber numberWithInt:19],
@"Reverse Black and White", [NSNumber numberWithInt:21],
@"Turn image smoothing on or off", [NSNumber numberWithInt:23],
@"Increase Contrast", [NSNumber numberWithInt:25],
@"Decrease Contrast", [NSNumber numberWithInt:26],
@"Move focus to the next window in application", [NSNumber numberWithInt:27],
@"Save picture of screen as file", [NSNumber numberWithInt:28],
@"Copy picture of screen to clipboard", [NSNumber numberWithInt:29],
@"Save picture of selected area as file", [NSNumber numberWithInt:30],
@"Copy picture of selected area to clipboard", [NSNumber numberWithInt:31],
@"All Windows", [NSNumber numberWithInt:32],
@"Application Windows", [NSNumber numberWithInt:33],
@"All Windows (Slow)", [NSNumber numberWithInt:34],
@"Application Windows (Slow)", [NSNumber numberWithInt:35],
@"Desktop", [NSNumber numberWithInt:36],
@"Desktop (Slow)", [NSNumber numberWithInt:37],
@"Move focus to the window drawer", [NSNumber numberWithInt:51],
@"Turn Dock Hiding On/Off", [NSNumber numberWithInt:52],
@"Move focus to the status menus", [NSNumber numberWithInt:57],
@"Turn VoiceOver on / off", [NSNumber numberWithInt:59],
@"Select the previous input source", [NSNumber numberWithInt:60],
@"Select the next source in the Input Menu", [NSNumber numberWithInt:61],
@"Dashboard", [NSNumber numberWithInt:62],
@"Dashboard (Slow)", [NSNumber numberWithInt:63],
@"Show Spotlight search field", [NSNumber numberWithInt:64],
@"Show Spotlight window", [NSNumber numberWithInt:65],
@"Dictionary MouseOver", [NSNumber numberWithInt:70],
@"Hide and show Front Row", [NSNumber numberWithInt:73],
@"Activate Spaces", [NSNumber numberWithInt:75],
@"Activate Spaces (Slow)", [NSNumber numberWithInt:76],
@"Spaces Left", [NSNumber numberWithInt:79],
@"Spaces Right", [NSNumber numberWithInt:81],
@"Spaces Down", [NSNumber numberWithInt:83],
@"Spaces Up", [NSNumber numberWithInt:85],
@"Show Help Menu", [NSNumber numberWithInt:91],
@"Show Help Menu", [NSNumber numberWithInt:92],
@"Show Help Menu", [NSNumber numberWithInt:98],
@"Switch to Space 1", [NSNumber numberWithInt:118],
@"Switch to Space 2", [NSNumber numberWithInt:119],
@"Switch to Space 3", [NSNumber numberWithInt:120],
@"Switch to Space 4", [NSNumber numberWithInt:121],
@"Show Launchpad", [NSNumber numberWithInt:160],
@"Show Accessibility Controls", [NSNumber numberWithInt:162],
@"Show Notification Center", [NSNumber numberWithInt:163],
@"Turn Do-Not-Disturb On/Off", [NSNumber numberWithInt:175],
@"Turn focus following On/Off", [NSNumber numberWithInt:179],
nil
];
struct SymbolicHotKey {
// Unique human-readable identifier for the shortcut
const char* id;
[hotkeyId2DescMap retain];
}
// English-language description of the shortcut
const char* description;
// Whether this shortcut is enabled by default.
// Note that a shortcut can be enabled but not have any keys assigned
bool enabled;
// Character for shortcuts that are triggered based on the character value of the key,
// instead of its physical position on a keyboard. It's set to 65535 if it's unassigned.
int character;
// Virtual key code for the shortcut.
// This key code identifies a key on a keyboard independent of the logical layout used.
// It's set to 65535 if it's unassigned.
int key;
// Modifier mask using the NSEventModifierFlag* values for this shortcut
int modifiers;
// The first major version of macOS that has this shortcut or -1 if unknown.
int macOSVersion;
};
static const struct SymbolicHotKey defaultSymbolicHotKeys[] = {
[Shortcut_FocusMenuBar] = { "FocusMenuBar", "Move focus to the menu bar", YES, 65535, 120, 0x00840000, -1 },
[Shortcut_FocusDock] = { "FocusDock", "Move focus to the Dock", YES, 65535, 99, 0x00840000, -1 },
[Shortcut_FocusActiveWindow] = { "FocusActiveWindow", "Move focus to active or next window", YES, 65535, 118, 0x00840000, -1 },
[Shortcut_FocusToolbar] = { "FocusToolbar", "Move focus to window toolbar", YES, 65535, 96, 0x00840000, -1 },
[Shortcut_FocusFloatingWindow] = { "FocusFloatingWindow", "Move focus to floating window", YES, 65535, 97, 0x00840000, -1 },
[Shortcut_ToggleKeyboardAccess] = { "ToggleKeyboardAccess", "Turn keyboard access on or off", YES, 65535, 122, 0x00840000, -1 },
[Shortcut_ChangeTabMode] = { "ChangeTabMode", "Change the way Tab moves focus", YES, 65535, 98, 0x00840000, -1 },
[Shortcut_ToggleZoom] = { "ToggleZoom", "Zoom: Turn zoom on or off", NO, 56, 28, 0x00180000, -1 },
[Shortcut_ZoomIn] = { "ZoomIn", "Zoom: Zoom in", NO, 61, 24, 0x00180000, -1 },
[Shortcut_ZoomOut] = { "ZoomOut", "Zoom: Zoom out", NO, 45, 27, 0x00180000, -1 },
[Shortcut_InvertColors] = { "InvertColors", "Invert colors", YES, 56, 28, 0x001c0000, -1 },
[Shortcut_ToggleZoomImageSmoothing] = { "ToggleZoomImageSmoothing", "Zoom: Turn image smoothing on or off", NO, 92, 42, 0x00180000, -1 },
[Shortcut_IncreaseContrast] = { "IncreaseContrast", "Increase contrast", NO, 46, 47, 0x001c0000, -1 },
[Shortcut_DecreaseContrast] = { "DecreaseContrast", "Decrease contrast", NO, 44, 43, 0x001c0000, -1 },
[Shortcut_FocusNextApplicationWindow] = { "FocusNextApplicationWindow", "Move focus to the next window in application", YES, 96, 50, 0x00100000, -1 },
[Shortcut_ScreenshotToFile] = { "ScreenshotToFile", "Save picture of screen as a file", YES, 51, 20, 0x00120000, -1 },
[Shortcut_ScreenshotToClipboard] = { "ScreenshotToClipboard", "Copy picture of screen to the clipboard", YES, 51, 20, 0x00160000, -1 },
[Shortcut_ScreenshotAreaToFile] = { "ScreenshotAreaToFile", "Save picture of selected area as a file", YES, 52, 21, 0x00120000, -1 },
[Shortcut_ScreenshotAreaToClipboard] = { "ScreenshotAreaToClipboard", "Copy picture of selected area to the clipboard", YES, 52, 21, 0x00160000, -1 },
[Shortcut_ShowAllWindows] = { "ShowAllWindows", "Mission Control", YES, 65535, 126, 0x00840000, -1 },
[Shortcut_ShowApplicationWindows] = { "ShowApplicationWindows", "Application windows", YES, 65535, 125, 0x00840000, -1 },
[Shortcut_ShowDesktop] = { "ShowDesktop", "Show desktop", YES, 65535, 103, 0x00800000, -1 },
[Shortcut_ToggleDockHiding] = { "ToggleDockHiding", "Turn Dock hiding on/off", YES, 100, 2, 0x00180000, -1 },
[Shortcut_DecreaseBrightness] = { "DecreaseBrightness", "Decrease display brightness", YES, 65535, 107, 0x00800000, -1 },
[Shortcut_IncreaseBrightness] = { "IncreaseBrightness", "Increase display brightness", YES, 65535, 113, 0x00800000, -1 },
[Shortcut_FocusStatusMenu] = { "FocusStatusMenu", "Move focus to the status menus", YES, 65535, 100, 0x00840000, -1 },
[Shortcut_ToggleVoiceOver] = { "ToggleVoiceOver", "Turn VoiceOver on or off", YES, 65535, 96, 0x00900000, -1 },
[Shortcut_SelectPreviousInputSource] = { "SelectPreviousInputSource", "Select the previous input source", YES, 32, 49, 0x00040000, -1 },
[Shortcut_SelectNextInputSource] = { "SelectNextInputSource", "Select next source in Input menu", YES, 32, 49, 0x000c0000, -1 },
[Shortcut_ShowSpotlight] = { "ShowSpotlight", "Show Spotlight Search", YES, 32, 49, 0x00100000, -1 },
[Shortcut_ShowFinderSearch] = { "ShowFinderSearch", "Show Finder search window", YES, 32, 49, 0x00180000, -1 },
[Shortcut_SwitchToDesktopLeft] = { "SwitchToDesktopLeft", "Move left a space", NO, 65535, 123, 0x00840000, -1 },
[Shortcut_SwitchToDesktopRight] = { "SwitchToDesktopRight", "Move right a space", NO, 65535, 124, 0x00840000, -1 },
[Shortcut_SwitchToDesktop1] = { "SwitchToDesktop1", "Switch to Desktop 1", NO, 65535, 18, 0x00040000, -1 },
[Shortcut_SwitchToDesktop2] = { "SwitchToDesktop2", "Switch to Desktop 2", NO, 65535, 19, 0x00040000, -1 },
[Shortcut_SwitchToDesktop3] = { "SwitchToDesktop3", "Switch to Desktop 3", NO, 65535, 20, 0x00040000, -1 },
[Shortcut_SwitchToDesktop4] = { "SwitchToDesktop4", "Switch to Desktop 4", NO, 65535, 21, 0x00040000, -1 },
[Shortcut_ShowContextualMenu] = { "ShowContextualMenu", "Show contextual menu", YES, 65535, 36, 0x00040000, 15 },
[Shortcut_ShowLaunchpad] = { "ShowLaunchpad", "Show Launchpad", NO, 65535, 65535, 0, -1 },
[Shortcut_ShowAccessibilityControls] = { "ShowAccessibilityControls", "Show Accessibility controls", YES, 65535, 96, 0x00980000, -1 },
[Shortcut_ShowNotificationCenter] = { "ShowNotificationCenter", "Show Notification Center", NO, 65535, 65535, 0, -1 },
[Shortcut_ToggleDoNotDisturb] = { "ToggleDoNotDisturb", "Turn Do Not Disturb on/off", YES, 65535, 65535, 0, -1 },
[Shortcut_ToggleZoomFocusFollowing] = { "ToggleZoomFocusFollowing", "Zoom: Turn focus following on or off", NO, 65535, 65535, 0, -1 },
[Shortcut_ScreenshotOptions] = { "ScreenshotOptions", "Screenshot and recording options", YES, 53, 23, 0x00120000, -1 },
[Shortcut_OpenQuickNote] = { "OpenQuickNote", "Quick note", YES, 113, 12, 0x00800000, -1 },
[Shortcut_ToggleStageManager] = { "ToggleStageManager", "Turn Stage Manager on/off", NO, 65535, 65535, 0, -1 },
[Shortcut_TogglePresenterOverlayLarge] = { "TogglePresenterOverlayLarge", "Turn Presenter Overlay (large) on or off", YES, 65535, 65535, 0, -1 },
[Shortcut_TogglePresenterOverlaySmall] = { "TogglePresenterOverlaySmall", "Turn Presenter Overlay (small) on or off", YES, 65535, 65535, 0, -1 },
[Shortcut_ToggleLiveSpeech] = { "ToggleLiveSpeech", "LiveSpeech: Turn Live Speech on or off", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleLiveSpeechVisibility] = { "ToggleLiveSpeechVisibility", "LiveSpeech: Toggle visibility", YES, 65535, 65535, 0, 14 },
[Shortcut_PauseOrResumeLiveSpeech] = { "PauseOrResumeLiveSpeech", "LiveSpeech: Pause or resume speech", YES, 65535, 65535, 0, 14 },
[Shortcut_CancelLiveSpeech] = { "CancelLiveSpeech", "LiveSpeech: Cancel speech", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleLiveSpeechPhrases] = { "ToggleLiveSpeechPhrases", "LiveSpeech: Hide or show phrases", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleSpeakSelection] = { "ToggleSpeakSelection", "Turn speak selection on or off", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleSpeakItemUnderPointer] = { "ToggleSpeakItemUnderPointer", "Turn speak item under the pointer on or off", YES, 65535, 65535, 0, 14 },
[Shortcut_ToggleTypingFeedback] = { "ToggleTypingFeedback", "Turn typing feedback on or off", YES, 65535, 65535, 0, 14 },
};
static const int numSymbolicHotkeys = sizeof(defaultSymbolicHotKeys) / sizeof(defaultSymbolicHotKeys[0]);
// Current state of system shortcuts.
// Should only be read and written inside a @synchronized([SystemHotkey class]) block
static struct SymbolicHotKey currentSymbolicHotkeys[numSymbolicHotkeys];
// Should only be read and written inside a @synchronized([SystemHotkey class]) block
static bool subscribedToShortcutUpdates = false;
return [hotkeyId2DescMap objectForKey : [NSNumber numberWithInt : hotKeyId]];
}
@interface DefaultParams: NSObject
@property (assign) BOOL enabled;
@@ -314,7 +223,7 @@ static int javaModifiers2NS(int jmask) {
return result;
}
typedef void (^ Visitor)(int, const char *, int, const char *, int, const char*);
typedef bool (^ Visitor)(int, const char *, int, const char *, int);
static void visitServicesShortcut(Visitor visitorBlock, NSString * key_equivalent, NSString * desc) {
// @ - command
@@ -338,15 +247,16 @@ static void visitServicesShortcut(Visitor visitorBlock, NSString * key_equivalen
NSCharacterSet * excludeSet = [NSCharacterSet characterSetWithCharactersInString:@"@$^~"];
NSString * keyChar = [key_equivalent stringByTrimmingCharactersInSet:excludeSet];
visitorBlock(-1, keyChar.UTF8String, modifiers, desc.UTF8String, -1, NULL);
visitorBlock(-1, keyChar.UTF8String, modifiers, desc.UTF8String, -1);
}
static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
// Called from the main thread
void readSystemHotkeysImpl(Visitor visitorBlock) {
// 1. read from com.apple.symbolichotkeys.plist (domain with custom (user defined) shortcuts)
@try {
NSDictionary<NSString *, id> *shk = [[NSUserDefaults standardUserDefaults] persistentDomainForName:@"com.apple.symbolichotkeys"];
NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults];
NSDictionary<NSString *,id> * shk = [defaults persistentDomainForName:@"com.apple.symbolichotkeys"];
if (shk != nil) {
// AppleSymbolicHotKeys = {
// 10 = {
// enabled = 1;
@@ -361,136 +271,91 @@ static void readAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHo
// };
// ......
// }
id hkObj = shk ? [shk valueForKey:@"AppleSymbolicHotKeys"] : nil;
if (hkObj && ![hkObj isKindOfClass:[NSDictionary class]]) {
plog(LL_DEBUG, "object for key 'AppleSymbolicHotKeys' isn't NSDictionary (class=%s)",
[[hkObj className] UTF8String]);
return;
}
id hotkeys = [shk valueForKey:@"AppleSymbolicHotKeys"];
if (hotkeys == nil)
plog(LL_DEBUG, "key AppleSymbolicHotKeys doesn't exist in domain com.apple.symbolichotkeys");
else if (![hotkeys isKindOfClass:[NSDictionary class]])
plog(LL_DEBUG, "object for key 'AppleSymbolicHotKeys' isn't NSDictionary (class=%s)", [hotkeys className].UTF8String);
else {
for (id keyObj in hotkeys) {
if (![keyObj isKindOfClass:[NSString class]]) {
plog(LL_DEBUG, "key '%s' isn't instance of NSString (class=%s)", toCString(keyObj), [keyObj className].UTF8String);
continue;
}
NSString *hkNumber = keyObj;
id hkDesc = hotkeys[hkNumber];
if (![hkDesc isKindOfClass:[NSDictionary class]]) {
plog(LL_DEBUG, "hotkey descriptor '%s' isn't instance of NSDictionary (class=%s)", toCString(hkDesc), [hkDesc className].UTF8String);
continue;
}
NSDictionary<id, id> *sdict = hkDesc;
id objValue = sdict[@"value"];
if (objValue == nil)
continue;
memcpy(hotkeys, defaultSymbolicHotKeys, numSymbolicHotkeys * sizeof(struct SymbolicHotKey));
if (![objValue isKindOfClass:[NSDictionary class]]) {
plog(LL_DEBUG, "property 'value' %s isn't instance of NSDictionary (class=%s)", toCString(objValue), [objValue className].UTF8String);
continue;
}
for (id keyObj in hkObj) {
if (![keyObj isKindOfClass:[NSString class]]) {
plog(LL_DEBUG, "key '%s' isn't instance of NSString (class=%s)", toCString(keyObj),
[[keyObj className] UTF8String]);
continue;
}
NSString *hkNumber = keyObj;
id objEnabled = sdict[@"enabled"];
BOOL enabled = objEnabled != nil && [objEnabled boolValue] == YES;
int uid = [hkNumber intValue];
if (!enabled)
continue;
id hkDesc = hkObj[hkNumber];
if (![hkDesc isKindOfClass:[NSDictionary class]]) {
plog(LL_DEBUG, "hotkey descriptor '%s' isn't instance of NSDictionary (class=%s)", toCString(hkDesc),
[[hkDesc className] UTF8String]);
continue;
}
NSDictionary<id, id> *sdict = hkDesc;
NSDictionary * value = objValue;
id objParams = value[@"parameters"];
if (![objParams isKindOfClass:[NSArray class]]) {
plog(LL_DEBUG, "property 'parameters' %s isn't instance of NSArray (class=%s)", toCString(objParams), [objParams className].UTF8String);
continue;
}
id objEnabled = sdict[@"enabled"];
BOOL enabled = objEnabled != nil && [objEnabled boolValue] == YES;
hotkeys[uid].enabled = enabled;
NSArray *parameters = objParams;
if ([parameters count] < 3) {
plog(LL_DEBUG, "too small lenght of parameters %d", [parameters count]);
continue;
}
if (!enabled)
continue;
id p0 = parameters[0];
id p1 = parameters[1];
id p2 = parameters[2];
id objValue = sdict[@"value"];
if (objValue == nil)
continue;
if (![p0 isKindOfClass:[NSNumber class]] || ![p1 isKindOfClass:[NSNumber class]] || ![p2 isKindOfClass:[NSNumber class]]) {
plog(LL_DEBUG, "some of parameters isn't instance of NSNumber (%s, %s, %s)", [p0 className].UTF8String, [p1 className].UTF8String, [p2 className].UTF8String);
continue;
}
if (![objValue isKindOfClass:[NSDictionary class]]) {
plog(LL_DEBUG, "property 'value' %s isn't instance of NSDictionary (class=%s)", toCString(objValue),
[[objValue className] UTF8String]);
continue;
}
//parameter 1: ASCII code of the character (or 65535 - hex 0xFFFF - for non-ASCII characters).
//parameter 2: the keyboard key code for the character.
//Parameter 3: the sum of the control, command, shift and option keys. these are bits 17-20 in binary: shift is bit 17, control is bit 18, option is bit 19, and command is bit 20.
// 0x020000 => "Shift",
// 0x040000 => "Control",
// 0x080000 => "Option",
// 0x100000 => "Command"
NSDictionary *value = objValue;
id objParams = value[@"parameters"];
if (![objParams isKindOfClass:[NSArray class]]) {
plog(LL_DEBUG, "property 'parameters' %s isn't instance of NSArray (class=%s)", toCString(objParams),
[[objParams className] UTF8String]);
continue;
}
int asciiCode = p0 == nil ? 0xFFFF : [p0 intValue];
int vkeyCode = p1 == nil ? -1 : [p1 intValue];
int modifiers = p2 == nil ? 0 : [p2 intValue];
NSArray *parameters = objParams;
if ([parameters count] < 3) {
plog(LL_DEBUG, "too small length of parameters %d", [parameters count]);
continue;
}
id p0 = parameters[0];
id p1 = parameters[1];
id p2 = parameters[2];
if (![p0 isKindOfClass:[NSNumber class]] || ![p1 isKindOfClass:[NSNumber class]] ||
![p2 isKindOfClass:[NSNumber class]]) {
plog(LL_DEBUG, "some of parameters isn't instance of NSNumber (%s, %s, %s)",
[[p0 className] UTF8String],
[[p1 className] UTF8String], [[p2 className] UTF8String]);
continue;
}
//parameter 1: ASCII code of the character (or 65535 - hex 0xFFFF - for non-ASCII characters).
//parameter 2: the keyboard key code for the character.
//Parameter 3: the sum of the control, command, shift and option keys. these are bits 17-20 in binary: shift is bit 17, control is bit 18, option is bit 19, and command is bit 20.
// 0x020000 => "Shift",
// 0x040000 => "Control",
// 0x080000 => "Option",
// 0x100000 => "Command"
hotkeys[uid].character = p0 == nil ? 0xFFFF : [p0 intValue];
hotkeys[uid].key = p1 == nil ? 0xFFFF : [p1 intValue];
hotkeys[uid].modifiers = p2 == nil ? 0 : [p2 intValue];
}
}
@catch (NSException *exception) {
NSLog(@"readCachedAppleSymbolicHotkeys: catched exception, reason '%@'", exception.reason);
}
}
static void updateAppleSymbolicHotkeysCache() {
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
readAppleSymbolicHotkeys(hotkeys);
@synchronized ([SystemHotkey class]) {
memcpy(currentSymbolicHotkeys, hotkeys, numSymbolicHotkeys * sizeof(struct SymbolicHotKey));
}
}
static void iterateAppleSymbolicHotkeys(struct SymbolicHotKey hotkeys[numSymbolicHotkeys], Visitor visitorBlock) {
const NSOperatingSystemVersion macOSVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
for (int uid = 0; uid < numSymbolicHotkeys; ++uid) {
struct SymbolicHotKey* hotkey = &hotkeys[uid];
if (!hotkey->enabled) continue;
if (hotkey->macOSVersion > macOSVersion.majorVersion) continue;
char keyCharBuf[64];
const char *keyCharStr = keyCharBuf;
if (hotkey->character >= 0 && hotkey->character <= 0xFF) {
sprintf(keyCharBuf, "%c", hotkey->character);
} else {
keyCharStr = NULL;
}
int modifiers = symbolicHotKeysModifiers2java(hotkey->modifiers);
visitorBlock(hotkey->key, keyCharStr, modifiers, hotkey->description, uid, hotkey->id);
if (uid == Shortcut_FocusNextApplicationWindow) {
// Derive the "Move focus to the previous window in application" shortcut
if (!(modifiers & AWT_SHIFT_DOWN_MASK)) {
visitorBlock(hotkey->key, keyCharStr, modifiers | AWT_SHIFT_DOWN_MASK,
"Move focus to the previous window in application", -1, "FocusPreviousApplicationWindow");
char keyCharBuf[64];
const char * keyCharStr = keyCharBuf;
if (asciiCode >= 0 && asciiCode <= 0xFF) {
sprintf(keyCharBuf, "%c", asciiCode);
} else
keyCharStr = NULL;
NSString * description = getAppleSymbolicHotKeysDescription([hkNumber intValue]);
visitorBlock(vkeyCode, keyCharStr, symbolicHotKeysModifiers2java(modifiers), description == nil ? NULL : description.UTF8String, [hkNumber intValue]);
}
}
} else {
plog(LL_DEBUG, "domain com.apple.symbolichotkeys doesn't exist");
}
}
static void readPbsHotkeys(Visitor visitorBlock) {
@try {
NSMutableDictionary *allDefParams = createDefaultParams();
NSDictionary<NSString *, id> *pbs = [[NSUserDefaults standardUserDefaults] persistentDomainForName:@"pbs"];
if (pbs) {
// 2. read from Pbs (domain with services shortcuts)
NSMutableDictionary * allDefParams = createDefaultParams();
NSDictionary<NSString *,id> * pbs = [defaults persistentDomainForName:@"pbs"];
if (pbs) {
// NSServicesStatus = {
// "com.apple.Terminal - Open man Page in Terminal - openManPage" = {
// "key_equivalent" = "@$m";
@@ -507,144 +372,115 @@ static void readPbsHotkeys(Visitor visitorBlock) {
// };
// }
NSDictionary<NSString *, id> *services = [pbs valueForKey:@"NSServicesStatus"];
if (services) {
for (NSString *key in services) {
id value = services[key];
if (![value isKindOfClass:[NSDictionary class]]) {
plog(LL_DEBUG, "'%s' isn't instance of NSDictionary (class=%s)", toCString(value),
[[value className] UTF8String]);
continue;
}
// NOTE: unchanged default params will not appear here, check allDefParams at the end of this loop
DefaultParams *defParams = [allDefParams objectForKey:key];
[allDefParams removeObjectForKey:key];
NSDictionary<NSString *, id> *sdict = value;
NSString *key_equivalent = sdict[@"key_equivalent"];
if (!key_equivalent && defParams != nil) {
key_equivalent = defParams.key_equivalent;
}
if (!key_equivalent)
continue;
NSString *enabled = sdict[@"enabled_services_menu"];
if (enabled != nil && [enabled boolValue] == NO) {
continue;
}
if (enabled == nil && defParams != nil && !defParams.enabled) {
continue;
}
visitServicesShortcut(visitorBlock, key_equivalent, key);
NSDictionary<NSString *, id> *services = [pbs valueForKey:@"NSServicesStatus"];
if (services) {
for (NSString *key in services) {
id value = services[key];
if (![value isKindOfClass:[NSDictionary class]]) {
plog(LL_DEBUG, "'%s' isn't instance of NSDictionary (class=%s)", toCString(value), [value className].UTF8String);
continue;
}
// NOTE: unchanged default params will not appear here, check allDefParams at the end of this loop
DefaultParams * defParams = [allDefParams objectForKey:key];
[allDefParams removeObjectForKey:key];
NSDictionary<NSString *, id> *sdict = value;
NSString *key_equivalent = sdict[@"key_equivalent"];
if (!key_equivalent && defParams != nil) {
key_equivalent = defParams.key_equivalent;
}
if (!key_equivalent)
continue;
NSString *enabled = sdict[@"enabled_services_menu"];
if (enabled != nil && [enabled boolValue] == NO) {
continue;
}
if (enabled == nil && defParams != nil && !defParams.enabled) {
continue;
}
visitServicesShortcut(visitorBlock, key_equivalent, key);
}
}
}
// Iterate through rest of allDefParams
for (NSString* key in allDefParams) {
DefaultParams * defParams = allDefParams[key];
if (!defParams.enabled) {
continue;
}
visitServicesShortcut(visitorBlock, defParams.key_equivalent, key);
}
#ifdef USE_CARBON_CopySymbolicHotKeys
// 3. read from core services
CFArrayRef registeredHotKeys;
if(CopySymbolicHotKeys(&registeredHotKeys) == noErr) {
CFIndex count = CFArrayGetCount(registeredHotKeys);
for(CFIndex i = 0; i < count; i++) {
CFDictionaryRef hotKeyInfo = CFArrayGetValueAtIndex(registeredHotKeys, i);
CFNumberRef hotKeyCode = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyCode);
CFNumberRef hotKeyModifiers = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyModifiers);
CFBooleanRef hotKeyEnabled = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyEnabled);
int64_t vkeyCode = -1;
CFNumberGetValue(hotKeyCode, kCFNumberSInt64Type, &vkeyCode);
int64_t keyModifiers = 0;
CFNumberGetValue(hotKeyModifiers, kCFNumberSInt64Type, &keyModifiers);
Boolean enabled = CFBooleanGetValue(hotKeyEnabled);
if (!enabled)
continue;
visitorBlock(vkeyCode, NULL, NSModifiers2java(keyModifiers), NULL, -1);
}
// Iterate through rest of allDefParams
for (NSString *key in allDefParams) {
DefaultParams *defParams = allDefParams[key];
if (!defParams.enabled) {
continue;
}
visitServicesShortcut(visitorBlock, defParams.key_equivalent, key);
}
CFRelease(registeredHotKeys);
}
#endif // USE_CARBON_CopySymbolicHotKeys
}
@catch (NSException *exception) {
NSLog(@"readPbsHotkeys: catched exception, reason '%@'", exception.reason);
NSLog(@"readSystemHotkeys: catched exception, reason '%@'", exception.reason);
}
}
static void readAppleSymbolicHotkeysCached(struct SymbolicHotKey hotkeys[numSymbolicHotkeys]) {
@synchronized ([SystemHotkey class]) {
if (!subscribedToShortcutUpdates) {
[SystemHotkey setUp];
bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, int keyCode, NSString * chars) {
const int shortcutUid_NextWindowInApplication = 27;
static NSString * shortcutCharacter = nil;
static int shortcutMask = 0;
static int shortcutKeyCode = -1;
if (shortcutCharacter == nil && shortcutKeyCode == -1) {
readSystemHotkeysImpl(
^bool(int vkeyCode, const char * keyCharStr, int jmodifiers, const char * descriptionStr, int hotkeyUid) {
if (hotkeyUid != shortcutUid_NextWindowInApplication)
return true;
if (keyCharStr != NULL) {
shortcutCharacter = [[NSString stringWithFormat:@"%s", keyCharStr] retain];
}
if (vkeyCode != -1) {
shortcutKeyCode = vkeyCode;
}
shortcutMask = javaModifiers2NS(jmodifiers);
return false;
}
);
if (shortcutCharacter == nil && shortcutKeyCode == -1) {
shortcutCharacter = @"`";
shortcutMask = NSCommandKeyMask;
}
memcpy(hotkeys, currentSymbolicHotkeys, numSymbolicHotkeys * sizeof(struct SymbolicHotKey));
}
}
static void readSystemHotkeysImpl(Visitor visitorBlock) {
// Normally, SystemHotkey would get initialized in LWCToolkit initialization.
// But since we can (theoretically) use this API from headless, let's check again.
struct SymbolicHotKey hotkeys[numSymbolicHotkeys];
readAppleSymbolicHotkeysCached(hotkeys);
iterateAppleSymbolicHotkeys(hotkeys, visitorBlock);
readPbsHotkeys(visitorBlock);
}
@implementation SystemHotkey
+ (void)setUp {
// This should be called on LWCToolkit initialization.
@synchronized (self) {
if (subscribedToShortcutUpdates) {
return;
}
// Update cached values
updateAppleSymbolicHotkeysCache();
// Subscribe to changes
NSUserDefaults *symbolicHotKeys = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.symbolichotkeys"];
[symbolicHotKeys addObserver:self forKeyPath:@"AppleSymbolicHotKeys" options:NSKeyValueObservingOptionNew
context:nil];
NSUserDefaults *pbsHotKeys = [[NSUserDefaults alloc] initWithSuiteName:@"pbs"];
[pbsHotKeys addObserver:self forKeyPath:@"NSServicesStatus" options:NSKeyValueObservingOptionNew context:nil];
subscribedToShortcutUpdates = true;
}
}
+ (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context {
// Called after AppleSymbolicHotKeys or pbs hotkeys change.
// This method can be called from any thread.
if ([keyPath isEqualToString:@"AppleSymbolicHotKeys"]) {
updateAppleSymbolicHotkeysCache();
}
// Since this notification is sent *after* the configuration was updated,
// the user can safely re-read the hotkeys info after receiving this callback.
// On the Java side, this simply enqueues the change handler to run on the EDT later.
JNIEnv* env = [ThreadUtilities getJNIEnv];
DECLARE_CLASS(jc_SystemHotkey, "java/awt/desktop/SystemHotkey");
DECLARE_STATIC_METHOD(jsm_onChange, jc_SystemHotkey, "onChange", "()V");
(*env)->CallStaticVoidMethod(env, jc_SystemHotkey, jsm_onChange);
CHECK_EXCEPTION();
}
@end
bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, int keyCode, NSString *chars) {
struct SymbolicHotKey shortcut;
@synchronized ([SystemHotkey class]) {
if (!subscribedToShortcutUpdates) {
[SystemHotkey setUp];
}
shortcut = currentSymbolicHotkeys[Shortcut_FocusNextApplicationWindow];
}
int ignoredModifiers = NSAlphaShiftKeyMask | NSFunctionKeyMask | NSNumericPadKeyMask | NSHelpKeyMask;
// Ignore Shift because of JBR-4899.
if (!(shortcut.modifiers & NSShiftKeyMask)) {
if (!(shortcutMask & NSShiftKeyMask)) {
ignoredModifiers |= NSShiftKeyMask;
}
if ((modifiersMask & ~ignoredModifiers) != shortcut.modifiers) {
return false;
}
if (shortcut.key == keyCode) {
return true;
}
if (shortcut.character > 0 && shortcut.character < 0xFFFF) {
unichar ch = shortcut.character;
return [chars isEqualToString:[NSString stringWithCharacters:&ch length:1]];
if ((modifiersMask & ~ignoredModifiers) == shortcutMask) {
return shortcutKeyCode == keyCode || [chars isEqualToString:shortcutCharacter];
}
return false;
@@ -652,16 +488,16 @@ bool isSystemShortcut_NextWindowInApplication(NSUInteger modifiersMask, int keyC
JNIEXPORT void JNICALL Java_java_awt_desktop_SystemHotkeyReader_readSystemHotkeys(JNIEnv* env, jobject reader) {
jclass clsReader = (*env)->GetObjectClass(env, reader);
jmethodID methodAdd = (*env)->GetMethodID(env, clsReader, "add", "(ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;)V");
jmethodID methodAdd = (*env)->GetMethodID(env, clsReader, "add", "(ILjava/lang/String;ILjava/lang/String;)V");
readSystemHotkeysImpl(
^(int vkeyCode, const char * keyCharStr, int jmodifiers, const char * descriptionStr, int hotkeyUid, const char * idStr) {
^bool(int vkeyCode, const char * keyCharStr, int jmodifiers, const char * descriptionStr, int hotkeyUid){
jstring jkeyChar = keyCharStr == NULL ? NULL : (*env)->NewStringUTF(env, keyCharStr);
jstring jdesc = descriptionStr == NULL ? NULL : (*env)->NewStringUTF(env, descriptionStr);
jstring jid = idStr == NULL ? NULL : (*env)->NewStringUTF(env, idStr);
(*env)->CallVoidMethod(
env, reader, methodAdd, (jint)vkeyCode, jkeyChar, (jint)jmodifiers, jdesc, jid
env, reader, methodAdd, (jint)vkeyCode, jkeyChar, (jint)jmodifiers, jdesc
);
return true;
}
);
}

View File

@@ -14,44 +14,28 @@ import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
/**
* Provides info about system hotkeys.
* Deprecated, use JBR SystemShortcuts API instead.
* Provides info about system hotkeys
*/
public class SystemHotkey extends AWTKeyStroke {
private static final long serialVersionUID = 4340163519946285280L;
private static final long serialVersionUID = -6593119259058157651L;
private static final PlatformLogger ourLog = PlatformLogger.getLogger(java.awt.desktop.SystemHotkey.class.getName());
private static final Map<Integer, String> ourCodeDescriptionCache = new HashMap<>();
private static volatile Runnable changeEventHandler = null;
private final int myNativeKeyCode;
private final String myId;
private final String myDescription;
SystemHotkey(char keyChar, int javaKeyCode, int javaModifiers, String description, int nativeKeyCode) {
this(keyChar, javaKeyCode, javaModifiers, description, nativeKeyCode, description);
}
SystemHotkey(char keyChar, int javaKeyCode, int javaModifiers, String description, int nativeKeyCode, String id) {
super(keyChar, javaKeyCode, javaModifiers, true);
this.myNativeKeyCode = nativeKeyCode;
this.myId = id;
this.myDescription = description;
super(keyChar, javaKeyCode, javaModifiers, true);
this.myNativeKeyCode = nativeKeyCode;
this.myDescription = description;
}
public String toString() {
return String.format("id='%s' desc='%s' char=%s mod='%s' nativeKeyCode=0x%X ['%s'] javaKeyCode=0x%X",
String.valueOf(myId), String.valueOf(myDescription), String.valueOf(getKeyChar()), InputEvent.getModifiersExText(getModifiers()),
return String.format("desc='%s' char=%s mod='%s' nativeKeyCode=0x%X ['%s'] javaKeyCode=0x%X",
String.valueOf(myDescription), String.valueOf(getKeyChar()), InputEvent.getModifiersExText(getModifiers()),
myNativeKeyCode, getOsxKeyCodeDescription(myNativeKeyCode), getKeyCode());
}
/**
* Gets unique hotkey identifier
* @return hotkey identifier
*/
public String getId() {
return myId;
}
/**
* Gets hotkey description
* @return hotkey description
@@ -83,32 +67,16 @@ public class SystemHotkey extends AWTKeyStroke {
}
private static native String osxKeyCodeDescription(int osxCode);
/**
* Set the event handler, which is fired when the user changes a system shortcut.
* @param changeEventHandler event handler
*/
public static void setChangeEventHandler(Runnable changeEventHandler) {
SystemHotkey.changeEventHandler = changeEventHandler; // store to volatile
}
private static void onChange() {
// called from native code from any thread
var handler = changeEventHandler; // load from volatile
if (handler != null) {
EventQueue.invokeLater(handler);
}
}
}
class SystemHotkeyReader {
private final List<SystemHotkey> myResult = new ArrayList<>();
void add(int keyCode, String keyChar, int modifiers, String desc, String id) {
void add(int keyCode, String keyChar, int modifiers, String desc) {
myResult.add(new SystemHotkey(
keyChar == null || keyChar.isEmpty() ? KeyEvent.CHAR_UNDEFINED : keyChar.charAt(0),
keyCode == -1 ? KeyEvent.VK_UNDEFINED : osx2java(keyCode),
modifiers, desc, keyCode, (id == null) ? desc : id
modifiers, desc, keyCode
));
}