mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-27 02:40:52 +01:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b739ff937 |
43
jb/project/docker/Dockerfile.musl_aarch64
Normal file
43
jb/project/docker/Dockerfile.musl_aarch64
Normal 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 '*'
|
||||
@@ -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"
|
||||
@@ -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
|
||||
44
jb/project/docker/Dockerfile.oraclelinux_aarch64
Normal file
44
jb/project/docker/Dockerfile.oraclelinux_aarch64
Normal 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"
|
||||
|
||||
45
jb/project/docker/Dockerfile.oraclelinux_x86_64
Normal file
45
jb/project/docker/Dockerfile.oraclelinux_x86_64
Normal 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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
@@ -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
|
||||
|
||||
28
jb/project/docker/mkdocker_x86_64.sh
Executable file
28
jb/project/docker/mkdocker_x86_64.sh
Executable 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.
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
@@ -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(®isteredHotKeys) == 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;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user