美文网首页
编写插件解决Jetbrains系列软件Ctrl + Alt +

编写插件解决Jetbrains系列软件Ctrl + Alt +

作者: 忆_析风 | 来源:发表于2019-12-16 21:52 被阅读0次

编写插件解决Jetbrains系列软件Ctrl + Alt + L 和搜狗输入法Ctrl切换语言的冲突

以下内容只针对Windows平台

问题

  • 搜狗输入法提供了两种语言切换快捷键,一个是Shift一个是Ctrl,作为一个码农,Shift肯定是少不了会一直按的,拿它作为语言切换快捷键会存在一个问题,就是只要你稍微犹豫了一下,只按了Shift但是没按其它键,那么搜狗就会切语言了,然而这肯定并非尔之所愿,所谓的犹豫就会败北.所以我将搜狗默认的Shift切换语言改成Ctrl了.不过感觉周围好像就我一个人这个干,我就想知道选择Shift键作为语言切换的同学的是怎么忍受Shift天天没事乱切换语言的...
  • 然后涉及第二个习惯,在使用IDEA/Android Studio过程中,我老是喜欢按下Ctrl + Alt + L去对齐全文代码,可能我已经习惯了整齐舒适的感觉.不过这个习惯经常遭来祸端,比如改了别人的代码,然后他提交的时候就冲突了.当然我会告诉他,你没对齐还怪我喽[手动滑稽]

基于以上两个习惯,冲突了.........

按下Ctrl + Alt + L会切换语言. WTF.

按下Ctrl + L或者其它键并不会切换语言,只要带上Ctrl + Alt就会切.所以这特么就是一个搜狗N年都没解决的Bug..........

可能还是因为使用Ctrl键作为语言切换的人太少了,没反馈过去.

能怎么办呢?搜狗不解决那只有自己解了.

解决办法

  • 在搜狗改成Shift切换语言 : 去死!
  • 修改IDEA的快捷键 : 有效,容易和其它快捷键重叠,试了好几个都发现有重叠,然后我尝试覆盖了一个Ctrl + L,有用,但是我特么已经习惯了Ctrl + Alt + L了..........每次都会习惯的用Ctrl + Alt + L,所以这个方案放弃了.
  • 对搜狗屏蔽Alt : 感觉像是系统层才能实现的方式,太难了,告辞.而且搜狗也有一些Ctrl + Alt的快捷键,比如截图,所以屏蔽了也不好.
  • 用一个程序监听按键消息,当发生Ctrl + ALt + * 的组合快捷键时,当所有按键弹起时再按一次Ctrl来将搜狗的语言恢复回去.

最终也就是最后一个方案是较为可行的.

实现方案

有了想法,如何实现呢?Java不能在后台检测按键,其必须要有焦点,所以写个Java程序在后台跑是不现实的;然后C/C++是可以实现后台监听按键的,但是作为一个菜鸡表示对C/C++不是很熟,而且一直跑的必要性不是很高;那么就试试写个IDEA的插件喽,本身只是在IDEA使用Ctrl + Alt + L才有的冲突,在IDEA中处理完就行了.

实现过程

了解插件的编写

IDEA插件的编写资料很少,尤其是中文资料更少,或者说不详细.特么的都是抄袭,点开几个网页内容都是一致的好烦,滥竽充数真没意思......你说你要是记笔记记在有道云不好吗?

找到一篇较为详细的中文资料,有兴趣可以了解下.

https://cloud.tencent.com/developer/article/1348741

创建工程

IDEA插件的创建方式有两种,一种是IntelliJ Platform Plugin一种是Gradle.

作为一个Android开发者对Gradle有着莫名的好感.所以,一开始是使用的Gradle,结果它第一次使用要下载依赖.......下了半天没啥动静....当我把插件写完了,它终于下载完了....

然后很无奈只好选择另一种方式创建了.

创建完了里面大概就一个plugin.xml,配置一些插件信息和注册一些组件,类似Android的AndroidManifest.xml.

此篇水文并不是教怎么写插件的,只是记录一个解决问题的过程,所以在此不对plugin.xml做说明,如果想了解插件编写可以先看下上面链接的文章.

创建组件

IDEA常用的组件应该是Action居多吧,它可以实现IDEA的菜单和快捷键调用,很方便,不过这里是一个监听操作,所以用不到Action.

这里我们需要做的是注册一个ApplicationComponent,这个组件可以实现在IDEA打开的时候就初始化.然后我们需要的正是这个效果 : 在IDEA打开时注册一个按键事件的监听回调.

简述其创建过程,如下.创建一个接口,继承于ApplicationComponent,举例:

package com.yxf.plugin;

import org.jetbrains.annotations.NotNull;

import com.intellij.openapi.components.ApplicationComponent;

public interface Component extends ApplicationComponent {

}

Java 8有了接口默认实现,所以不需要实现其方法,真好.

然后编写一个类实现这个接口,举例:

package com.yxf.plugin;
public class FixSouGouConflictComponent implements Component {

    @NotNull
    @Override
    public String getComponentName() {
        return "FixSgC.FixSouGouConflictComponent";
    }

    @Override
    public void initComponent() {

    }

    @Override
    public void disposeComponent() {

    }

获取名称,初始化,销毁,实现此三个接口即可.

然后别忘了将组件注册到plugin.xml中.

    <actions>
        <!-- Add your actions here -->
    </actions>

