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

编写插件解决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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342