編寫插件解決Jetbrains系列軟件Ctrl + Alt + L 和搜狗輸入法Ctrl切換語言的沖突
以下內(nèi)容只針對(duì)Windows平臺(tái)
問題
- 搜狗輸入法提供了兩種語言切換快捷鍵,一個(gè)是Shift一個(gè)是Ctrl,作為一個(gè)碼農(nóng),Shift肯定是少不了會(huì)一直按的,拿它作為語言切換快捷鍵會(huì)存在一個(gè)問題,就是只要你稍微猶豫了一下,只按了Shift但是沒按其它鍵,那么搜狗就會(huì)切語言了,然而這肯定并非爾之所愿,所謂的猶豫就會(huì)敗北.所以我將搜狗默認(rèn)的Shift切換語言改成Ctrl了.不過感覺周圍好像就我一個(gè)人這個(gè)干,我就想知道選擇Shift鍵作為語言切換的同學(xué)的是怎么忍受Shift天天沒事亂切換語言的...
- 然后涉及第二個(gè)習(xí)慣,在使用IDEA/Android Studio過程中,我老是喜歡按下Ctrl + Alt + L去對(duì)齊全文代碼,可能我已經(jīng)習(xí)慣了整齊舒適的感覺.不過這個(gè)習(xí)慣經(jīng)常遭來禍端,比如改了別人的代碼,然后他提交的時(shí)候就沖突了.當(dāng)然我會(huì)告訴他,你沒對(duì)齊還怪我嘍[手動(dòng)滑稽]
基于以上兩個(gè)習(xí)慣,沖突了.........
按下Ctrl + Alt + L會(huì)切換語言. WTF.
按下Ctrl + L或者其它鍵并不會(huì)切換語言,只要帶上Ctrl + Alt就會(huì)切.所以這特么就是一個(gè)搜狗N年都沒解決的Bug..........
可能還是因?yàn)槭褂肅trl鍵作為語言切換的人太少了,沒反饋過去.
能怎么辦呢?搜狗不解決那只有自己解了.
解決辦法
- 在搜狗改成Shift切換語言 : 去死!
- 修改IDEA的快捷鍵 : 有效,容易和其它快捷鍵重疊,試了好幾個(gè)都發(fā)現(xiàn)有重疊,然后我嘗試覆蓋了一個(gè)Ctrl + L,有用,但是我特么已經(jīng)習(xí)慣了Ctrl + Alt + L了..........每次都會(huì)習(xí)慣的用Ctrl + Alt + L,所以這個(gè)方案放棄了.
- 對(duì)搜狗屏蔽Alt : 感覺像是系統(tǒng)層才能實(shí)現(xiàn)的方式,太難了,告辭.而且搜狗也有一些Ctrl + Alt的快捷鍵,比如截圖,所以屏蔽了也不好.
- 用一個(gè)程序監(jiān)聽按鍵消息,當(dāng)發(fā)生Ctrl + ALt + * 的組合快捷鍵時(shí),當(dāng)所有按鍵彈起時(shí)再按一次Ctrl來將搜狗的語言恢復(fù)回去.
最終也就是最后一個(gè)方案是較為可行的.
實(shí)現(xiàn)方案
有了想法,如何實(shí)現(xiàn)呢?Java不能在后臺(tái)檢測(cè)按鍵,其必須要有焦點(diǎn),所以寫個(gè)Java程序在后臺(tái)跑是不現(xiàn)實(shí)的;然后C/C++是可以實(shí)現(xiàn)后臺(tái)監(jiān)聽按鍵的,但是作為一個(gè)菜雞表示對(duì)C/C++不是很熟,而且一直跑的必要性不是很高;那么就試試寫個(gè)IDEA的插件嘍,本身只是在IDEA使用Ctrl + Alt + L才有的沖突,在IDEA中處理完就行了.
實(shí)現(xiàn)過程
了解插件的編寫
IDEA插件的編寫資料很少,尤其是中文資料更少,或者說不詳細(xì).特么的都是抄襲,點(diǎn)開幾個(gè)網(wǎng)頁內(nèi)容都是一致的好煩,濫竽充數(shù)真沒意思......你說你要是記筆記記在有道云不好嗎?
找到一篇較為詳細(xì)的中文資料,有興趣可以了解下.
https://cloud.tencent.com/developer/article/1348741
創(chuàng)建工程
IDEA插件的創(chuàng)建方式有兩種,一種是IntelliJ Platform Plugin一種是Gradle.
作為一個(gè)Android開發(fā)者對(duì)Gradle有著莫名的好感.所以,一開始是使用的Gradle,結(jié)果它第一次使用要下載依賴.......下了半天沒啥動(dòng)靜....當(dāng)我把插件寫完了,它終于下載完了....
然后很無奈只好選擇另一種方式創(chuàng)建了.
創(chuàng)建完了里面大概就一個(gè)plugin.xml,配置一些插件信息和注冊(cè)一些組件,類似Android的AndroidManifest.xml.
此篇水文并不是教怎么寫插件的,只是記錄一個(gè)解決問題的過程,所以在此不對(duì)plugin.xml做說明,如果想了解插件編寫可以先看下上面鏈接的文章.
創(chuàng)建組件
IDEA常用的組件應(yīng)該是Action居多吧,它可以實(shí)現(xiàn)IDEA的菜單和快捷鍵調(diào)用,很方便,不過這里是一個(gè)監(jiān)聽操作,所以用不到Action.
這里我們需要做的是注冊(cè)一個(gè)ApplicationComponent,這個(gè)組件可以實(shí)現(xiàn)在IDEA打開的時(shí)候就初始化.然后我們需要的正是這個(gè)效果 : 在IDEA打開時(shí)注冊(cè)一個(gè)按鍵事件的監(jiān)聽回調(diào).
簡述其創(chuàng)建過程,如下.創(chuàng)建一個(gè)接口,繼承于ApplicationComponent,舉例:
package com.yxf.plugin;
import org.jetbrains.annotations.NotNull;
import com.intellij.openapi.components.ApplicationComponent;
public interface Component extends ApplicationComponent {
}
Java 8有了接口默認(rèn)實(shí)現(xiàn),所以不需要實(shí)現(xiàn)其方法,真好.
然后編寫一個(gè)類實(shí)現(xiàn)這個(gè)接口,舉例:
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() {
}
獲取名稱,初始化,銷毀,實(shí)現(xiàn)此三個(gè)接口即可.
然后別忘了將組件注冊(cè)到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>這個(gè)標(biāo)簽?zāi)J(rèn)沒有,需要自己添加.
監(jiān)聽事件
然后如何實(shí)現(xiàn)按鍵事件的監(jiān)聽呢?中文網(wǎng)站沒搜索到這部分內(nèi)容,然后Google找到了一個(gè)線索,有個(gè)網(wǎng)友提到IdeEventQueue.addPostprocessor可以實(shí)現(xiàn).然后我針對(duì)addPostprocessor搜索了下沒發(fā)現(xiàn)啥.然后我想起了萬能的GayHub,呸,GitHub.一搜索發(fā)現(xiàn)了一個(gè)Kotlin的例子,可以取出其中的KeyEvent.然后根據(jù)其方法修改實(shí)現(xiàn):
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就容易很多了,然后很容易就可以實(shí)現(xiàn)針對(duì)Ctrl + Alt + [*]快捷鍵的監(jiān)控,發(fā)生后再按下Ctrl鍵恢復(fù)語言.具體實(shí)現(xiàn)如下.
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類是用于模擬鼠標(biāo)和鍵盤的.
至此邏輯就完了,寫一個(gè)簡單的插件實(shí)際上就和創(chuàng)建一個(gè)Android的Activity差不多.不過要實(shí)現(xiàn)復(fù)雜的插件,就像你想創(chuàng)建一個(gè)Dialog但是沒有文檔一樣難受.IDEA的插件編寫文檔也是特別少,其官方文檔寫的貌似也不怎么樣,講道理最好的學(xué)習(xí)方式真的就是去GitHub找源代碼看........
添加依賴
完了嗎?Naive,哪有這么簡單,這樣做出了的插件直接運(yùn)行沒問題,放在Android Studio中沒問題,但是非Java系列的軟件上就有問題了,比如Pycharm/Rider,這樣直接做出了的插件放到Pycharm根本沒用,但是特么也不報(bào)錯(cuò),也沒log..........
Google了一把沒多少有效信息,看到了一個(gè)關(guān)于說引用了python模塊無法在IDEA中使用的......然后懷疑是不是缺失了什么依賴.然后回去plugin.xml中尋找線索,發(fā)現(xiàn)這樣一段注釋
<!-- 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>
-->
這是引導(dǎo)我如何對(duì)他們不同的產(chǎn)品做處理,哇,這正是所需要的.貼下網(wǎng)址
http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
其內(nèi)容大致是說每個(gè)產(chǎn)品依賴了不同的模塊,有些公共模塊,有些是IDEA/Android Studio才有的有些Pycharm才有的,諸如此類.......然后如果插件需要通用的話需要申明需要的模塊.這部分它官方文檔也沒給個(gè)例子,差評(píng).
而且國內(nèi)的IDEA插件開發(fā)資料基本上沒有這個(gè)信息.......
為了找個(gè)例子,繼續(xù)GitHub搜吧,搜索關(guān)鍵字com.intellij.modules找出一堆.........發(fā)現(xiàn)很多Pycharm的插件,確實(shí)都有加一些依賴.然后我將其所有編輯器共有的依賴項(xiàng)都加上去了,如下
<!-- 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中運(yùn)行正常,只要使用Ctrl + Alt + [*]的快捷鍵,切換了語言又會(huì)馬上切換回來.
曲線救國成功\(^o^)/YES!
此插件已經(jīng)上傳至Jetbrains插件倉庫,所以可以在倉庫中直接搜索FixSgC安裝