    <application-components>
        <component>
            <interface-class>com.yxf.plugin.Component</interface-class>
            <implementation-class>com.yxf.plugin.FixSouGouConflictComponent</implementation-class>
        </component>
    </application-components>

<application-components>这个标签默认没有,需要自己添加.

监听事件

然后如何实现按键事件的监听呢?中文网站没搜索到这部分内容,然后Google找到了一个线索,有个网友提到IdeEventQueue.addPostprocessor可以实现.然后我针对addPostprocessor搜索了下没发现啥.然后我想起了万能的GayHub,呸,GitHub.一搜索发现了一个Kotlin的例子,可以取出其中的KeyEvent.然后根据其方法修改实现:

    private IdeEventQueue.EventDispatcher mDispatcher = awtEvent -> {
        if (awtEvent instanceof KeyEvent) {
            return onKeyEvent((KeyEvent) awtEvent);
        }
        return false;
    };
    
    @Override
    public void initComponent() {
        IdeEventQueue queue = IdeEventQueue.getInstance();
        queue.addPostprocessor(mDispatcher, null);
    }
    
    private boolean onKeyEvent(KeyEvent event) {
        //................
        return false;
    }
    

有了KeyEvent就容易很多了,然后很容易就可以实现针对Ctrl + Alt + [*]快捷键的监控,发生后再按下Ctrl键恢复语言.具体实现如下.

    private Robot mRobot;
    private Set<Integer> mKeyDownSet = new HashSet<Integer>();
    private boolean mTriggered = false;

    private boolean onKeyEvent(KeyEvent event) {
        int keyCode = event.getKeyCode();
        switch (event.getID()) {
            case KeyEvent.KEY_PRESSED:
                if (event.isControlDown() && event.isAltDown()) {
                    if (keyCode == KeyEvent.VK_CONTROL || keyCode == KeyEvent.VK_ALT) {
                        return false;
                    }
                    mKeyDownSet.add(keyCode);
                    mTriggered = true;
                }
                break;
            case KeyEvent.KEY_RELEASED:
                if (keyCode != KeyEvent.VK_CONTROL && keyCode != KeyEvent.VK_ALT) {
                    mKeyDownSet.remove(keyCode);
                }
                if (mTriggered && mKeyDownSet.size() == 0 && !event.isControlDown() && !event.isAltDown()) {
                    mTriggered = false;
                    if (mRobot != null) {
                        mRobot.keyPress(KeyEvent.VK_CONTROL);
                        mRobot.delay(50);
                        mRobot.keyRelease(KeyEvent.VK_CONTROL);
                    }
                }
                break;
        }

        return false;
    }

其中Robot类是用于模拟鼠标和键盘的.

至此逻辑就完了,写一个简单的插件实际上就和创建一个Android的Activity差不多.不过要实现复杂的插件,就像你想创建一个Dialog但是没有文档一样难受.IDEA的插件编写文档也是特别少,其官方文档写的貌似也不怎么样,讲道理最好的学习方式真的就是去GitHub找源代码看........

添加依赖

完了吗?Naive,哪有这么简单,这样做出了的插件直接运行没问题,放在Android Studio中没问题,但是非Java系列的软件上就有问题了,比如Pycharm/Rider,这样直接做出了的插件放到Pycharm根本没用,但是特么也不报错,也没log..........

Google了一把没多少有效信息,看到了一个关于说引用了python模块无法在IDEA中使用的......然后怀疑是不是缺失了什么依赖.然后回去plugin.xml中寻找线索,发现这样一段注释

    <!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
         on how to target different products -->
    <!-- uncomment to enable plugin in all products
    <depends>com.intellij.modules.lang</depends>
    -->

这是引导我如何对他们不同的产品做处理,哇,这正是所需要的.贴下网址

http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html

其内容大致是说每个产品依赖了不同的模块,有些公共模块,有些是IDEA/Android Studio才有的有些Pycharm才有的,诸如此类.......然后如果插件需要通用的话需要申明需要的模块.这部分它官方文档也没给个例子,差评.

而且国内的IDEA插件开发资料基本上没有这个信息.......

为了找个例子,继续GitHub搜吧,搜索关键字com.intellij.modules找出一堆.........发现很多Pycharm的插件,确实都有加一些依赖.然后我将其所有编辑器共有的依赖项都加上去了,如下

    <!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description -->
    <idea-version since-build="173.0"/>

    <!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
         on how to target different products -->
    <!-- uncomment to enable plugin in all products
    <depends>com.intellij.modules.lang</depends>
    -->
    <depends>com.intellij.modules.platform</depends>
    <depends>com.intellij.modules.lang</depends>
    <depends>com.intellij.modules.vcs</depends>
    <depends>com.intellij.modules.xml</depends>
    <depends>com.intellij.modules.xdebugger</depends>

    <extensions defaultExtensionNs="com.intellij">
        <!-- Add your extensions here -->
    </extensions>

重新编译后放到Pycharm和Rider中运行正常,只要使用Ctrl + Alt + [*]的快捷键,切换了语言又会马上切换回来.

曲线救国成功\(^o^)/YES!

此插件已经上传至Jetbrains插件仓库,所以可以在仓库中直接搜索FixSgC安装

源码

FixSgC

相关文章

网友评论

      本文标题:编写插件解决Jetbrains系列软件Ctrl + Alt +

      本文链接:https://www.haomeiwen.com/subject/zzhjnctx.html