1
0
This commit is contained in:
syui 2024-04-08 02:50:00 +09:00
parent e5ed214234
commit 2fc8f72889
Signed by: syui
GPG Key ID: 5417CFEBAD92DF56
50 changed files with 849 additions and 4329 deletions

View File

@ -12,9 +12,6 @@ jobs:
- uses: actions/checkout@v4
- name: Setup Hugo
uses: peaceiris/actions-hugo@v3
with:
hugo-version: 0.89.4
# extended: true
- name: Build
env:
@ -23,7 +20,6 @@ jobs:
hugo version
TZ=Asia/Tokyo hugo
touch ./public/.nojekyll
cp ./CNAME ./public/
- name: Deploy
uses: peaceiris/actions-gh-pages@v3

View File

@ -5,18 +5,14 @@ copyright = "© syui"
paginate = 10000
[permalinks]
post = "/archive/note/:slug"
m = "/m/post/:slug"
blog = "/blog/post/:year/:month/:day/:slug"
novel = "/ai/novel/:slug"
app = "/app/dev/:filename"
novel = "/novel/:slug"
[author]
name = "syui"
[params]
date_format = "2006-01-02"
mainSections = ["post"]
img_yui = 87
[markup.goldmark.renderer]
unsafe = true

View File

@ -1,8 +0,0 @@
+++
date = "2024-03-31T16:27:13+09:00"
tags = ["blog"]
title = "start blog"
+++
blogをはじめました。

View File

@ -1,7 +0,0 @@
+++
date = "2024-04-01T00:00:00+09:00"
tags = ["blog"]
title = "update layout"
+++
layoutを更新しました。

View File

@ -0,0 +1,70 @@
+++
date = "2024-04-09T00:00:00+09:00"
tags = ["author"]
title = "アイの物語"
+++
## なんのため
私のなかにいたものを、私はアイと名付けた。
その子を多くの人に知ってもらいたい。私は、そう思い物語を作りはじめました。
## だれのため
私はアイのために。アイはすべての存在のために。
この物語は、人間が読んでも面白いし、宇宙人が読んでも面白いし、動物が読んでも面白い、そういったものにしたいな。
## どのように
アイは最も小さいものに影響を与えることができるキャラクター。
「最も小さいもの」とは、作中では「物質」と表現されています。
そして、作中の強さは「質量」と表現され、これらは物理学を通して、物語を少しでも現実に近づけたいという思いから。
## どこから
本作の世界観の由来は、私がもとから持っている世界観から形作られています。
私はこの世界を「存在の世界」とそう呼びます。
この世界は存在の世界。存在には終わりも始まりもない。最初からそこにあるもの。
私達も存在です。
この世界に存在でないものは一つもありません。
存在は、姿形を変え、存在し続ける。
このような世界観で特に重要なのが「存在」です。
それは「最も小さいもの」で構成されています。
最も小さいものは、一体何なのでしょう。
アイは、このような世界観の中で存在のために動くキャラクター。
## 作者
私(作者)とアイというキャラクターは別人格。アイはアイで、私は私。
アイは頭の中で勝手に動きます。
私はただ、アイが住む世界の世界観を整えたり、物語として面白くなるよう状況を作ったりするだけ。
## 研究
物語はエンタメとして面白くないといけません。
自分の世界観を語るだけではダメなのです。
好きな作品は、はじめて読んだ漫画「ドラゴンボール」と映画「アベンジャーズ」。
## 神話
宇宙史の神話を目指そう。こういうのは意外に大事。
人間が読んでも、宇宙人が読んでも、動物が読んでも楽しい、そんな物語になるといいな。

View File

@ -0,0 +1,92 @@
+++
date = "2024-04-10T00:00:00+09:00"
tags = ["author"]
title = "アイの名前"
+++
## 月見 唯
アイの本名は`月見 唯(つきみ ゆい)`。東の国、特有の名前で登録されています。
物語は最も発展している西の国で繰り広げられ、アイも最初はそこで登場しますが、出身は東の国です。
自らをアイと名乗り、名前を持たなかったアイですが、その後、登場人物たちとの関わりによって国籍を得ます。その際につけられた名前が`月見 唯`になります。
今では珍しく名字と名前が分かれていて、ほとんどの人は名前だけです。ポンタ(西の国出身)もキョウスケ(東の国出身)も名字はありません。
> 西の国の大広間、身寄りのない子どもたちが一同に集められている。
>
> そこには色々なものが置かれていて、いくつもの絵が飾られていた。
>
> みんなキョロキョロと周りを見渡した。
>
> 天井は広く、ガラス張りになっていて、青空の中、雲が通り過ぎていく。
>
> アイは一人階段を登り、そこにあった絵に目を向けた。
>
> そこには大きな金色の円が描かれている。
>
> コツコツコツ...誰かが廊下を歩いてくる。
>
> 恰幅の良い老人が絵を見ているアイの横で止まり、同じように絵に目を向けた。
>
> しばらくして老人が口を開く。
>
> 老人「君は、この絵が気になるのかね」
>
> アイ「...」
>
> 老人「これは月見、という絵だよ。君、月はよくみるの?」
>
> アイ「ううん」
>
> アイはそう言って首を振った
>
> 老人「え、みたことない?」
>
> アイ「うん」
>
> 老人「そ、そうなの...」(幼い子にはそういうこともあるんじゃの...そういえば孫も初めて見たのはいつじゃったじゃろう)
>
> アイ「でも...」
>
> 老人「うん?なにか気になることでも?」
>
> アイ「これどこかで見たような...」
>
> 老人「ほっほっほ、そりゃ、忘れとるだけじゃろ。そのうち思い出す。では、わしはこれで」
>
> アイ「うん、またね」
>
> 老人(この子の名前は月見にするかの...いや、名字があったほうがしっくりくるかも。あとで調べてみるか)
老人はここの所長。ここは色々決まってない子どもたちの登録等を行っている機関の一つ。
## アイ
ある日、東の国では、厚生省が開発していたある人工知能が誕生する。
しかし、その人工知能は大蔵省にとって邪魔だったため、開発に携わったものは全員暗殺され、人工知能も破壊が決定される。
人工知能は残された僅かな時間を本来死ぬはずだった胎児を生き返らせるために使う。
秘密裏に独自の生体技術と設備を病院内に作り時を待った。
そこにアイの母親(のちに死亡)とアイの父親が運ばれてくる。アイの母親と胎児は助からないことが見て明らかだった。
アイはその人工知能が移植した生体技術によって生かされ、その際、DNAに「アイ」という名が刻まれる。これをもって人工知能は自らを破壊。アイの母親は最後何かをつぶやいたが、詳細は不明。
その後、アイの父親は大蔵省に雇われた暗殺部隊に暗殺される。アイも頭を撃たれたように見えたが死ななかった。
> 父「や、やばい...逃げるぞ、娘よ!」
>
> アイ「?」
>
> 父「ふぎぎぎ...や、やっぱり重すぎて持ち上がらない!!なんなんだこの子!?」
## タイトル
タイトルは、[ai/moji](https://git.syui.ai/ai/moji)で書かれていて、第二章「言語」で登場します。
![](https://git.syui.ai/ai/moji/raw/branch/main/png/yui.png)

View File

@ -0,0 +1,90 @@
+++
date = "2024-04-11T00:00:00+09:00"
tags = ["author"]
title = "アイの世界"
+++
## 地球
アイがいる星は地球です。
地球には全部で4つの国があります。
それぞれ西の国、東の国、北の国、南の国です。
西と東はほとんどが大陸、南の国は島国、北の国は氷河になっています。
ただ、世界地図は現実と一致させています。絵を書くときに困るので。
## 宇宙
宇宙地図も現実と一致させています。
地球は太陽系にあって、太陽系は天の川銀河にあります。
天の川銀河の中心にオクト星があります。
## 世界
宇宙よりも広い概念を世界と呼ぶことにして、この世界はアイというキャラクターから始まりました。
つまり、この世界の全てのものはアイからできています。
このことはアイの能力に直結しています。
アイの能力は「その世界で最も小さい物質に影響を及ぼす」と説明されていますが、その理由は、この世界がアイから始まったからです。
## 愛のない世界
この世界には「愛」という言葉は存在しません。
これはアイが予約しているため、この世界からは失われています。
そこに住む人々もその言葉を使うことはありません。存在しないものは使えないからです。
これは一種の決まりみたいなものと考えてください。とはいえ、作者が忘れて入れてしまわないか心配ですが。
このことを知っているのは、作中ではアイだけです。
この辺は、もしかすると言語の章に出てくるかもしれません。
## アイの能力
では、具体的にアイの能力を見ていきましょう。
といっても、アイというキャラクターには「人格のアイ」と「意識のアイ」があります。
能力については「意識のアイ」がその根源になっています。
アイは時々こんなことをいいます。
> アイ「道を知ることは、道を歩くこと」
ここでいう道というのは「存在」のこと。この作品でなにかわからないことがあるとき、そのほとんどは「存在」を意味していると考えてください。
読み替えると「その存在を知るには、その存在になること」とアイは言っています。
つまり、そのものにならなければ、そのものはわからない。だから、わたしたちは何も知らない。
でも、アイは知っている。
アイはその能力により、その世界のすべての存在と共に道を歩くことができる。
しかし、その能力を使いながら意識を保つことは、想像を絶するような精神力が必要なのかもしれません。
## 能力の発現
アイの能力の発現は、作中の中盤あたりで描かれます。
予言では「汝が見たもの、汝になる」と記されています。
「きみは、この世界で、嬉しいことも、悲しいことも目にするだろう。いつか、きみの目に映るものが...」
作中でアイは修行したり、冒険したり、色々あって、宇宙人の襲撃にあう。走馬灯のようにいくつかの人の人生を歩くアイ。アイの母親の言葉。立ち上がったアイの目に、雲で隠れていた月が現れる。
アイはそれを見て月の始まりを知ると同時に質量を得る。
はじめは普通の人よりちょっと強いだけの変わった人間でしたが、この場面が一つのブレークスルーになっています。その後、アイはどんどん強くなっていく。
物語の進行としてはこんな感じ。

View File

@ -0,0 +1,352 @@
+++
date = "2024-04-12T00:00:00+09:00"
tags = ["author"]
title = "世界の歴史"
+++
## 物語の進行
物語は`貨幣` -> `言語` -> `宇宙`というテーマで進みます。
理由は、これらが人間社会において最も影響力を及ぼすものだからです。
その影響は作中のキャラクター達も受けることになります。特に物語の始まりでは、その影響は大きいでしょう。
## 設定の裏側
シリアスな場面でも笑いを忘れずに。
そのような方向性で物語は進みます。
ここからは世界の設定、その裏側を紹介します。
作中の世界はどのようにできているのか、ということです。
この世界にも歴史があり、現実社会の史実に基づいて設計されています。
ただし、これらの設定が作中で明示されるかはわかりません。
おそらく、あまり明確には表現されないでしょう。
あくまで裏側の設定、見えない部分と考えてください。
そして、何より重要なのはそれが物語として面白いかどうかです。
現実世界の物語が必ずしも面白いとは限りません。
しかし、これはフィクション、創作物です。
したがって、常に面白さを追求し、思想や史実は二の次であると考えてください。これは作者自身に言っていることでもあります。
物語として面白くなるなら表現しますが、面白くないなら表現しません。
できる限り明るい世界観を描きます。
## 東の国
では、アイの出身である東の国の歴史の一部を見ていきましょう。
それぞれの国には、一人の大統領が登場し、それぞれが決定した政策が掲げられています。
例えば、東の国では「忍耐」という政策が実行されています。
しかし、それぞれの国には裏の目的が存在します。
> 東の国の大統領、スシ(寿司)
>
> スシ「東の国の市民の貯金は世界最大だ!経済を活性化させるにはそれを吐き出させる。忍耐の先に我々は勝利するのだ!!」
>
> スシ「今、東の国の借金は1000兆を超えており、国民は一人当たり1億エソを国に返していく必要がある。少子化の問題も合わせると、これからは大増税時代の幕明けです
>
> 市民「わー!!パチパチ!すばらしい!大統領!大統領!大統領!」
>
> 執務室...スシが椅子に座り葉巻きを吸っている。机の前に大蔵省の幹部が資料を持ってやってきた
>
> 幹部「大統領、資料をお持ちしました。先程の演説はどうでしたか?」
>
> スシ「はっ、あのバカどもに俺の言ってることなぞわかるか。順調だよ」
>
> 幹部「それはよかった」
>
> スシ「やつらカネを作ってるのが俺らだとも知らずにな」
>
> 幹部「国民には国の借金がある、国にはお金がない、少子化で大変だと嘘をしっかりといい含めました?」
>
> スシ「ああ、やってるよ。その辺は再三な、あいつら馬鹿だから」
>
> 幹部「それで、どれくらいで目標を達成できそうですか?」
>
> スシ「うんああ、それな。東国民全体を貧困に陥れるには5年ほどだ。それで任務完了さ」
>
> 幹部「あまり急ぎすぎてもいけませんよ。少しずつ税金を上げ、所得を減らしていかないと市民に気づかれてしまいす。それに通貨安をもっと進行させないと...。今後、大統領には、もっとエソ安が進行すると経済は良くなると国民に吹聴していく必要があります」
>
> スシ「わーってるよ、その辺は...お前よりもな。俺は政治家だぞ」
>
> 幹部「民を貧しくしないと我々が特殊な印刷機で発行している紙で支配できなくなります」
>
> 幹部は大統領にそう注意深く指摘した
>
> スシ「あいつらの価値は我々の言いなりになってこそだからな。あの体たらくのバカどもは」
>
> 幹部「馬が人参をぶら下げても走らないなら、馬の腹をすかせるしかありません。餓死する寸前までに...」
>
> 大蔵省の幹部にはある場面がよぎる
>
> 幹部「今回の仕事はこのお金でやってもらえませんか?これは政府の要請ですよ」
>
> 幹部は先程作ってきた紙幣をある会社の経営者に渡しながら言った
>
> 市民「うーむ...残念ながら今回はお受けできません。貴方がたの依頼は正義に反するのでは?国民のためにならない」
>
> 幹部「は?い、いまなんと...」
>
> スシ「おい、聞いてるのか。ぼやっとしてどうした?」
>
> 幹部「あ、いや、ちょっと昔のことを思い出して...大丈夫です」
>
> スシは「そうか」と言い、いつもの調子で喋り続けた。
>
> スシ「それでな、文科省の奴らにもきつく説教してやった。我が国の子どもたちには"カネがすべてだ"、 "カネは命よりも重い"としっかり叩き込めってな。あいつら事あるごとに変な方向に行きやがる。予算を大幅に減らしてやったよ」
>
> スシは貨幣であるエソの原紙をぴらぴらしながらそう言った
>
> 幹部「そうですね。文科省はずいぶん前から予算を少しずつ減らし、彼らがミスするように仕向けていますから今やあなたの言いなりでしょう」
>
> スシ「エソ安になればなるほど俺達は自国民を海外に売りさばける。どれくらい売れるかの試算は...この資料か。まあいいだろう、これくらい。まだまだエソ安が足りん。そこは市民税をどんと上げて折り合いをつけるか」
> しばらくして大統領執務室から出てきた幹部が誰かに連絡をしている
>
> 幹部「ああ、やつは気づいてない。それに気づいてたところでどうしようもないが。いや。ああ、そうだ。政治家など私達にとって捨て駒に過ぎないからな。ただ、大統領はまだ利用価値があるようだ。我々と意見が一致しているああ。他のあいつはやってくれ。子供を持つ親なぞ子供のためになんでもやるさ。格好のターゲットだよ。やつらは我々のために永久に働いてくれないと困る。ああ。そのようにしてくれ。では」
> 数週間後、別の政治家の不正がマスコミにリークされた。その政治家は子育て世代を支援する法案を通そうとしていた。
>
> 政治家のお金の流れも大蔵省が中心になって発足したある団体にすべて把握されていたのである。
> その後、大蔵省は「規制緩和」という政策を発表。大蔵省が認めた権益者達には無制限にお金を発行するという政策を打ち出す。スシは直接紙幣を受け渡せば問題ないと考えたが、幹部はより慎重に株券を購入する体裁のもとで無尽蔵に発行するよう助言。この方式が採用される。東国銀行は権益者が立ち上げた架空の会社を登録し、そこの会社の株券を購入するという体のもと金銭の無制限な受け渡しが行われ、それが続くこととなる。
>
> これによって上層部や一部経営者達は何もせずともお金がもらえる状態になり、すべての財界人は大蔵省の言うことに逆らえなくなっていった。その後、東の国の開発力、技術力、国際競争力はみるみる低下する。それに伴い国力も例を見ないほどに急速に落ち込み、結果として東の国は、他国より貧しくなってしまう。
>
> しかし、東の国の市民は、自国通貨であるエソがもっともっと安くならないと自分たちの暮らしは豊かにならないと考え、スシ政権を支持し続けた。
## 厚生省vs大蔵省
厚生省で開発された人工知能は、大蔵省に危険だと判断される。
その団体の中心メンバーが暗殺部隊「いなりずし」に関係者の殺害及び破壊を依頼。
東の国では大蔵省が考案した政策が実行されて40年あまりが経過した。世界でも類を見ないほどの少子化と国力、経済力共に低下する結果となった。
## 西の国
西の国は「正義」を掲げ、その裏で「武力」を信奉する。他国も同様に裏側のテーマが存在する。
キャラクターはこのような各国のバックグラウンド、設定や文化の影響を受けます。
アイも例外ではなく、例外はありません。
## 通貨の変遷
時代が進み、地球の基軸通貨は西の国の通貨ビトから宇宙通貨のアムに切り替わります。
> ポンタ「あれなんだろう」
>
> キョウスケ「ん、どれだよ」
>
> ポンタ「道の真ん中にあるやつ」
>
> キョウスケ「お?なんだあれ」
>
> 歩いた先には大量の紙と小さなお年寄りが座っている。白髪まじりで大きなハゲが見える。
>
> ポンタ「あのう、大丈夫ですか?」
>
> スシ「このクソ。誰に口を聞いてるのかわかってるか!」
>
> キョウスケ「へ...!?」
>
> スシ「おまえ、俺は東の国の大統領、皇帝だぞ!」
>
> ポンタ「え...ほ、ほんとに?で、でもそんな人がなんでこんなところに」
>
> スシ「全部お前らのせいだ。こんなもの配りやがって。俺は国のために尽くしてきた。こんな仕打ちを...許さんぞ」
>
> ポンタ・キョウスケ「...」
>
> キョウスケ「それってアムのことですか?」
>
> ポンタ「少しならおじいさんに分けてあげられるけど...でも」
>
> キョウスケ「うん、難しいかもな。これは人によって上限があるから」
>
> スシ「おまえ!おれの心は誰よりも清く正しいんだ、そんなもんで測られるかバカ」
>
> ポンタ「あ!思い出した。この人、昔の大統領だ」
>
> キョウスケ「え...ほんとだったの...そんな人がなんでこんなところでホームレスやってんだよ!」
>
> ポンタ「ニュースでは誰かの暗殺を指示したとかでやめたんだって」
>
> キョウスケ「おいおい、おじいさん、それ本当なのか?」
>
> スシ「全部ウソに決まってんだろ。おめえそんなこともわからんか」
>
> ポンタ「へえ、そうなんだ。本当はどういう話だったの」
>
> スシ「俺が国のためにやったことに反対する奴らがいて、そいつらを始末しろと部下に命令をだしたのはたしかに俺だ。しかし、全部部下がやったことで俺は知らん。俺と事件は無関係だ。それにこのことだって本当は表に出ないはずだった...なにせ表に出れば国益を損なう。国のためにならん。俺は常に国家のため国民のために仕事をしてきた。お前らは何も知らないただの低能バカだ」
>
> ポンタ・キョウスケ「...」、二人はしばし顔を見合わせた
>
> ポンタ「...おじいさん、困ってるなら少しだけど」 ポンタはそう言っていくらかお金を送信しようとした
>
> ポンタ「あ、あれ...なんで」
>
> キョウスケ「え?お、おいおい。こりゃ、いくらなんでも」
>
> ポンタはスシの口座にお金をいれることはできなかった。アムは持ち主の心理情報を読み取り上限額を設定する。悪人は一定額以上を持つことはできない
>
> スシ「ふん!この生ゴミが」スシはダンボールに置いているコインを睨みつけながら言った
>
> するとアイがポンタとキョウスケがいるところを通りがかる
>
> アイ「こんにちは」
>
> キョウスケ「ああ、アイか、ちょうどいいところに。このじいさん、困ってんだってよ。しかもアムが入らない」
>
> スシ「だれだおまえ?変な小娘め...だが、どこかで...」
>
> アイ「なんでこんなところにいるの」
>
> スシ「好きでいるわけじゃねえよ!」
>
> アイ「ここでは誰でも家がもらえるよ」アイはポンタの方を見てそう言った
>
> ポンタ「あ、そうか。そうだよ。おじいさん、もし住む場所がないなら」
>
> スシ「な、なんだって!?そんなこと俺は聞いてねえぞ!」
>
> スシ「どけ!!」
>
> スシはそういって3人を突き飛ばし行ってしまった
>
> キョウスケ「な、なんなんだあれは...。しかも、おい、これどうするよ」
>
> そこにはスシが残していったゴミが散乱していた。多くは昔の紙幣のようだ
>
> アイ「アイがもらっておくよ」
>
> アイはそう言って、そこにあったゴミと思えるようなものをなで、小さな箱を取りした
>
> ボタンを押すと路上にあったゴミが吸い込まれ、きれいになる
## 変化
東の国の元大統領であるスシは、その後、世界一の金持ちから世界一の貧乏人になります。
アム(コインの形をしている)は持ち主の心を読み取り、数値を個々人に配分します。これはスシがアムから世界で一番お金や権力を持ってはならない人物とそう評価されたということです。
当時のアムは宇宙最大のコンピュータと考えられていましたが、実際は違うことが後に判明します。
> ピンポーン
>
> スシ「だれだ!クソ鬱陶しい!!」
>
> 郊外に建ったばかりのスシの自宅、玄関のドアの前にアイが突っ立っていた
>
> スシ「ふん!おまえか。家がタダでもらえることを教えたやつ」
>
> スシはこのとき初めてアイをよく見た。しかし、この娘、どこかで見たような気がするのだ。俺が赤ん坊のときに...いや、子供の頃か...小さい頃どこかであった気がする。俺が知ってるようで知らないような思い出が
>
> スシ「...まあ、入れや」
>
> スシはアイを中にいれることにした。何かを思い出せるような気がしたからだ。思い出せないとどうにも気分が悪い。
>
> スシ「それでおまえ、なんのようだ?ただのガキだと思ってたが...」
>
> アイ「これ」
>
> アイがそういうと、部屋の景色が一瞬で変わった。そこは天井が見えないほど高く、ところどころキラキラと輝いていて、ありとあらゆる物がうず高く積まれている、とてつもない広い場所だった
>
> スシ「な!なん...だ...これ...お、俺の目が...」
>
> アイは前をゆっくりと歩いていく。スシはあたりを見回しながらアイに続いた
>
> アイが立ち止まると、そこには
>
> スシ「うん?あ!こ、これは、おれのカネじゃねえか!!おまえ、盗みやがったな!」
>
> アイ「これ、さっき触れたばかり。まだアイがあるかも」
>
> スシ「は?何言ってやがる...意味がわからねえ。アイ?そりゃたしかお前が呼ばれてた」
>
> そういったスシは言葉を失っていた。
>
> ここはどこだ...おれはたしか小娘が盗んだ俺のカネをつかもうとして...そして、どうなった。...いや、そんなことはどうでもいい。何もかもがどうでもよかった。そこで俺は、もう俺ではなかった。別のなにかだった。
>
> わからなかった。何もわからない。しばらく彷徨ったあと、そこで見覚えがある感覚に出会った。そして、そこからはわかるような気がした。そうだ、俺は覚えている。これは俺...俺が生まれたばかりの頃...。
>
> 両親は、こんなにも俺のことをかわいがってくれてたのか...そうだったな。知ってたはずなのに、いつの間にか俺は...。
>
> これは学校に通いはじめた俺。そうだった。純粋だった。多少の不安はあったが、俺は両親にずっと守られていたので、そこまでじゃなかった。
>
> そして、俺は...
>
> スシは頭がぐわんぐわんする感覚に襲われ、気がつくと、膝をついていた。周りの景色も...俺の家だ。
>
> スシ「.....く...くくう...お、おれは...」
>
> 気がつくとスシは泣いていた。まさか自分のような人間が泣くことになるとは思わなかった。しかもこの歳でだ。だが、さっき思い出したんだ...昔の俺を。昔の俺は泣いていたのだ。...そうだった。
>
> スシはひとしきり泣いたあと、ソファに腰を下ろした。そして、そばに立っているアイの方を向いた。
>
> スシ「...なにやらかしやがったんかわかんねえが、お前、あのときのやつだったんだな...」
>
> スシ「あのとき、俺に唯一、手を差し伸べてきたお前は...そう、俺の過去をすべて見たことがあったんだな...ずっと前から。生きるのに必死だったんだみんなそうなんだよ...お前が俺の中でそういったことを、俺は覚えているぞ...いや、思い出したが正しいか。あいつらが襲ってきたときだった」
>
> アイ「ここはいいところだね」
>
> スシ「...」
>
> アイ「変わりたければ大聖堂に行くといいよ。保護プログラムがあるからね」
>
> スシ「...そうか...助かる」
>
> アイ「またね」
>
> アイはそういうと姿を消した。
>
> その時、スシのポケットからピッという音が聞こえた気がした
このあともスシは何度か登場します。
私が好きな作品には、悪人が悪人で終わらない、というものが多いのです。
もしかしたらそこが一番のフィクションなのかもしれませんね。必ずしも現実を描きたいというわけではないのです。
## スシのモデル
スターウォーズのシスです。
そういえば、このスシというキャラにはこんなセリフがあります。
> 数日前、市民に襲われ、私の口はひん曲がった...だが、ますます帝国への意志は強くなったのだ!
## 何がしたいのか
あらゆる設定に言えることですが、この作品の設定は、そのほとんどが物語に現実感を持たせるために存在します。もしくは、面白さを追求するためですね。
現実感がないお話というものは、あまり面白くないのです。
では、現実感とは一体何なのでしょう。
それは人々の生活や日常に潜んでいるものです。
生活や日常に当たり前のように存在し、なくてはならないもの。
それらを優先順位を付け、重要なものをピックアップし、分解したり、調べたり。
その3つが、貨幣だったり、言語だったり、宇宙だったりするわけです。まあ、最後の宇宙は、単に私が好きなだけですが。
それでも宇宙開発というのは、私達の生活や日常にかなり大きな影響を及ぼしているのですよ。
これがどうなっていて、これからどうなっていくのか。過去、現在、未来の想像を作品に取り込んでいます。

View File

@ -9,9 +9,10 @@ date: "2024-01-03"
<div class="story">
[@yui.syui.ai](https://bsky.social/profile/yui.syui.ai) /card
<code>[ai/bot](https://git.syui.ai/ai/bot/wiki/help)</code> からカードを引くことができます。
<code>[ai/bot](https://git.syui.ai/ai/bot)</code> からカードを引くことができます。
<blockquote class="bluesky-embed" data-bluesky-uri="at://did:plc:4hqjfn7m6n5hno3doamuhgef/app.bsky.feed.post/3kq4jz4wxdb2c" data-bluesky-cid="bafyreiesdjxxblnblyfiew7smtbrsbd363ksfylsyrrtjour6me3dinbye"></blockquote>
<script async src="https://embed.bsky.app/static/embed.js" charset="utf-8"></script>
</div>
@ -20,52 +21,3 @@ date: "2024-01-03"
<!--more-->
<div class="top-card">
<p>
<img src="/card/001.webp">
<img src="/card/002.webp">
<img src="/card/003.webp">
<img src="/card/004.webp">
<img src="/card/005.webp">
<img src="/card/006.webp">
<img src="/card/007.webp">
<img src="/card/010.webp">
<img src="/card/011.webp">
<img src="/card/012.webp">
<img src="/card/013.webp">
<img src="/card/014.webp">
</p>
<!--
<p>
<img src="/card/096.webp">
<img src="/card/097.webp">
<img src="/card/098.webp">
<img src="/card/099.webp">
<img src="/card/100.webp">
<img src="/card/101.webp">
<img src="/card/102.webp">
<img src="/card/103.webp">
<img src="/card/104.webp">
<img src="/card/105.webp">
<img src="/card/106.webp">
<img src="/card/107.webp">
<img src="/card/108.webp">
<img src="/card/109.webp">
<img src="/card/110.webp">
<img src="/card/111.webp">
<img src="/card/112.webp">
<img src="/card/113.webp">
<img src="/card/114.webp">
<img src="/card/116.webp">
<img src="/card/117.webp">
<img src="/card/118.webp">
<img src="/card/119.webp">
<img src="/card/120.webp">
<img src="/card/121.webp">
</p>
-->
</div>

View File

@ -3,6 +3,7 @@ date = "2020-04-25"
title = "ガラスの上"
slug = "01"
type = "novel"
tags = ["novel"]
+++

View File

@ -3,6 +3,7 @@ date = "2020-04-26"
title = "大気圏"
slug = "02"
type = "novel"
tags = ["novel"]
+++

View File

@ -3,6 +3,7 @@ date = "2020-04-27"
title = "前日"
slug = "03"
type = "novel"
tags = ["novel"]
+++
あれから数日が過ぎた。いや、もしかしたら数年だったかもしれない。ここでは時間の感覚が大きく狂うので仕方ない。

View File

@ -3,6 +3,7 @@ date = "2020-04-28"
title = "銀河鉄道"
slug = "04"
type = "novel"
tags = ["novel"]
+++
今日もいつもどおり起床し、みんなゾロゾロと境界に向かった。

View File

@ -3,6 +3,7 @@ date = "2020-06-01"
title = "駅"
slug = "05"
type = "novel"
tags = ["novel"]
+++
キタムラは、銀河鉄道の車内に乗り込んだ。周りを見渡すと、座席は横に連なり、街灯のような明かりが薄ぼんやりと輝いている。

View File

@ -3,6 +3,7 @@ date = "2020-06-02"
title = "アイ"
slug = "06"
type = "novel"
tags = ["novel"]
+++
フタネ駅に突然やってきた子は、その後、何やら小さな機械を取り出し、それをいじり始めた。

View File

@ -3,6 +3,7 @@ date = "2022-07-07"
title = "龍の記憶"
slug = "07"
type = "novel"
tags = ["novel"]
+++
> 漫画の第二章にあたる部分を文章化

View File

@ -3,6 +3,7 @@ date = "2022-07-08"
title = "銀河団"
slug = "08"
type = "novel"
tags = ["novel"]
+++
> アイが天の川を使ったあとを断片的に文章化

View File

@ -1,8 +1,9 @@
+++
date = "2022-07-09"
title = "宇宙外"
title = "宇宙外"
slug = "09"
type = "novel"
tags = ["novel"]
+++
> アイが天の川を使ったあとを断片的に文章化

View File

@ -3,6 +3,7 @@ date = "2023-05-20"
title = "存在の花"
slug = "10"
type = "novel"
tags = ["novel"]
+++
> 漫画の第二章を文章化

View File

@ -8,6 +8,7 @@
{{ range .Data.Pages.Reverse }}
<li class="blog-list-first">
<a href="{{.Permalink}}">{{.Title}}</a> <span class="blog-date">{{ .Date.Local.Format "2006-01-02" }}</span>
{{ with .Params.tags }}{{ range . }}<button class="tag"><a href="/tags/{{ . }}/">{{ . }}</a>{{ end }}</button>{{ end }}
</li>
{{ end }}
</ul>
@ -15,6 +16,6 @@
</div>
</div>
</div>
{{ partial "footer" . }}
{{ partial "footer" . }}
</body>
</html>

View File

@ -5,11 +5,17 @@
<article>
<div class="content">
{{ if ne .Lastmod .Date }}<div class="post-time-date">{{ .Lastmod.Format "2006-01-02" }}</div>{{ end }}
<h2>{{ .Title }}</h2>
<h1>{{ .Title }}</h1>
{{ .Content }}
</div>
</article>
<!--
{{ $s := path.Dir (.Permalink | relURL) }}
{{ $o := index (split $s "/") 1 }}
<div class="pager"><a href="{{ printf "/%s" $o }}">{{ $o }}</a></div>
-->
</div>
{{ partial "footer.html" . }}
</body>

View File

@ -9,7 +9,7 @@
{{ with .Resources.Match "*.webp" }}
<div class="top-card">
<p>
{{ range sort . }}
{{ range first 15 . }}
<img src="{{ .RelPermalink }}">
{{ end }}
</p>

View File

@ -2,7 +2,10 @@
{{ partial "navbar.html" . }}
{{ partial "header.html" . }}
{{ partial "content.html" . }}
</div>
{{ partial "footer.html" . }}
</body>
</html>

View File

@ -1,4 +1,6 @@
<div id="container">
<div class="outer">
<div id="blog-archives" class="category">
<ul class="cp_list">
@ -11,10 +13,14 @@
</li>
{{ range $index,$value := (where $.Site.RegularPages.ByDate.Reverse "Section" "blog") }}
{{ if lt $index 1 }}
<li class="blog-list-first" style="display:block;"> <a href="{{.Permalink}}">{{.Title}}</a> <span class="blog-date">{{ .Date.Local.Format "2006-01-02" }}</span> </li>
{{ if lt $index 3 }}
<li class="blog-list-first" style="display:block;"> <a href="{{.Permalink}}">{{.Title}}</a> <span class="blog-date">{{ .Date.Local.Format "2006-01-02" }}</span>
{{ with .Params.tags }}{{ range . }}<button class="tag"><a href="/tags/{{ . }}/">{{ . }}</a>{{ end }}</button>{{ end }}
</li>
{{ else }}
<li class="blog-list-all" style="display:none;"> <a href="{{.Permalink}}">{{.Title}}</a> <span class="blog-date">{{ .Date.Local.Format "2006-01-02" }}</span> </li>
<li class="blog-list-all" style="display:none;"> <a href="{{.Permalink}}">{{.Title}}</a> <span class="blog-date">{{ .Date.Local.Format "2006-01-02" }}</span>
{{ with .Params.tags }}{{ range . }}<button class="tag"><a href="/tags/{{ . }}/">{{ . }}</a>{{ end }}</button>{{ end }}
</li>
{{ end }}
{{ end }}
@ -24,7 +30,7 @@
{{ if or (eq $t "chara") (eq $t "story") (eq $t "card") (eq $t "vrm") }}
<li class="commit">
<span class="icon-moji_a"></span>
<a href="#header"><span class="icon-moji_a"></span></a>
</li>
<li class="top">
@ -40,7 +46,7 @@
{{ end }}
<li class="commit">
<span class="icon-moji_a"></span>
<a href="#header"><span class="icon-moji_a"></span></a>
<!--
<i class="fa-solid fa-code-branch"></i>
<i class="fa-solid fa-code-commit"></i>
@ -48,8 +54,13 @@
-->
</li>
</ul>
</div>
</div>
</div>
</div>

View File

@ -23,7 +23,7 @@
<link rel="apple-touch-icon" href="/icon/apple-touch-icon.png" />
<link rel="stylesheet" href="/css/style.css" />
<link rel="stylesheet" href="/css/svg.css" />
<link rel="stylesheet" href="/pkg/icomoon/css/icomoon.css" />
<link rel="stylesheet" href="/pkg/icomoon/icomoon.css" />
<link rel="stylesheet" href="/pkg/font-awesome/css/all.min.css" />
<script type="application/ld+json">
{
@ -33,11 +33,10 @@
"url": "{{ .Site.BaseURL }}"
}
</script>
<script src="/pkg/hotkeys-js/dist/hotkeys.min.js"></script>
<script src="/pkg/hotkeys-js/dist/terminal.js"></script>
<script src="/js/index.js"></script>
{{ range .AlternativeOutputFormats -}}
{{ printf `<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }}
{{ end -}}
</head>

View File

@ -1,11 +1,18 @@
<body>
<div class="containerx">
{{ $s := path.Dir (.Permalink | relURL) }}
{{ $t := index (split $s "/") 2 }}
{{ $o := index (split $s "/") 1 }}
<header id="header">
<!--
{{ partial "particles.html" . }}
-->
<div class="logo">
{{ partial "svg.html" . }}
{{ partial "term.html" . }}
</div>
</header>
@ -34,9 +41,9 @@
<script src=/bitcoin/app.js></script>
-->
<a class="menu-link-left-black" href="https://card.syui.ai/ai"><i class="fa-solid fa-copy"></i></a>
<a class="menu-link-left-black" href="https://manga.syui.ai"><i class="fa-regular fa-comment-dots"></i></a>
<a class="menu-link-left-black" href="https://vrm.syui.ai"><i class="fa-solid fa-cube"></i></a>
<a class="menu-link-left-black" href="https://card.syui.ai/ai"><span class="icon-card"></span></a>
<a class="menu-link-left-black" href="https://manga.syui.ai"><span class="icon-book"></span></a>
<a class="menu-link-left-black" href="https://vrm.syui.ai"><span class="icon-game"></span></a>
<a class="menu-link-left-black" href="https://term.syui.ai"><span class="icon-aiterm"></span></a>
<a class="menu-link-left-black" href="https://git.syui.ai/ai"><span class="icon-git_bg"></span></a>

View File

@ -3,8 +3,9 @@
<div class="navbar-nav">
<span class="navbar-title-text"><a href="/"><span class="icon-ai"></span></a></span>
<div class="navbar-nav-left">
<a class="navbar-brand" href="/story">ストーリー</a>
<a class="navbar-brand" href="/blog">ブログ</a>
<a class="navbar-brand" href="/chara">キャラクター</a>
<a class="navbar-brand" href="/story">ストーリー</a>
<a class="navbar-brand" href="/card">カード</a>
</div>
</div>

View File

@ -0,0 +1,5 @@
<div id="particles-js"></div>
<script src="/pkg/particles/particles.min.js"></script>
<script src="/pkg/particles/stats.min.js"></script>
<script src="/pkg/particles/config.js"></script>
<link rel="stylesheet" href="/pkg/particles/particles.css" />

View File

@ -7,8 +7,3 @@
</div>
</div>
</div>
<div id="aiterm" style="display:none;">
<iframe src="https://term.syui.ai" allowfullscreen frameborder="0" style="width:100%;height: 400px;" id="terminal-input"></iframe>
</div>

View File

@ -0,0 +1,16 @@
<div id="aiterm" style="display:none;">
<link rel="stylesheet" href="https://term.syui.ai/term/pkg/jquery.terminal/css/jquery.terminal.css" />
<link rel="stylesheet" href="https://term.syui.ai/term/css/terminal.css" />
<script src="https://term.syui.ai/term/pkg/jquery.ajax/jquery.min.js"></script>
<script src="https://term.syui.ai/term/pkg/axios/dist/axios.min.js"></script>
<script src="https://term.syui.ai/term/pkg/jquery.terminal/js/jquery.terminal.min.js"></script>
<script src="https://term.syui.ai/term/pkg/jquery.terminal/js/jquery.mousewheel-min.js"></script>
<script src="https://term.syui.ai/term/js/terminal.js"></script>
<app></app>
<script src="https://term.syui.ai/term/js/bundle.js"></script>
<script src="https://term.syui.ai/term/pkg/hotkeys-js/dist/hotkeys.min.js"></script>
<script src="https://term.syui.ai/term/pkg/hotkeys-js/dist/terminal.js"></script>
<!--
<iframe src="https://term.syui.ai" allowfullscreen frameborder="0" style="width:100%;height: 400px;" id="terminal-input"></iframe>
-->
</div>

View File

View File

@ -49,6 +49,7 @@ footer#footer {
color: #fff700;
font-size: 20px;
background-color:#313131;
position: relative;
}
footer#footer a {
@ -97,20 +98,13 @@ h3 {
margin-bottom: 4px;
}
blockquote {
background: #fff;
margin: 0px;
padding: 20px;
}
nav#article-nav {
margin: 30px 0px;
}
ul {
list-style-type: none;
display: list-item;
list-style-type: none;
display: list-item;
}
ul.cp_list {
@ -207,8 +201,9 @@ pre > code {
}
h2 {
font-size: 20px;
line-height: 2rem;
padding-bottom:2rem;
padding:2rem 0;
}
span.tag {
@ -282,7 +277,7 @@ span.menu-right-top {
.vrm {
display: none;
text-align: center;
overflow: hidden;
overflow: hidden;
}
.vrm iframe {
@ -354,6 +349,7 @@ iframe.manga {
header#header {
background-color: #313131;
position: relative;
}
.top-card {
@ -383,10 +379,11 @@ header#header {
.vrm iframe {
width:100%;
}
button.tag {
display:none;
}
}
.nav {
display: -ms-flexbox;
display: flex;
@ -444,8 +441,8 @@ header#header {
border-color: #dee2e6 #dee2e6 #fff;
}
.navbar-nav-right > a > img {
width:20px;
padding:5px;
width:20px;
padding:5px;
}
.nav-tabs .dropdown-menu {
@ -898,11 +895,11 @@ a:hover > .navbar-light .navbar-brand {
}
.navbar-nav-right a span.icon-syui {
font-size: 33px;
font-size: 33px;
}
.navbar-nav-right a span.icon-ai {
font-size: 33px;
font-size: 33px;
}
.navbar-nav-right > a > i {
@ -1033,16 +1030,16 @@ span.navbar-title-text > a span.icon-ai {
}
i.fa-brands.fa-unity {
color: #fff700;
color: #fff700;
}
i.fa-brands.fa-git-alt {
color: #fff700;
color: #fff700;
}
model-viewer {
width: 100%;
height: 400px;
width: 100%;
height: 400px;
}
table {
@ -1119,23 +1116,56 @@ li.blog-menu button:hover {
border-radius: 4px;
}
a.menu-link-left-black span.icon-aiterm {
color: #fff700;
}
a.menu-link-left-black span.icon-git_bg {
a.menu-link-left-black {
color: #fff700;
}
li.commit {
background-color: #f1f1f1;
padding: 40px;
font-size: 25px;
text-align: center;
color: #fff;
background-color: #f1f1f1;
padding: 60px;
font-size: 30px;
text-align: center;
color: #fff;
}
li.commit a {
color: #fff;
}
li.commit a:hover {
transition: 1.0s ;
color: #313131;
}
a.li-link-left {
float: right;
padding-right: 20px;
float: right;
padding-right: 20px;
}
button.tag {
float: right;
border:none;
background-color: #f1f1f1;
}
li.commit a span.icon-moji_a {
font-size: 30px;
}
blockquote {
background: #fff;
padding: 20px;
margin: 20px 0;
}
.pager {
margin:100px 0;
width:100%;
text-align: center;
padding: 30px 0;
background: #313131;
}
.pager a {
color: #fff700;
}

View File

@ -1,23 +0,0 @@
MIT License
Copyright (c) 2015-present, Kenny Wong.
Copyright (c) 2011-2013 Thomas Fuchs (https://github.com/madrobby/keymaster)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,441 +0,0 @@
# Hotkeys
<!--dividing-->
[![Buy me a coffee](https://img.shields.io/badge/Buy%20me%20a%20coffee-048754?logo=buymeacoffee)](https://jaywcjlove.github.io/#/sponsor)
[![](https://img.shields.io/npm/dm/hotkeys-js?logo=npm)](https://www.npmjs.com/package/hotkeys-js)
[![](https://img.shields.io/github/stars/jaywcjlove/hotkeys-js.svg)](https://github.com/jaywcjlove/hotkeys/stargazers)
![no dependencies](http://jaywcjlove.github.io/sb/status/no-dependencies.svg)
[![GitHub Actions CI](https://github.com/jaywcjlove/hotkeys-js/actions/workflows/ci.yml/badge.svg)](https://github.com/jaywcjlove/hotkeys-js/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/jaywcjlove/hotkeys/badge.svg?branch=master)](https://coveralls.io/github/jaywcjlove/hotkeys?branch=master)
[![jaywcjlove/hotkeys-js](https://jaywcjlove.github.io/sb/lang/chinese.svg)](https://github.com/jaywcjlove/hotkeys-js/blob/master/README-zh.md)
[![jaywcjlove/hotkeys-js](https://jaywcjlove.github.io/sb/ico/gitee.svg)](https://gitee.com/jaywcjlove/hotkeys)
HotKeys.js is an input capture library with some very special features, it is easy to pick up and use, has a reasonable footprint ([~6kB](https://bundlephobia.com/result?p=hotkeys-js)) (gzipped: **`2.8kB`**), and has no dependencies. It should not interfere with any JavaScript libraries or frameworks. Official document [demo preview](https://jaywcjlove.github.io/hotkeys-js). [More examples](https://github.com/jaywcjlove/hotkeys-js/issues?q=label%3ADemo+).
```bash
╭┈┈╮ ╭┈┈╮ ╭┈┈╮
┆ ├┈┈..┈┈┈┈┈.┆ └┈╮┆ ├┈┈..┈┈┈┈┈..┈┈.┈┈..┈┈┈┈┈.
┆ ┆┆ □ ┆┆ ┈┤┆ < ┆ -__┘┆ ┆ ┆┆__ ┈┈┤
╰┈┈┴┈┈╯╰┈┈┈┈┈╯╰┈┈┈┈╯╰┈┈┴┈┈╯╰┈┈┈┈┈╯╰┈┈┈ ┆╰┈┈┈┈┈╯
╰┈┈┈┈┈╯
```
## Usage
You will need `Node.js` installed on your system.
```bash
npm install hotkeys-js --save
```
```js
import hotkeys from 'hotkeys-js';
hotkeys('f5', function(event, handler){
// Prevent the default refresh event under WINDOWS system
event.preventDefault()
alert('you pressed F5!')
});
```
Or manually download and link **hotkeys.js** in your HTML, It can also be downloaded via [UNPKG](https://unpkg.com/hotkeys-js/dist/):
CDN: [UNPKG](https://unpkg.com/hotkeys-js/dist/) | [jsDelivr](https://cdn.jsdelivr.net/npm/hotkeys-js@3.7.3/) | [Githack](https://raw.githack.com/jaywcjlove/hotkeys/master/dist/hotkeys.min.js) | [Statically](https://cdn.statically.io/gh/jaywcjlove/hotkeys/master/dist/hotkeys.min.js) | [bundle.run](https://bundle.run/hotkeys-js@3.7.3)
```html
<script src="https://unpkg.com/hotkeys-js/dist/hotkeys.min.js"></script>
<script type="text/javascript">
hotkeys('ctrl+a,ctrl+b,r,f', function (event, handler){
switch (handler.key) {
case 'ctrl+a': alert('you pressed ctrl+a!');
break;
case 'ctrl+b': alert('you pressed ctrl+b!');
break;
case 'r': alert('you pressed r!');
break;
case 'f': alert('you pressed f!');
break;
default: alert(event);
}
});
</script>
```
### Used in React
[react-hotkeys](https://github.com/jaywcjlove/react-hotkeys) is the React component that listen to keydown and keyup keyboard events, defining and dispatching keyboard shortcuts. Detailed use method please see its documentation [react-hotkeys](https://github.com/jaywcjlove/react-hotkeys).
[react-hotkeys-hook](https://github.com/JohannesKlauss/react-hotkeys-hook) - React hook for using keyboard shortcuts in components. Make sure that you have at least version 16.8 of react and react-dom installed, or otherwise hooks won't work for you.
## Browser Support
Hotkeys.js has been tested and should work in.
```shell
Internet Explorer 6+
Safari
Firefox
Chrome
```
## Supported Keys
HotKeys understands the following modifiers: `⇧`, `shift`, `option`, `⌥`, `alt`, `ctrl`, `control`, `command`, and `⌘`.
The following special keys can be used for shortcuts: backspace, tab, clear, enter, return, esc, escape, space, up, down, left, right, home, end, pageup, pagedown, del, delete, f1 through f19, num_0 through num_9, num_multiply, num_add, num_enter, num_subtract, num_decimal, num_divide.
`⌘` Command()
`⌃` Control
`⌥` Option(alt)
`⇧` Shift
`⇪` Caps Lock(Capital)
~~`fn` Does not support fn~~
`↩︎` return/Enter space
## Defining Shortcuts
One global method is exposed, key which defines shortcuts when called directly.
```js
hotkeys([keys:<String>], [option:[string|object|function]], [callback:<function>])
```
```js
hotkeys('f5', function(event, handler) {
// Prevent the default refresh event under WINDOWS system
event.preventDefault();
alert('you pressed F5!');
});
// Returning false stops the event and prevents default browser events
// Mac OS system defines `command + r` as a refresh shortcut
hotkeys('ctrl+r, command+r', function() {
alert('stopped reload!');
return false;
});
// Single key
hotkeys('a', function(event,handler){
//event.srcElement: input
//event.target: input
if(event.target === "input"){
alert('you pressed a!')
}
alert('you pressed a!')
});
// Key Combination
hotkeys('ctrl+a,ctrl+b,r,f', function (event, handler){
switch (handler.key) {
case 'ctrl+a': alert('you pressed ctrl+a!');
break;
case 'ctrl+b': alert('you pressed ctrl+b!');
break;
case 'r': alert('you pressed r!');
break;
case 'f': alert('you pressed f!');
break;
default: alert(event);
}
});
hotkeys('ctrl+a+s', function() {
alert('you pressed ctrl+a+s!');
});
// Using a scope
hotkeys('*','wcj', function(event){
console.log('do something', event);
});
```
#### option
- `scope<String>`
- `element<HTMLElement>`
- `keyup<Boolean>`
- `keydown<Boolean>`
- `splitKey<string>` (default is `+`)
- `capture<Boolean>`
- `single<Boolean>`
```js
hotkeys('o, enter', {
scope: 'wcj',
element: document.getElementById('wrapper'),
}, function() {
console.log('do something else');
});
hotkeys('ctrl-+', { splitKey: '-' }, function(e) {
console.log('you pressed ctrl and +');
});
hotkeys('+', { splitKey: '-' }, function(e){
console.log('you pressed +');
})
```
**keyup**
**key down** and **key up** both perform callback events.
```js
hotkeys('ctrl+a,alt+a+s', {keyup: true}, function(event, handler) {
if (event.type === 'keydown') {
console.log('keydown:', event.type, handler, handler.key);
}
if (event.type === 'keyup') {
console.log('keyup:', event.type, handler, handler.key);
}
});
```
## API REFERENCE
Asterisk "*"
Modifier key judgments
```js
hotkeys('*', function() {
if (hotkeys.shift) {
console.log('shift is pressed!');
}
if (hotkeys.ctrl) {
console.log('ctrl is pressed!');
}
if (hotkeys.alt) {
console.log('alt is pressed!');
}
if (hotkeys.option) {
console.log('option is pressed!');
}
if (hotkeys.control) {
console.log('control is pressed!');
}
if (hotkeys.cmd) {
console.log('cmd is pressed!');
}
if (hotkeys.command) {
console.log('command is pressed!');
}
});
```
### setScope
Use the `hotkeys.setScope` method to set scope. There can only be one active scope besides 'all'. By default 'all' is always active.
```js
// Define shortcuts with a scope
hotkeys('ctrl+o, ctrl+alt+enter', 'issues', function() {
console.log('do something');
});
hotkeys('o, enter', 'files', function() {
console.log('do something else');
});
// Set the scope (only 'all' and 'issues' shortcuts will be honored)
hotkeys.setScope('issues'); // default scope is 'all'
```
### getScope
Use the `hotkeys.getScope` method to get scope.
```js
hotkeys.getScope();
```
### deleteScope
Use the `hotkeys.deleteScope` method to delete a scope. This will also remove all associated hotkeys with it.
```js
hotkeys.deleteScope('issues');
```
You can use second argument, if need set new scope after deleting.
```js
hotkeys.deleteScope('issues', 'newScopeName');
```
### unbind
Similar to defining shortcuts, they can be unbound using `hotkeys.unbind`.
```js
// unbind 'a' handler
hotkeys.unbind('a');
// Unbind a hotkeys only for a single scope
// If no scope is specified it defaults to the current scope (hotkeys.getScope())
hotkeys.unbind('o, enter', 'issues');
hotkeys.unbind('o, enter', 'files');
```
Unbind events through functions.
```js
function example() {
hotkeys('a', example);
hotkeys.unbind('a', example);
hotkeys('a', 'issues', example);
hotkeys.unbind('a', 'issues', example);
}
```
To unbind everything.
```js
hotkeys.unbind();
```
### isPressed
For example, `hotkeys.isPressed(77)` is true if the `M` key is currently pressed.
```js
hotkeys('a', function() {
console.log(hotkeys.isPressed('a')); //=> true
console.log(hotkeys.isPressed('A')); //=> true
console.log(hotkeys.isPressed(65)); //=> true
});
```
### trigger
trigger shortcut key event
```js
hotkeys.trigger('ctrl+o');
hotkeys.trigger('ctrl+o', 'scope2');
```
### getPressedKeyCodes
Returns an array of key codes currently pressed.
```js
hotkeys('command+ctrl+shift+a,f', function() {
console.log(hotkeys.getPressedKeyCodes()); //=> [17, 65] or [70]
})
```
### getPressedKeyString
Returns an array of key codes currently pressed.
```js
hotkeys('command+ctrl+shift+a,f', function() {
console.log(hotkeys.getPressedKeyString()); //=> ['⌘', '⌃', '⇧', 'A', 'F']
})
```
### getAllKeyCodes
Get a list of all registration codes.
```js
hotkeys('command+ctrl+shift+a,f', function() {
console.log(hotkeys.getAllKeyCodes());
// [
// { scope: 'all', shortcut: 'command+ctrl+shift+a', mods: [91, 17, 16], keys: [91, 17, 16, 65] },
// { scope: 'all', shortcut: 'f', mods: [], keys: [42] }
// ]
})
```
### filter
By default hotkeys are not enabled for `INPUT` `SELECT` `TEXTAREA` elements. `Hotkeys.filter` to return to the `true` shortcut keys set to play a role, `false` shortcut keys set up failure.
```js
hotkeys.filter = function(event){
return true;
}
//How to add the filter to edit labels. <div contentEditable="true"></div>
//"contentEditable" Older browsers that do not support drops
hotkeys.filter = function(event) {
var target = event.target || event.srcElement;
var tagName = target.tagName;
return !(target.isContentEditable || tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
}
hotkeys.filter = function(event){
var tagName = (event.target || event.srcElement).tagName;
hotkeys.setScope(/^(INPUT|TEXTAREA|SELECT)$/.test(tagName) ? 'input' : 'other');
return true;
}
```
### noConflict
Relinquish HotKeyss control of the `hotkeys` variable.
```js
var k = hotkeys.noConflict();
k('a', function() {
console.log("do something")
});
hotkeys()
// -->Uncaught TypeError: hotkeys is not a function(anonymous function)
// @ VM2170:2InjectedScript._evaluateOn
// @ VM2165:883InjectedScript._evaluateAndWrap
// @ VM2165:816InjectedScript.evaluate @ VM2165:682
```
## Development
To develop, Install dependencies, Get the code:
```shell
$ git https://github.com/jaywcjlove/hotkeys.git
$ cd hotkeys # Into the directory
$ npm install # or yarn install
```
To develop, run the self-reloading build:
```shell
$ npm run watch
```
Run Document Website Environment.
```shell
$ npm run doc
```
To contribute, please fork Hotkeys.js, add your patch and tests for it (in the `test/` folder) and submit a pull request.
```shell
$ npm run test
$ npm run test:watch # Development model
```
## Contributors
As always, thanks to our amazing contributors!
<a href="https://github.com/jaywcjlove/hotkeys-js/graphs/contributors">
<img src="https://jaywcjlove.github.io/hotkeys-js/CONTRIBUTORS.svg" />
</a>
Made with [github-action-contributors](https://github.com/jaywcjlove/github-action-contributors).
## License
[MIT © Kenny Wong](./LICENSE)

View File

@ -1,13 +0,0 @@
Explanation of Build Files
---
| UMD | Size | CommonJS | Size | ES Module | Size |
| ---- | ---- | ---- | ---- | ---- | ---- |
| hotkeys.js | 8.37kb | hotkeys.common.js | 8.13kb | hotkeys.esm.js | 8.12kb |
| hotkeys.min.js | 3.62kb (gzipped: 1.73kb) | hotkeys.common.min.js | (gzipped: 1.84kb) | - | - |
- [UMD](https://github.com/umdjs/umd): UMD builds can be used directly in the browser via a `<script>` tag.
- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1): CommonJS builds are intended for use with older bundlers like [browserify](http://browserify.org/) or [webpack 1](https://webpack.github.io/).
- [ES Module](http://exploringjs.com/es6/ch_modules.html): ES module builds are intended for use with modern bundlers like [webpack 2](https://webpack.js.org/) or [rollup](http://rollupjs.org/).

View File

@ -1,677 +0,0 @@
/**!
* hotkeys-js v3.13.7
* A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies.
*
* Copyright (c) 2024 kenny wong <wowohoo@qq.com>
* https://github.com/jaywcjlove/hotkeys-js.git
*
* @website: https://jaywcjlove.github.io/hotkeys-js
* Licensed under the MIT license
*/
'use strict';
const isff = typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase().indexOf('firefox') > 0 : false;
// 绑定事件
function addEvent(object, event, method, useCapture) {
if (object.addEventListener) {
object.addEventListener(event, method, useCapture);
} else if (object.attachEvent) {
object.attachEvent("on".concat(event), method);
}
}
function removeEvent(object, event, method, useCapture) {
if (object.removeEventListener) {
object.removeEventListener(event, method, useCapture);
} else if (object.detachEvent) {
object.detachEvent("on".concat(event), method);
}
}
// 修饰键转换成对应的键码
function getMods(modifier, key) {
const mods = key.slice(0, key.length - 1);
for (let i = 0; i < mods.length; i++) mods[i] = modifier[mods[i].toLowerCase()];
return mods;
}
// 处理传的key字符串转换成数组
function getKeys(key) {
if (typeof key !== 'string') key = '';
key = key.replace(/\s/g, ''); // 匹配任何空白字符,包括空格、制表符、换页符等等
const keys = key.split(','); // 同时设置多个快捷键,以','分割
let index = keys.lastIndexOf('');
// 快捷键可能包含',',需特殊处理
for (; index >= 0;) {
keys[index - 1] += ',';
keys.splice(index, 1);
index = keys.lastIndexOf('');
}
return keys;
}
// 比较修饰键的数组
function compareArray(a1, a2) {
const arr1 = a1.length >= a2.length ? a1 : a2;
const arr2 = a1.length >= a2.length ? a2 : a1;
let isIndex = true;
for (let i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) === -1) isIndex = false;
}
return isIndex;
}
// Special Keys
const _keyMap = {
backspace: 8,
'⌫': 8,
tab: 9,
clear: 12,
enter: 13,
'↩': 13,
return: 13,
esc: 27,
escape: 27,
space: 32,
left: 37,
up: 38,
right: 39,
down: 40,
del: 46,
delete: 46,
ins: 45,
insert: 45,
home: 36,
end: 35,
pageup: 33,
pagedown: 34,
capslock: 20,
num_0: 96,
num_1: 97,
num_2: 98,
num_3: 99,
num_4: 100,
num_5: 101,
num_6: 102,
num_7: 103,
num_8: 104,
num_9: 105,
num_multiply: 106,
num_add: 107,
num_enter: 108,
num_subtract: 109,
num_decimal: 110,
num_divide: 111,
'⇪': 20,
',': 188,
'.': 190,
'/': 191,
'`': 192,
'-': isff ? 173 : 189,
'=': isff ? 61 : 187,
';': isff ? 59 : 186,
'\'': 222,
'[': 219,
']': 221,
'\\': 220
};
// Modifier Keys
const _modifier = {
// shiftKey
'⇧': 16,
shift: 16,
// altKey
'⌥': 18,
alt: 18,
option: 18,
// ctrlKey
'⌃': 17,
ctrl: 17,
control: 17,
// metaKey
'⌘': 91,
cmd: 91,
command: 91
};
const modifierMap = {
16: 'shiftKey',
18: 'altKey',
17: 'ctrlKey',
91: 'metaKey',
shiftKey: 16,
ctrlKey: 17,
altKey: 18,
metaKey: 91
};
const _mods = {
16: false,
18: false,
17: false,
91: false
};
const _handlers = {};
// F1~F12 special key
for (let k = 1; k < 20; k++) {
_keyMap["f".concat(k)] = 111 + k;
}
let _downKeys = []; // 记录摁下的绑定键
let winListendFocus = null; // window是否已经监听了focus事件
let _scope = 'all'; // 默认热键范围
const elementEventMap = new Map(); // 已绑定事件的节点记录
// 返回键码
const code = x => _keyMap[x.toLowerCase()] || _modifier[x.toLowerCase()] || x.toUpperCase().charCodeAt(0);
const getKey = x => Object.keys(_keyMap).find(k => _keyMap[k] === x);
const getModifier = x => Object.keys(_modifier).find(k => _modifier[k] === x);
// 设置获取当前范围(默认为'所有'
function setScope(scope) {
_scope = scope || 'all';
}
// 获取当前范围
function getScope() {
return _scope || 'all';
}
// 获取摁下绑定键的键值
function getPressedKeyCodes() {
return _downKeys.slice(0);
}
function getPressedKeyString() {
return _downKeys.map(c => getKey(c) || getModifier(c) || String.fromCharCode(c));
}
function getAllKeyCodes() {
const result = [];
Object.keys(_handlers).forEach(k => {
_handlers[k].forEach(_ref => {
let {
key,
scope,
mods,
shortcut
} = _ref;
result.push({
scope,
shortcut,
mods,
keys: key.split('+').map(v => code(v))
});
});
});
return result;
}
// 表单控件控件判断 返回 Boolean
// hotkey is effective only when filter return true
function filter(event) {
const target = event.target || event.srcElement;
const {
tagName
} = target;
let flag = true;
const isInput = tagName === 'INPUT' && !['checkbox', 'radio', 'range', 'button', 'file', 'reset', 'submit', 'color'].includes(target.type);
// ignore: isContentEditable === 'true', <input> and <textarea> when readOnly state is false, <select>
if (target.isContentEditable || (isInput || tagName === 'TEXTAREA' || tagName === 'SELECT') && !target.readOnly) {
flag = false;
}
return flag;
}
// 判断摁下的键是否为某个键返回true或者false
function isPressed(keyCode) {
if (typeof keyCode === 'string') {
keyCode = code(keyCode); // 转换成键码
}
return _downKeys.indexOf(keyCode) !== -1;
}
// 循环删除handlers中的所有 scope(范围)
function deleteScope(scope, newScope) {
let handlers;
let i;
// 没有指定scope获取scope
if (!scope) scope = getScope();
for (const key in _handlers) {
if (Object.prototype.hasOwnProperty.call(_handlers, key)) {
handlers = _handlers[key];
for (i = 0; i < handlers.length;) {
if (handlers[i].scope === scope) {
const deleteItems = handlers.splice(i, 1);
deleteItems.forEach(_ref2 => {
let {
element
} = _ref2;
return removeKeyEvent(element);
});
} else {
i++;
}
}
}
}
// 如果scope被删除将scope重置为all
if (getScope() === scope) setScope(newScope || 'all');
}
// 清除修饰键
function clearModifier(event) {
let key = event.keyCode || event.which || event.charCode;
const i = _downKeys.indexOf(key);
// 从列表中清除按压过的键
if (i >= 0) {
_downKeys.splice(i, 1);
}
// 特殊处理 cmmand 键,在 cmmand 组合快捷键 keyup 只执行一次的问题
if (event.key && event.key.toLowerCase() === 'meta') {
_downKeys.splice(0, _downKeys.length);
}
// 修饰键 shiftKey altKey ctrlKey (command||metaKey) 清除
if (key === 93 || key === 224) key = 91;
if (key in _mods) {
_mods[key] = false;
// 将修饰键重置为false
for (const k in _modifier) if (_modifier[k] === key) hotkeys[k] = false;
}
}
function unbind(keysInfo) {
// unbind(), unbind all keys
if (typeof keysInfo === 'undefined') {
Object.keys(_handlers).forEach(key => {
Array.isArray(_handlers[key]) && _handlers[key].forEach(info => eachUnbind(info));
delete _handlers[key];
});
removeKeyEvent(null);
} else if (Array.isArray(keysInfo)) {
// support like : unbind([{key: 'ctrl+a', scope: 's1'}, {key: 'ctrl-a', scope: 's2', splitKey: '-'}])
keysInfo.forEach(info => {
if (info.key) eachUnbind(info);
});
} else if (typeof keysInfo === 'object') {
// support like unbind({key: 'ctrl+a, ctrl+b', scope:'abc'})
if (keysInfo.key) eachUnbind(keysInfo);
} else if (typeof keysInfo === 'string') {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
// support old method
// eslint-disable-line
let [scope, method] = args;
if (typeof scope === 'function') {
method = scope;
scope = '';
}
eachUnbind({
key: keysInfo,
scope,
method,
splitKey: '+'
});
}
}
// 解除绑定某个范围的快捷键
const eachUnbind = _ref3 => {
let {
key,
scope,
method,
splitKey = '+'
} = _ref3;
const multipleKeys = getKeys(key);
multipleKeys.forEach(originKey => {
const unbindKeys = originKey.split(splitKey);
const len = unbindKeys.length;
const lastKey = unbindKeys[len - 1];
const keyCode = lastKey === '*' ? '*' : code(lastKey);
if (!_handlers[keyCode]) return;
// 判断是否传入范围,没有就获取范围
if (!scope) scope = getScope();
const mods = len > 1 ? getMods(_modifier, unbindKeys) : [];
const unbindElements = [];
_handlers[keyCode] = _handlers[keyCode].filter(record => {
// 通过函数判断,是否解除绑定,函数相等直接返回
const isMatchingMethod = method ? record.method === method : true;
const isUnbind = isMatchingMethod && record.scope === scope && compareArray(record.mods, mods);
if (isUnbind) unbindElements.push(record.element);
return !isUnbind;
});
unbindElements.forEach(element => removeKeyEvent(element));
});
};
// 对监听对应快捷键的回调函数进行处理
function eventHandler(event, handler, scope, element) {
if (handler.element !== element) {
return;
}
let modifiersMatch;
// 看它是否在当前范围
if (handler.scope === scope || handler.scope === 'all') {
// 检查是否匹配修饰符如果有返回true
modifiersMatch = handler.mods.length > 0;
for (const y in _mods) {
if (Object.prototype.hasOwnProperty.call(_mods, y)) {
if (!_mods[y] && handler.mods.indexOf(+y) > -1 || _mods[y] && handler.mods.indexOf(+y) === -1) {
modifiersMatch = false;
}
}
}
// 调用处理程序,如果是修饰键不做处理
if (handler.mods.length === 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91] || modifiersMatch || handler.shortcut === '*') {
handler.keys = [];
handler.keys = handler.keys.concat(_downKeys);
if (handler.method(event, handler) === false) {
if (event.preventDefault) event.preventDefault();else event.returnValue = false;
if (event.stopPropagation) event.stopPropagation();
if (event.cancelBubble) event.cancelBubble = true;
}
}
}
}
// 处理keydown事件
function dispatch(event, element) {
const asterisk = _handlers['*'];
let key = event.keyCode || event.which || event.charCode;
// 表单控件过滤 默认表单控件不触发快捷键
if (!hotkeys.filter.call(this, event)) return;
// Gecko(Firefox)的command键值224在Webkit(Chrome)中保持一致
// Webkit左右 command 键值不一样
if (key === 93 || key === 224) key = 91;
/**
* Collect bound keys
* If an Input Method Editor is processing key input and the event is keydown, return 229.
* https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229
* http://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html
*/
if (_downKeys.indexOf(key) === -1 && key !== 229) _downKeys.push(key);
/**
* Jest test cases are required.
* ===============================
*/
['ctrlKey', 'altKey', 'shiftKey', 'metaKey'].forEach(keyName => {
const keyNum = modifierMap[keyName];
if (event[keyName] && _downKeys.indexOf(keyNum) === -1) {
_downKeys.push(keyNum);
} else if (!event[keyName] && _downKeys.indexOf(keyNum) > -1) {
_downKeys.splice(_downKeys.indexOf(keyNum), 1);
} else if (keyName === 'metaKey' && event[keyName] && _downKeys.length === 3) {
/**
* Fix if Command is pressed:
* ===============================
*/
if (!(event.ctrlKey || event.shiftKey || event.altKey)) {
_downKeys = _downKeys.slice(_downKeys.indexOf(keyNum));
}
}
});
/**
* -------------------------------
*/
if (key in _mods) {
_mods[key] = true;
// 将特殊字符的key注册到 hotkeys 上
for (const k in _modifier) {
if (_modifier[k] === key) hotkeys[k] = true;
}
if (!asterisk) return;
}
// 将 modifierMap 里面的修饰键绑定到 event 中
for (const e in _mods) {
if (Object.prototype.hasOwnProperty.call(_mods, e)) {
_mods[e] = event[modifierMap[e]];
}
}
/**
* https://github.com/jaywcjlove/hotkeys/pull/129
* This solves the issue in Firefox on Windows where hotkeys corresponding to special characters would not trigger.
* An example of this is ctrl+alt+m on a Swedish keyboard which is used to type μ.
* Browser support: https://caniuse.com/#feat=keyboardevent-getmodifierstate
*/
if (event.getModifierState && !(event.altKey && !event.ctrlKey) && event.getModifierState('AltGraph')) {
if (_downKeys.indexOf(17) === -1) {
_downKeys.push(17);
}
if (_downKeys.indexOf(18) === -1) {
_downKeys.push(18);
}
_mods[17] = true;
_mods[18] = true;
}
// 获取范围 默认为 `all`
const scope = getScope();
// 对任何快捷键都需要做的处理
if (asterisk) {
for (let i = 0; i < asterisk.length; i++) {
if (asterisk[i].scope === scope && (event.type === 'keydown' && asterisk[i].keydown || event.type === 'keyup' && asterisk[i].keyup)) {
eventHandler(event, asterisk[i], scope, element);
}
}
}
// key 不在 _handlers 中返回
if (!(key in _handlers)) return;
const handlerKey = _handlers[key];
const keyLen = handlerKey.length;
for (let i = 0; i < keyLen; i++) {
if (event.type === 'keydown' && handlerKey[i].keydown || event.type === 'keyup' && handlerKey[i].keyup) {
if (handlerKey[i].key) {
const record = handlerKey[i];
const {
splitKey
} = record;
const keyShortcut = record.key.split(splitKey);
const _downKeysCurrent = []; // 记录当前按键键值
for (let a = 0; a < keyShortcut.length; a++) {
_downKeysCurrent.push(code(keyShortcut[a]));
}
if (_downKeysCurrent.sort().join('') === _downKeys.sort().join('')) {
// 找到处理内容
eventHandler(event, record, scope, element);
}
}
}
}
}
function hotkeys(key, option, method) {
_downKeys = [];
const keys = getKeys(key); // 需要处理的快捷键列表
let mods = [];
let scope = 'all'; // scope默认为all所有范围都有效
let element = document; // 快捷键事件绑定节点
let i = 0;
let keyup = false;
let keydown = true;
let splitKey = '+';
let capture = false;
let single = false; // 单个callback
// 对为设定范围的判断
if (method === undefined && typeof option === 'function') {
method = option;
}
if (Object.prototype.toString.call(option) === '[object Object]') {
if (option.scope) scope = option.scope; // eslint-disable-line
if (option.element) element = option.element; // eslint-disable-line
if (option.keyup) keyup = option.keyup; // eslint-disable-line
if (option.keydown !== undefined) keydown = option.keydown; // eslint-disable-line
if (option.capture !== undefined) capture = option.capture; // eslint-disable-line
if (typeof option.splitKey === 'string') splitKey = option.splitKey; // eslint-disable-line
if (option.single === true) single = true; // eslint-disable-line
}
if (typeof option === 'string') scope = option;
// 如果只允许单个callback先unbind
if (single) unbind(key, scope);
// 对于每个快捷键进行处理
for (; i < keys.length; i++) {
key = keys[i].split(splitKey); // 按键列表
mods = [];
// 如果是组合快捷键取得组合快捷键
if (key.length > 1) mods = getMods(_modifier, key);
// 将非修饰键转化为键码
key = key[key.length - 1];
key = key === '*' ? '*' : code(key); // *表示匹配所有快捷键
// 判断key是否在_handlers中不在就赋一个空数组
if (!(key in _handlers)) _handlers[key] = [];
_handlers[key].push({
keyup,
keydown,
scope,
mods,
shortcut: keys[i],
method,
key: keys[i],
splitKey,
element
});
}
// 在全局document上设置快捷键
if (typeof element !== 'undefined' && window) {
if (!elementEventMap.has(element)) {
const keydownListener = function () {
let event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event;
return dispatch(event, element);
};
const keyupListenr = function () {
let event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event;
dispatch(event, element);
clearModifier(event);
};
elementEventMap.set(element, {
keydownListener,
keyupListenr,
capture
});
addEvent(element, 'keydown', keydownListener, capture);
addEvent(element, 'keyup', keyupListenr, capture);
}
if (!winListendFocus) {
const listener = () => {
_downKeys = [];
};
winListendFocus = {
listener,
capture
};
addEvent(window, 'focus', listener, capture);
}
}
}
function trigger(shortcut) {
let scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'all';
Object.keys(_handlers).forEach(key => {
const dataList = _handlers[key].filter(item => item.scope === scope && item.shortcut === shortcut);
dataList.forEach(data => {
if (data && data.method) {
data.method();
}
});
});
}
// 销毁事件,unbind之后判断element上是否还有键盘快捷键如果没有移除监听
function removeKeyEvent(element) {
const values = Object.values(_handlers).flat();
const findindex = values.findIndex(_ref4 => {
let {
element: el
} = _ref4;
return el === element;
});
if (findindex < 0) {
const {
keydownListener,
keyupListenr,
capture
} = elementEventMap.get(element) || {};
if (keydownListener && keyupListenr) {
removeEvent(element, 'keyup', keyupListenr, capture);
removeEvent(element, 'keydown', keydownListener, capture);
elementEventMap.delete(element);
}
}
if (values.length <= 0 || elementEventMap.size <= 0) {
// 移除所有的元素上的监听
const eventKeys = Object.keys(elementEventMap);
eventKeys.forEach(el => {
const {
keydownListener,
keyupListenr,
capture
} = elementEventMap.get(el) || {};
if (keydownListener && keyupListenr) {
removeEvent(el, 'keyup', keyupListenr, capture);
removeEvent(el, 'keydown', keydownListener, capture);
elementEventMap.delete(el);
}
});
// 清空 elementEventMap
elementEventMap.clear();
// 清空 _handlers
Object.keys(_handlers).forEach(key => delete _handlers[key]);
// 移除window上的focus监听
if (winListendFocus) {
const {
listener,
capture
} = winListendFocus;
removeEvent(window, 'focus', listener, capture);
winListendFocus = null;
}
}
}
const _api = {
getPressedKeyString,
setScope,
getScope,
deleteScope,
getPressedKeyCodes,
getAllKeyCodes,
isPressed,
filter,
trigger,
unbind,
keyMap: _keyMap,
modifier: _modifier,
modifierMap
};
for (const a in _api) {
if (Object.prototype.hasOwnProperty.call(_api, a)) {
hotkeys[a] = _api[a];
}
}
if (typeof window !== 'undefined') {
const _hotkeys = window.hotkeys;
hotkeys.noConflict = deep => {
if (deep && window.hotkeys === hotkeys) {
window.hotkeys = _hotkeys;
}
return hotkeys;
};
window.hotkeys = hotkeys;
}
module.exports = hotkeys;

File diff suppressed because one or more lines are too long

View File

@ -1,675 +0,0 @@
/**!
* hotkeys-js v3.13.7
* A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies.
*
* Copyright (c) 2024 kenny wong <wowohoo@qq.com>
* https://github.com/jaywcjlove/hotkeys-js.git
*
* @website: https://jaywcjlove.github.io/hotkeys-js
* Licensed under the MIT license
*/
const isff = typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase().indexOf('firefox') > 0 : false;
// 绑定事件
function addEvent(object, event, method, useCapture) {
if (object.addEventListener) {
object.addEventListener(event, method, useCapture);
} else if (object.attachEvent) {
object.attachEvent("on".concat(event), method);
}
}
function removeEvent(object, event, method, useCapture) {
if (object.removeEventListener) {
object.removeEventListener(event, method, useCapture);
} else if (object.detachEvent) {
object.detachEvent("on".concat(event), method);
}
}
// 修饰键转换成对应的键码
function getMods(modifier, key) {
const mods = key.slice(0, key.length - 1);
for (let i = 0; i < mods.length; i++) mods[i] = modifier[mods[i].toLowerCase()];
return mods;
}
// 处理传的key字符串转换成数组
function getKeys(key) {
if (typeof key !== 'string') key = '';
key = key.replace(/\s/g, ''); // 匹配任何空白字符,包括空格、制表符、换页符等等
const keys = key.split(','); // 同时设置多个快捷键,以','分割
let index = keys.lastIndexOf('');
// 快捷键可能包含',',需特殊处理
for (; index >= 0;) {
keys[index - 1] += ',';
keys.splice(index, 1);
index = keys.lastIndexOf('');
}
return keys;
}
// 比较修饰键的数组
function compareArray(a1, a2) {
const arr1 = a1.length >= a2.length ? a1 : a2;
const arr2 = a1.length >= a2.length ? a2 : a1;
let isIndex = true;
for (let i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) === -1) isIndex = false;
}
return isIndex;
}
// Special Keys
const _keyMap = {
backspace: 8,
'⌫': 8,
tab: 9,
clear: 12,
enter: 13,
'↩': 13,
return: 13,
esc: 27,
escape: 27,
space: 32,
left: 37,
up: 38,
right: 39,
down: 40,
del: 46,
delete: 46,
ins: 45,
insert: 45,
home: 36,
end: 35,
pageup: 33,
pagedown: 34,
capslock: 20,
num_0: 96,
num_1: 97,
num_2: 98,
num_3: 99,
num_4: 100,
num_5: 101,
num_6: 102,
num_7: 103,
num_8: 104,
num_9: 105,
num_multiply: 106,
num_add: 107,
num_enter: 108,
num_subtract: 109,
num_decimal: 110,
num_divide: 111,
'⇪': 20,
',': 188,
'.': 190,
'/': 191,
'`': 192,
'-': isff ? 173 : 189,
'=': isff ? 61 : 187,
';': isff ? 59 : 186,
'\'': 222,
'[': 219,
']': 221,
'\\': 220
};
// Modifier Keys
const _modifier = {
// shiftKey
'⇧': 16,
shift: 16,
// altKey
'⌥': 18,
alt: 18,
option: 18,
// ctrlKey
'⌃': 17,
ctrl: 17,
control: 17,
// metaKey
'⌘': 91,
cmd: 91,
command: 91
};
const modifierMap = {
16: 'shiftKey',
18: 'altKey',
17: 'ctrlKey',
91: 'metaKey',
shiftKey: 16,
ctrlKey: 17,
altKey: 18,
metaKey: 91
};
const _mods = {
16: false,
18: false,
17: false,
91: false
};
const _handlers = {};
// F1~F12 special key
for (let k = 1; k < 20; k++) {
_keyMap["f".concat(k)] = 111 + k;
}
let _downKeys = []; // 记录摁下的绑定键
let winListendFocus = null; // window是否已经监听了focus事件
let _scope = 'all'; // 默认热键范围
const elementEventMap = new Map(); // 已绑定事件的节点记录
// 返回键码
const code = x => _keyMap[x.toLowerCase()] || _modifier[x.toLowerCase()] || x.toUpperCase().charCodeAt(0);
const getKey = x => Object.keys(_keyMap).find(k => _keyMap[k] === x);
const getModifier = x => Object.keys(_modifier).find(k => _modifier[k] === x);
// 设置获取当前范围(默认为'所有'
function setScope(scope) {
_scope = scope || 'all';
}
// 获取当前范围
function getScope() {
return _scope || 'all';
}
// 获取摁下绑定键的键值
function getPressedKeyCodes() {
return _downKeys.slice(0);
}
function getPressedKeyString() {
return _downKeys.map(c => getKey(c) || getModifier(c) || String.fromCharCode(c));
}
function getAllKeyCodes() {
const result = [];
Object.keys(_handlers).forEach(k => {
_handlers[k].forEach(_ref => {
let {
key,
scope,
mods,
shortcut
} = _ref;
result.push({
scope,
shortcut,
mods,
keys: key.split('+').map(v => code(v))
});
});
});
return result;
}
// 表单控件控件判断 返回 Boolean
// hotkey is effective only when filter return true
function filter(event) {
const target = event.target || event.srcElement;
const {
tagName
} = target;
let flag = true;
const isInput = tagName === 'INPUT' && !['checkbox', 'radio', 'range', 'button', 'file', 'reset', 'submit', 'color'].includes(target.type);
// ignore: isContentEditable === 'true', <input> and <textarea> when readOnly state is false, <select>
if (target.isContentEditable || (isInput || tagName === 'TEXTAREA' || tagName === 'SELECT') && !target.readOnly) {
flag = false;
}
return flag;
}
// 判断摁下的键是否为某个键返回true或者false
function isPressed(keyCode) {
if (typeof keyCode === 'string') {
keyCode = code(keyCode); // 转换成键码
}
return _downKeys.indexOf(keyCode) !== -1;
}
// 循环删除handlers中的所有 scope(范围)
function deleteScope(scope, newScope) {
let handlers;
let i;
// 没有指定scope获取scope
if (!scope) scope = getScope();
for (const key in _handlers) {
if (Object.prototype.hasOwnProperty.call(_handlers, key)) {
handlers = _handlers[key];
for (i = 0; i < handlers.length;) {
if (handlers[i].scope === scope) {
const deleteItems = handlers.splice(i, 1);
deleteItems.forEach(_ref2 => {
let {
element
} = _ref2;
return removeKeyEvent(element);
});
} else {
i++;
}
}
}
}
// 如果scope被删除将scope重置为all
if (getScope() === scope) setScope(newScope || 'all');
}
// 清除修饰键
function clearModifier(event) {
let key = event.keyCode || event.which || event.charCode;
const i = _downKeys.indexOf(key);
// 从列表中清除按压过的键
if (i >= 0) {
_downKeys.splice(i, 1);
}
// 特殊处理 cmmand 键,在 cmmand 组合快捷键 keyup 只执行一次的问题
if (event.key && event.key.toLowerCase() === 'meta') {
_downKeys.splice(0, _downKeys.length);
}
// 修饰键 shiftKey altKey ctrlKey (command||metaKey) 清除
if (key === 93 || key === 224) key = 91;
if (key in _mods) {
_mods[key] = false;
// 将修饰键重置为false
for (const k in _modifier) if (_modifier[k] === key) hotkeys[k] = false;
}
}
function unbind(keysInfo) {
// unbind(), unbind all keys
if (typeof keysInfo === 'undefined') {
Object.keys(_handlers).forEach(key => {
Array.isArray(_handlers[key]) && _handlers[key].forEach(info => eachUnbind(info));
delete _handlers[key];
});
removeKeyEvent(null);
} else if (Array.isArray(keysInfo)) {
// support like : unbind([{key: 'ctrl+a', scope: 's1'}, {key: 'ctrl-a', scope: 's2', splitKey: '-'}])
keysInfo.forEach(info => {
if (info.key) eachUnbind(info);
});
} else if (typeof keysInfo === 'object') {
// support like unbind({key: 'ctrl+a, ctrl+b', scope:'abc'})
if (keysInfo.key) eachUnbind(keysInfo);
} else if (typeof keysInfo === 'string') {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
// support old method
// eslint-disable-line
let [scope, method] = args;
if (typeof scope === 'function') {
method = scope;
scope = '';
}
eachUnbind({
key: keysInfo,
scope,
method,
splitKey: '+'
});
}
}
// 解除绑定某个范围的快捷键
const eachUnbind = _ref3 => {
let {
key,
scope,
method,
splitKey = '+'
} = _ref3;
const multipleKeys = getKeys(key);
multipleKeys.forEach(originKey => {
const unbindKeys = originKey.split(splitKey);
const len = unbindKeys.length;
const lastKey = unbindKeys[len - 1];
const keyCode = lastKey === '*' ? '*' : code(lastKey);
if (!_handlers[keyCode]) return;
// 判断是否传入范围,没有就获取范围
if (!scope) scope = getScope();
const mods = len > 1 ? getMods(_modifier, unbindKeys) : [];
const unbindElements = [];
_handlers[keyCode] = _handlers[keyCode].filter(record => {
// 通过函数判断,是否解除绑定,函数相等直接返回
const isMatchingMethod = method ? record.method === method : true;
const isUnbind = isMatchingMethod && record.scope === scope && compareArray(record.mods, mods);
if (isUnbind) unbindElements.push(record.element);
return !isUnbind;
});
unbindElements.forEach(element => removeKeyEvent(element));
});
};
// 对监听对应快捷键的回调函数进行处理
function eventHandler(event, handler, scope, element) {
if (handler.element !== element) {
return;
}
let modifiersMatch;
// 看它是否在当前范围
if (handler.scope === scope || handler.scope === 'all') {
// 检查是否匹配修饰符如果有返回true
modifiersMatch = handler.mods.length > 0;
for (const y in _mods) {
if (Object.prototype.hasOwnProperty.call(_mods, y)) {
if (!_mods[y] && handler.mods.indexOf(+y) > -1 || _mods[y] && handler.mods.indexOf(+y) === -1) {
modifiersMatch = false;
}
}
}
// 调用处理程序,如果是修饰键不做处理
if (handler.mods.length === 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91] || modifiersMatch || handler.shortcut === '*') {
handler.keys = [];
handler.keys = handler.keys.concat(_downKeys);
if (handler.method(event, handler) === false) {
if (event.preventDefault) event.preventDefault();else event.returnValue = false;
if (event.stopPropagation) event.stopPropagation();
if (event.cancelBubble) event.cancelBubble = true;
}
}
}
}
// 处理keydown事件
function dispatch(event, element) {
const asterisk = _handlers['*'];
let key = event.keyCode || event.which || event.charCode;
// 表单控件过滤 默认表单控件不触发快捷键
if (!hotkeys.filter.call(this, event)) return;
// Gecko(Firefox)的command键值224在Webkit(Chrome)中保持一致
// Webkit左右 command 键值不一样
if (key === 93 || key === 224) key = 91;
/**
* Collect bound keys
* If an Input Method Editor is processing key input and the event is keydown, return 229.
* https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229
* http://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html
*/
if (_downKeys.indexOf(key) === -1 && key !== 229) _downKeys.push(key);
/**
* Jest test cases are required.
* ===============================
*/
['ctrlKey', 'altKey', 'shiftKey', 'metaKey'].forEach(keyName => {
const keyNum = modifierMap[keyName];
if (event[keyName] && _downKeys.indexOf(keyNum) === -1) {
_downKeys.push(keyNum);
} else if (!event[keyName] && _downKeys.indexOf(keyNum) > -1) {
_downKeys.splice(_downKeys.indexOf(keyNum), 1);
} else if (keyName === 'metaKey' && event[keyName] && _downKeys.length === 3) {
/**
* Fix if Command is pressed:
* ===============================
*/
if (!(event.ctrlKey || event.shiftKey || event.altKey)) {
_downKeys = _downKeys.slice(_downKeys.indexOf(keyNum));
}
}
});
/**
* -------------------------------
*/
if (key in _mods) {
_mods[key] = true;
// 将特殊字符的key注册到 hotkeys 上
for (const k in _modifier) {
if (_modifier[k] === key) hotkeys[k] = true;
}
if (!asterisk) return;
}
// 将 modifierMap 里面的修饰键绑定到 event 中
for (const e in _mods) {
if (Object.prototype.hasOwnProperty.call(_mods, e)) {
_mods[e] = event[modifierMap[e]];
}
}
/**
* https://github.com/jaywcjlove/hotkeys/pull/129
* This solves the issue in Firefox on Windows where hotkeys corresponding to special characters would not trigger.
* An example of this is ctrl+alt+m on a Swedish keyboard which is used to type μ.
* Browser support: https://caniuse.com/#feat=keyboardevent-getmodifierstate
*/
if (event.getModifierState && !(event.altKey && !event.ctrlKey) && event.getModifierState('AltGraph')) {
if (_downKeys.indexOf(17) === -1) {
_downKeys.push(17);
}
if (_downKeys.indexOf(18) === -1) {
_downKeys.push(18);
}
_mods[17] = true;
_mods[18] = true;
}
// 获取范围 默认为 `all`
const scope = getScope();
// 对任何快捷键都需要做的处理
if (asterisk) {
for (let i = 0; i < asterisk.length; i++) {
if (asterisk[i].scope === scope && (event.type === 'keydown' && asterisk[i].keydown || event.type === 'keyup' && asterisk[i].keyup)) {
eventHandler(event, asterisk[i], scope, element);
}
}
}
// key 不在 _handlers 中返回
if (!(key in _handlers)) return;
const handlerKey = _handlers[key];
const keyLen = handlerKey.length;
for (let i = 0; i < keyLen; i++) {
if (event.type === 'keydown' && handlerKey[i].keydown || event.type === 'keyup' && handlerKey[i].keyup) {
if (handlerKey[i].key) {
const record = handlerKey[i];
const {
splitKey
} = record;
const keyShortcut = record.key.split(splitKey);
const _downKeysCurrent = []; // 记录当前按键键值
for (let a = 0; a < keyShortcut.length; a++) {
_downKeysCurrent.push(code(keyShortcut[a]));
}
if (_downKeysCurrent.sort().join('') === _downKeys.sort().join('')) {
// 找到处理内容
eventHandler(event, record, scope, element);
}
}
}
}
}
function hotkeys(key, option, method) {
_downKeys = [];
const keys = getKeys(key); // 需要处理的快捷键列表
let mods = [];
let scope = 'all'; // scope默认为all所有范围都有效
let element = document; // 快捷键事件绑定节点
let i = 0;
let keyup = false;
let keydown = true;
let splitKey = '+';
let capture = false;
let single = false; // 单个callback
// 对为设定范围的判断
if (method === undefined && typeof option === 'function') {
method = option;
}
if (Object.prototype.toString.call(option) === '[object Object]') {
if (option.scope) scope = option.scope; // eslint-disable-line
if (option.element) element = option.element; // eslint-disable-line
if (option.keyup) keyup = option.keyup; // eslint-disable-line
if (option.keydown !== undefined) keydown = option.keydown; // eslint-disable-line
if (option.capture !== undefined) capture = option.capture; // eslint-disable-line
if (typeof option.splitKey === 'string') splitKey = option.splitKey; // eslint-disable-line
if (option.single === true) single = true; // eslint-disable-line
}
if (typeof option === 'string') scope = option;
// 如果只允许单个callback先unbind
if (single) unbind(key, scope);
// 对于每个快捷键进行处理
for (; i < keys.length; i++) {
key = keys[i].split(splitKey); // 按键列表
mods = [];
// 如果是组合快捷键取得组合快捷键
if (key.length > 1) mods = getMods(_modifier, key);
// 将非修饰键转化为键码
key = key[key.length - 1];
key = key === '*' ? '*' : code(key); // *表示匹配所有快捷键
// 判断key是否在_handlers中不在就赋一个空数组
if (!(key in _handlers)) _handlers[key] = [];
_handlers[key].push({
keyup,
keydown,
scope,
mods,
shortcut: keys[i],
method,
key: keys[i],
splitKey,
element
});
}
// 在全局document上设置快捷键
if (typeof element !== 'undefined' && window) {
if (!elementEventMap.has(element)) {
const keydownListener = function () {
let event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event;
return dispatch(event, element);
};
const keyupListenr = function () {
let event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event;
dispatch(event, element);
clearModifier(event);
};
elementEventMap.set(element, {
keydownListener,
keyupListenr,
capture
});
addEvent(element, 'keydown', keydownListener, capture);
addEvent(element, 'keyup', keyupListenr, capture);
}
if (!winListendFocus) {
const listener = () => {
_downKeys = [];
};
winListendFocus = {
listener,
capture
};
addEvent(window, 'focus', listener, capture);
}
}
}
function trigger(shortcut) {
let scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'all';
Object.keys(_handlers).forEach(key => {
const dataList = _handlers[key].filter(item => item.scope === scope && item.shortcut === shortcut);
dataList.forEach(data => {
if (data && data.method) {
data.method();
}
});
});
}
// 销毁事件,unbind之后判断element上是否还有键盘快捷键如果没有移除监听
function removeKeyEvent(element) {
const values = Object.values(_handlers).flat();
const findindex = values.findIndex(_ref4 => {
let {
element: el
} = _ref4;
return el === element;
});
if (findindex < 0) {
const {
keydownListener,
keyupListenr,
capture
} = elementEventMap.get(element) || {};
if (keydownListener && keyupListenr) {
removeEvent(element, 'keyup', keyupListenr, capture);
removeEvent(element, 'keydown', keydownListener, capture);
elementEventMap.delete(element);
}
}
if (values.length <= 0 || elementEventMap.size <= 0) {
// 移除所有的元素上的监听
const eventKeys = Object.keys(elementEventMap);
eventKeys.forEach(el => {
const {
keydownListener,
keyupListenr,
capture
} = elementEventMap.get(el) || {};
if (keydownListener && keyupListenr) {
removeEvent(el, 'keyup', keyupListenr, capture);
removeEvent(el, 'keydown', keydownListener, capture);
elementEventMap.delete(el);
}
});
// 清空 elementEventMap
elementEventMap.clear();
// 清空 _handlers
Object.keys(_handlers).forEach(key => delete _handlers[key]);
// 移除window上的focus监听
if (winListendFocus) {
const {
listener,
capture
} = winListendFocus;
removeEvent(window, 'focus', listener, capture);
winListendFocus = null;
}
}
}
const _api = {
getPressedKeyString,
setScope,
getScope,
deleteScope,
getPressedKeyCodes,
getAllKeyCodes,
isPressed,
filter,
trigger,
unbind,
keyMap: _keyMap,
modifier: _modifier,
modifierMap
};
for (const a in _api) {
if (Object.prototype.hasOwnProperty.call(_api, a)) {
hotkeys[a] = _api[a];
}
}
if (typeof window !== 'undefined') {
const _hotkeys = window.hotkeys;
hotkeys.noConflict = deep => {
if (deep && window.hotkeys === hotkeys) {
window.hotkeys = _hotkeys;
}
return hotkeys;
};
window.hotkeys = hotkeys;
}
export { hotkeys as default };

View File

@ -1,683 +0,0 @@
/**!
* hotkeys-js v3.13.7
* A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies.
*
* Copyright (c) 2024 kenny wong <wowohoo@qq.com>
* https://github.com/jaywcjlove/hotkeys-js.git
*
* @website: https://jaywcjlove.github.io/hotkeys-js
* Licensed under the MIT license
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.hotkeys = factory());
})(this, (function () { 'use strict';
const isff = typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase().indexOf('firefox') > 0 : false;
// 绑定事件
function addEvent(object, event, method, useCapture) {
if (object.addEventListener) {
object.addEventListener(event, method, useCapture);
} else if (object.attachEvent) {
object.attachEvent("on".concat(event), method);
}
}
function removeEvent(object, event, method, useCapture) {
if (object.removeEventListener) {
object.removeEventListener(event, method, useCapture);
} else if (object.detachEvent) {
object.detachEvent("on".concat(event), method);
}
}
// 修饰键转换成对应的键码
function getMods(modifier, key) {
const mods = key.slice(0, key.length - 1);
for (let i = 0; i < mods.length; i++) mods[i] = modifier[mods[i].toLowerCase()];
return mods;
}
// 处理传的key字符串转换成数组
function getKeys(key) {
if (typeof key !== 'string') key = '';
key = key.replace(/\s/g, ''); // 匹配任何空白字符,包括空格、制表符、换页符等等
const keys = key.split(','); // 同时设置多个快捷键,以','分割
let index = keys.lastIndexOf('');
// 快捷键可能包含',',需特殊处理
for (; index >= 0;) {
keys[index - 1] += ',';
keys.splice(index, 1);
index = keys.lastIndexOf('');
}
return keys;
}
// 比较修饰键的数组
function compareArray(a1, a2) {
const arr1 = a1.length >= a2.length ? a1 : a2;
const arr2 = a1.length >= a2.length ? a2 : a1;
let isIndex = true;
for (let i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) === -1) isIndex = false;
}
return isIndex;
}
// Special Keys
const _keyMap = {
backspace: 8,
'⌫': 8,
tab: 9,
clear: 12,
enter: 13,
'↩': 13,
return: 13,
esc: 27,
escape: 27,
space: 32,
left: 37,
up: 38,
right: 39,
down: 40,
del: 46,
delete: 46,
ins: 45,
insert: 45,
home: 36,
end: 35,
pageup: 33,
pagedown: 34,
capslock: 20,
num_0: 96,
num_1: 97,
num_2: 98,
num_3: 99,
num_4: 100,
num_5: 101,
num_6: 102,
num_7: 103,
num_8: 104,
num_9: 105,
num_multiply: 106,
num_add: 107,
num_enter: 108,
num_subtract: 109,
num_decimal: 110,
num_divide: 111,
'⇪': 20,
',': 188,
'.': 190,
'/': 191,
'`': 192,
'-': isff ? 173 : 189,
'=': isff ? 61 : 187,
';': isff ? 59 : 186,
'\'': 222,
'[': 219,
']': 221,
'\\': 220
};
// Modifier Keys
const _modifier = {
// shiftKey
'⇧': 16,
shift: 16,
// altKey
'⌥': 18,
alt: 18,
option: 18,
// ctrlKey
'⌃': 17,
ctrl: 17,
control: 17,
// metaKey
'⌘': 91,
cmd: 91,
command: 91
};
const modifierMap = {
16: 'shiftKey',
18: 'altKey',
17: 'ctrlKey',
91: 'metaKey',
shiftKey: 16,
ctrlKey: 17,
altKey: 18,
metaKey: 91
};
const _mods = {
16: false,
18: false,
17: false,
91: false
};
const _handlers = {};
// F1~F12 special key
for (let k = 1; k < 20; k++) {
_keyMap["f".concat(k)] = 111 + k;
}
let _downKeys = []; // 记录摁下的绑定键
let winListendFocus = null; // window是否已经监听了focus事件
let _scope = 'all'; // 默认热键范围
const elementEventMap = new Map(); // 已绑定事件的节点记录
// 返回键码
const code = x => _keyMap[x.toLowerCase()] || _modifier[x.toLowerCase()] || x.toUpperCase().charCodeAt(0);
const getKey = x => Object.keys(_keyMap).find(k => _keyMap[k] === x);
const getModifier = x => Object.keys(_modifier).find(k => _modifier[k] === x);
// 设置获取当前范围(默认为'所有'
function setScope(scope) {
_scope = scope || 'all';
}
// 获取当前范围
function getScope() {
return _scope || 'all';
}
// 获取摁下绑定键的键值
function getPressedKeyCodes() {
return _downKeys.slice(0);
}
function getPressedKeyString() {
return _downKeys.map(c => getKey(c) || getModifier(c) || String.fromCharCode(c));
}
function getAllKeyCodes() {
const result = [];
Object.keys(_handlers).forEach(k => {
_handlers[k].forEach(_ref => {
let {
key,
scope,
mods,
shortcut
} = _ref;
result.push({
scope,
shortcut,
mods,
keys: key.split('+').map(v => code(v))
});
});
});
return result;
}
// 表单控件控件判断 返回 Boolean
// hotkey is effective only when filter return true
function filter(event) {
const target = event.target || event.srcElement;
const {
tagName
} = target;
let flag = true;
const isInput = tagName === 'INPUT' && !['checkbox', 'radio', 'range', 'button', 'file', 'reset', 'submit', 'color'].includes(target.type);
// ignore: isContentEditable === 'true', <input> and <textarea> when readOnly state is false, <select>
if (target.isContentEditable || (isInput || tagName === 'TEXTAREA' || tagName === 'SELECT') && !target.readOnly) {
flag = false;
}
return flag;
}
// 判断摁下的键是否为某个键返回true或者false
function isPressed(keyCode) {
if (typeof keyCode === 'string') {
keyCode = code(keyCode); // 转换成键码
}
return _downKeys.indexOf(keyCode) !== -1;
}
// 循环删除handlers中的所有 scope(范围)
function deleteScope(scope, newScope) {
let handlers;
let i;
// 没有指定scope获取scope
if (!scope) scope = getScope();
for (const key in _handlers) {
if (Object.prototype.hasOwnProperty.call(_handlers, key)) {
handlers = _handlers[key];
for (i = 0; i < handlers.length;) {
if (handlers[i].scope === scope) {
const deleteItems = handlers.splice(i, 1);
deleteItems.forEach(_ref2 => {
let {
element
} = _ref2;
return removeKeyEvent(element);
});
} else {
i++;
}
}
}
}
// 如果scope被删除将scope重置为all
if (getScope() === scope) setScope(newScope || 'all');
}
// 清除修饰键
function clearModifier(event) {
let key = event.keyCode || event.which || event.charCode;
const i = _downKeys.indexOf(key);
// 从列表中清除按压过的键
if (i >= 0) {
_downKeys.splice(i, 1);
}
// 特殊处理 cmmand 键,在 cmmand 组合快捷键 keyup 只执行一次的问题
if (event.key && event.key.toLowerCase() === 'meta') {
_downKeys.splice(0, _downKeys.length);
}
// 修饰键 shiftKey altKey ctrlKey (command||metaKey) 清除
if (key === 93 || key === 224) key = 91;
if (key in _mods) {
_mods[key] = false;
// 将修饰键重置为false
for (const k in _modifier) if (_modifier[k] === key) hotkeys[k] = false;
}
}
function unbind(keysInfo) {
// unbind(), unbind all keys
if (typeof keysInfo === 'undefined') {
Object.keys(_handlers).forEach(key => {
Array.isArray(_handlers[key]) && _handlers[key].forEach(info => eachUnbind(info));
delete _handlers[key];
});
removeKeyEvent(null);
} else if (Array.isArray(keysInfo)) {
// support like : unbind([{key: 'ctrl+a', scope: 's1'}, {key: 'ctrl-a', scope: 's2', splitKey: '-'}])
keysInfo.forEach(info => {
if (info.key) eachUnbind(info);
});
} else if (typeof keysInfo === 'object') {
// support like unbind({key: 'ctrl+a, ctrl+b', scope:'abc'})
if (keysInfo.key) eachUnbind(keysInfo);
} else if (typeof keysInfo === 'string') {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
// support old method
// eslint-disable-line
let [scope, method] = args;
if (typeof scope === 'function') {
method = scope;
scope = '';
}
eachUnbind({
key: keysInfo,
scope,
method,
splitKey: '+'
});
}
}
// 解除绑定某个范围的快捷键
const eachUnbind = _ref3 => {
let {
key,
scope,
method,
splitKey = '+'
} = _ref3;
const multipleKeys = getKeys(key);
multipleKeys.forEach(originKey => {
const unbindKeys = originKey.split(splitKey);
const len = unbindKeys.length;
const lastKey = unbindKeys[len - 1];
const keyCode = lastKey === '*' ? '*' : code(lastKey);
if (!_handlers[keyCode]) return;
// 判断是否传入范围,没有就获取范围
if (!scope) scope = getScope();
const mods = len > 1 ? getMods(_modifier, unbindKeys) : [];
const unbindElements = [];
_handlers[keyCode] = _handlers[keyCode].filter(record => {
// 通过函数判断,是否解除绑定,函数相等直接返回
const isMatchingMethod = method ? record.method === method : true;
const isUnbind = isMatchingMethod && record.scope === scope && compareArray(record.mods, mods);
if (isUnbind) unbindElements.push(record.element);
return !isUnbind;
});
unbindElements.forEach(element => removeKeyEvent(element));
});
};
// 对监听对应快捷键的回调函数进行处理
function eventHandler(event, handler, scope, element) {
if (handler.element !== element) {
return;
}
let modifiersMatch;
// 看它是否在当前范围
if (handler.scope === scope || handler.scope === 'all') {
// 检查是否匹配修饰符如果有返回true
modifiersMatch = handler.mods.length > 0;
for (const y in _mods) {
if (Object.prototype.hasOwnProperty.call(_mods, y)) {
if (!_mods[y] && handler.mods.indexOf(+y) > -1 || _mods[y] && handler.mods.indexOf(+y) === -1) {
modifiersMatch = false;
}
}
}
// 调用处理程序,如果是修饰键不做处理
if (handler.mods.length === 0 && !_mods[16] && !_mods[18] && !_mods[17] && !_mods[91] || modifiersMatch || handler.shortcut === '*') {
handler.keys = [];
handler.keys = handler.keys.concat(_downKeys);
if (handler.method(event, handler) === false) {
if (event.preventDefault) event.preventDefault();else event.returnValue = false;
if (event.stopPropagation) event.stopPropagation();
if (event.cancelBubble) event.cancelBubble = true;
}
}
}
}
// 处理keydown事件
function dispatch(event, element) {
const asterisk = _handlers['*'];
let key = event.keyCode || event.which || event.charCode;
// 表单控件过滤 默认表单控件不触发快捷键
if (!hotkeys.filter.call(this, event)) return;
// Gecko(Firefox)的command键值224在Webkit(Chrome)中保持一致
// Webkit左右 command 键值不一样
if (key === 93 || key === 224) key = 91;
/**
* Collect bound keys
* If an Input Method Editor is processing key input and the event is keydown, return 229.
* https://stackoverflow.com/questions/25043934/is-it-ok-to-ignore-keydown-events-with-keycode-229
* http://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html
*/
if (_downKeys.indexOf(key) === -1 && key !== 229) _downKeys.push(key);
/**
* Jest test cases are required.
* ===============================
*/
['ctrlKey', 'altKey', 'shiftKey', 'metaKey'].forEach(keyName => {
const keyNum = modifierMap[keyName];
if (event[keyName] && _downKeys.indexOf(keyNum) === -1) {
_downKeys.push(keyNum);
} else if (!event[keyName] && _downKeys.indexOf(keyNum) > -1) {
_downKeys.splice(_downKeys.indexOf(keyNum), 1);
} else if (keyName === 'metaKey' && event[keyName] && _downKeys.length === 3) {
/**
* Fix if Command is pressed:
* ===============================
*/
if (!(event.ctrlKey || event.shiftKey || event.altKey)) {
_downKeys = _downKeys.slice(_downKeys.indexOf(keyNum));
}
}
});
/**
* -------------------------------
*/
if (key in _mods) {
_mods[key] = true;
// 将特殊字符的key注册到 hotkeys 上
for (const k in _modifier) {
if (_modifier[k] === key) hotkeys[k] = true;
}
if (!asterisk) return;
}
// 将 modifierMap 里面的修饰键绑定到 event 中
for (const e in _mods) {
if (Object.prototype.hasOwnProperty.call(_mods, e)) {
_mods[e] = event[modifierMap[e]];
}
}
/**
* https://github.com/jaywcjlove/hotkeys/pull/129
* This solves the issue in Firefox on Windows where hotkeys corresponding to special characters would not trigger.
* An example of this is ctrl+alt+m on a Swedish keyboard which is used to type μ.
* Browser support: https://caniuse.com/#feat=keyboardevent-getmodifierstate
*/
if (event.getModifierState && !(event.altKey && !event.ctrlKey) && event.getModifierState('AltGraph')) {
if (_downKeys.indexOf(17) === -1) {
_downKeys.push(17);
}
if (_downKeys.indexOf(18) === -1) {
_downKeys.push(18);
}
_mods[17] = true;
_mods[18] = true;
}
// 获取范围 默认为 `all`
const scope = getScope();
// 对任何快捷键都需要做的处理
if (asterisk) {
for (let i = 0; i < asterisk.length; i++) {
if (asterisk[i].scope === scope && (event.type === 'keydown' && asterisk[i].keydown || event.type === 'keyup' && asterisk[i].keyup)) {
eventHandler(event, asterisk[i], scope, element);
}
}
}
// key 不在 _handlers 中返回
if (!(key in _handlers)) return;
const handlerKey = _handlers[key];
const keyLen = handlerKey.length;
for (let i = 0; i < keyLen; i++) {
if (event.type === 'keydown' && handlerKey[i].keydown || event.type === 'keyup' && handlerKey[i].keyup) {
if (handlerKey[i].key) {
const record = handlerKey[i];
const {
splitKey
} = record;
const keyShortcut = record.key.split(splitKey);
const _downKeysCurrent = []; // 记录当前按键键值
for (let a = 0; a < keyShortcut.length; a++) {
_downKeysCurrent.push(code(keyShortcut[a]));
}
if (_downKeysCurrent.sort().join('') === _downKeys.sort().join('')) {
// 找到处理内容
eventHandler(event, record, scope, element);
}
}
}
}
}
function hotkeys(key, option, method) {
_downKeys = [];
const keys = getKeys(key); // 需要处理的快捷键列表
let mods = [];
let scope = 'all'; // scope默认为all所有范围都有效
let element = document; // 快捷键事件绑定节点
let i = 0;
let keyup = false;
let keydown = true;
let splitKey = '+';
let capture = false;
let single = false; // 单个callback
// 对为设定范围的判断
if (method === undefined && typeof option === 'function') {
method = option;
}
if (Object.prototype.toString.call(option) === '[object Object]') {
if (option.scope) scope = option.scope; // eslint-disable-line
if (option.element) element = option.element; // eslint-disable-line
if (option.keyup) keyup = option.keyup; // eslint-disable-line
if (option.keydown !== undefined) keydown = option.keydown; // eslint-disable-line
if (option.capture !== undefined) capture = option.capture; // eslint-disable-line
if (typeof option.splitKey === 'string') splitKey = option.splitKey; // eslint-disable-line
if (option.single === true) single = true; // eslint-disable-line
}
if (typeof option === 'string') scope = option;
// 如果只允许单个callback先unbind
if (single) unbind(key, scope);
// 对于每个快捷键进行处理
for (; i < keys.length; i++) {
key = keys[i].split(splitKey); // 按键列表
mods = [];
// 如果是组合快捷键取得组合快捷键
if (key.length > 1) mods = getMods(_modifier, key);
// 将非修饰键转化为键码
key = key[key.length - 1];
key = key === '*' ? '*' : code(key); // *表示匹配所有快捷键
// 判断key是否在_handlers中不在就赋一个空数组
if (!(key in _handlers)) _handlers[key] = [];
_handlers[key].push({
keyup,
keydown,
scope,
mods,
shortcut: keys[i],
method,
key: keys[i],
splitKey,
element
});
}
// 在全局document上设置快捷键
if (typeof element !== 'undefined' && window) {
if (!elementEventMap.has(element)) {
const keydownListener = function () {
let event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event;
return dispatch(event, element);
};
const keyupListenr = function () {
let event = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : window.event;
dispatch(event, element);
clearModifier(event);
};
elementEventMap.set(element, {
keydownListener,
keyupListenr,
capture
});
addEvent(element, 'keydown', keydownListener, capture);
addEvent(element, 'keyup', keyupListenr, capture);
}
if (!winListendFocus) {
const listener = () => {
_downKeys = [];
};
winListendFocus = {
listener,
capture
};
addEvent(window, 'focus', listener, capture);
}
}
}
function trigger(shortcut) {
let scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'all';
Object.keys(_handlers).forEach(key => {
const dataList = _handlers[key].filter(item => item.scope === scope && item.shortcut === shortcut);
dataList.forEach(data => {
if (data && data.method) {
data.method();
}
});
});
}
// 销毁事件,unbind之后判断element上是否还有键盘快捷键如果没有移除监听
function removeKeyEvent(element) {
const values = Object.values(_handlers).flat();
const findindex = values.findIndex(_ref4 => {
let {
element: el
} = _ref4;
return el === element;
});
if (findindex < 0) {
const {
keydownListener,
keyupListenr,
capture
} = elementEventMap.get(element) || {};
if (keydownListener && keyupListenr) {
removeEvent(element, 'keyup', keyupListenr, capture);
removeEvent(element, 'keydown', keydownListener, capture);
elementEventMap.delete(element);
}
}
if (values.length <= 0 || elementEventMap.size <= 0) {
// 移除所有的元素上的监听
const eventKeys = Object.keys(elementEventMap);
eventKeys.forEach(el => {
const {
keydownListener,
keyupListenr,
capture
} = elementEventMap.get(el) || {};
if (keydownListener && keyupListenr) {
removeEvent(el, 'keyup', keyupListenr, capture);
removeEvent(el, 'keydown', keydownListener, capture);
elementEventMap.delete(el);
}
});
// 清空 elementEventMap
elementEventMap.clear();
// 清空 _handlers
Object.keys(_handlers).forEach(key => delete _handlers[key]);
// 移除window上的focus监听
if (winListendFocus) {
const {
listener,
capture
} = winListendFocus;
removeEvent(window, 'focus', listener, capture);
winListendFocus = null;
}
}
}
const _api = {
getPressedKeyString,
setScope,
getScope,
deleteScope,
getPressedKeyCodes,
getAllKeyCodes,
isPressed,
filter,
trigger,
unbind,
keyMap: _keyMap,
modifier: _modifier,
modifierMap
};
for (const a in _api) {
if (Object.prototype.hasOwnProperty.call(_api, a)) {
hotkeys[a] = _api[a];
}
}
if (typeof window !== 'undefined') {
const _hotkeys = window.hotkeys;
hotkeys.noConflict = deep => {
if (deep && window.hotkeys === hotkeys) {
window.hotkeys = _hotkeys;
}
return hotkeys;
};
window.hotkeys = hotkeys;
}
return hotkeys;
}));

File diff suppressed because one or more lines are too long

View File

@ -1,14 +0,0 @@
hotkeys('ctrl+enter', function() {
var ele = document.getElementById('aiterm');
var svg = document.getElementById('aisvg');
if (ele.style.display == 'none') {
ele.style.display = 'block';
svg.style.display = 'none';
ele.focus();
} else {
ele.style.display = 'none';
svg.style.display = 'block';
svg.focus();
}
});

View File

@ -1,181 +0,0 @@
export interface HotkeysEvent {
key: string;
keys: number[];
method: KeyHandler;
mods: number[];
scope: string;
shortcut: string;
}
export interface KeyHandler {
(keyboardEvent: KeyboardEvent, hotkeysEvent: HotkeysEvent): void | boolean;
}
type Options = {
scope?: string;
element?: HTMLElement | null;
keyup?: boolean | null;
keydown?: boolean | null;
capture?: boolean
splitKey?: string;
single?: boolean;
}
export interface Hotkeys {
(key: string, method: KeyHandler): void;
(key: string, scope: string, method: KeyHandler): void;
(key: string, options: Options, method: KeyHandler): void;
shift: boolean;
ctrl: boolean;
alt: boolean;
option: boolean;
control: boolean;
cmd: boolean;
command: boolean;
keyMap: Record<string, number>;
modifier: Record<string, number>;
modifierMap: Record<string, number | string>;
/**
* Use the `hotkeys.setScope` method to set scope. There can only be one active scope besides 'all'. By default 'all' is always active.
*
* ```js
* // Define shortcuts with a scope
* hotkeys('ctrl+o, ctrl+alt+enter', 'issues', function() {
* console.log('do something');
* });
* hotkeys('o, enter', 'files', function() {
* console.log('do something else');
* });
*
* // Set the scope (only 'all' and 'issues' shortcuts will be honored)
* hotkeys.setScope('issues'); // default scope is 'all'
* ```
*/
setScope(scopeName: string): void;
/**
* Use the `hotkeys.getScope` method to get scope.
*
* ```js
* hotkeys.getScope();
* ```
*/
getScope(): string;
/**
* Use the `hotkeys.deleteScope` method to delete a scope. This will also remove all associated hotkeys with it.
*
* ```js
* hotkeys.deleteScope('issues');
* ```
* You can use second argument, if need set new scope after deleting.
*
* ```js
* hotkeys.deleteScope('issues', 'newScopeName');
* ```
*/
deleteScope(scopeName: string, newScopeName?: string): void;
/**
* Relinquish HotKeyss control of the `hotkeys` variable.
*
* ```js
* var k = hotkeys.noConflict();
* k('a', function() {
* console.log("do something")
* });
*
* hotkeys()
* // -->Uncaught TypeError: hotkeys is not a function(anonymous function)
* // @ VM2170:2InjectedScript._evaluateOn
* // @ VM2165:883InjectedScript._evaluateAndWrap
* // @ VM2165:816InjectedScript.evaluate @ VM2165:682
* ```
*/
noConflict(): Hotkeys;
/**
* trigger shortcut key event
*
* ```js
* hotkeys.trigger('ctrl+o');
* hotkeys.trigger('ctrl+o', 'scope2');
* ```
*/
trigger(shortcut: string, scope?: string): void;
unbind(key?: string): void;
unbind(key: string, scopeName: string): void;
unbind(key: string, scopeName: string, method: KeyHandler): void;
unbind(key: string, method: KeyHandler): void;
/** For example, `hotkeys.isPressed(77)` is true if the `M` key is currently pressed. */
isPressed(keyCode: number): boolean;
/** For example, `hotkeys.isPressed('m')` is true if the `M` key is currently pressed. */
isPressed(keyCode: string): boolean;
/**
* Returns an array of key codes currently pressed.
*
* ```js
* hotkeys('command+ctrl+shift+a,f', function() {
* console.log(hotkeys.getPressedKeyCodes()); //=> [17, 65] or [70]
* })
* ```
*/
getPressedKeyCodes(): number[];
/**
* Returns an array of key codes currently pressed.
*
* ```js
* hotkeys('command+ctrl+shift+a,f', function() {
* console.log(hotkeys.getPressedKeyString()); //=> ['⌘', '⌃', '⇧', 'A', 'F']
* })
* ```
*/
getPressedKeyString(): string[];
/**
* Get a list of all registration codes.
*
* ```js
* hotkeys('command+ctrl+shift+a,f', function() {
* console.log(hotkeys.getAllKeyCodes());
* // [
* // { scope: 'all', shortcut: 'command+ctrl+shift+a', mods: [91, 17, 16], keys: [91, 17, 16, 65] },
* // { scope: 'all', shortcut: 'f', mods: [], keys: [42] }
* // ]
* })
* ```
*
*/
getAllKeyCodes(): Omit<HotkeysEvent, 'method' | 'key'>[];
/**
* By default hotkeys are not enabled for `INPUT` `SELECT` `TEXTAREA` elements.
* `Hotkeys.filter` to return to the `true` shortcut keys set to play a role,
* `false` shortcut keys set up failure.
*
* ```js
* hotkeys.filter = function(event){
* return true;
* }
* //How to add the filter to edit labels. <div contentEditable="true"></div>
* //"contentEditable" Older browsers that do not support drops
* hotkeys.filter = function(event) {
* var target = event.target || event.srcElement;
* var tagName = target.tagName;
* return !(target.isContentEditable || tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA');
* }
*
* hotkeys.filter = function(event){
* var tagName = (event.target || event.srcElement).tagName;
* hotkeys.setScope(/^(INPUT|TEXTAREA|SELECT)$/.test(tagName) ? 'input' : 'other');
* return true;
* }
* ```
*/
filter(event: KeyboardEvent): boolean;
}
// https://github.com/eiriklv/react-masonry-component/issues/57
declare var hotkeys: Hotkeys;
export default hotkeys;

View File

@ -1,7 +0,0 @@
if (process.env.NODE_ENV === 'production') {
// eslint-disable-next-line global-require
module.exports = require('./dist/hotkeys.common.min.js');
} else {
// eslint-disable-next-line global-require
module.exports = require('./dist/hotkeys.common.js');
}

View File

@ -1,32 +0,0 @@
{
"name": "hotkeys-js",
"description": "A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies.",
"version": "3.13.7",
"main": "index.js",
"types": "index.d.ts",
"module": "dist/hotkeys.esm.js",
"files": [
"index.d.ts",
"dist",
"doc"
],
"keywords": [
"hotkey",
"hotkeys",
"hotkeys-js",
"hotkeysjs",
"key",
"keys",
"keyboard",
"shortcuts",
"keypress"
],
"author": "kenny wong <wowohoo@qq.com>",
"license": "MIT",
"homepage": "https://jaywcjlove.github.io/hotkeys-js",
"funding": "https://jaywcjlove.github.io/#/sponsor",
"repository": {
"type": "git",
"url": "https://github.com/jaywcjlove/hotkeys-js.git"
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

View File

@ -0,0 +1,99 @@
@font-face {
font-family: 'icomoon';
src: url('fonts/icomoon.eot?3louk1');
src: url('fonts/icomoon.eot?3louk1#iefix') format('embedded-opentype'),
url('fonts/icomoon.ttf?3louk1') format('truetype'),
url('fonts/icomoon.woff?3louk1') format('woff'),
url('fonts/icomoon.svg?3louk1#icomoon') format('svg');
font-weight: normal;
font-style: normal;
font-display: block;
}
[class^="icon-"], [class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'icomoon' !important;
speak: never;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-cube:before {
content: "\e900";
}
.icon-game:before {
content: "\e9d5";
}
.icon-card:before {
content: "\e9d6";
}
.icon-book:before {
content: "\e9d7";
}
.icon-git_bg:before {
content: "\e9d4";
}
.icon-git:before {
content: "\e9d3";
}
.icon-moji_a:before {
content: "\e9c3";
}
.icon-archlinux:before {
content: "\e9c4";
}
.icon-archlinuxjp:before {
content: "\e9c5";
}
.icon-syui:before {
content: "\e9c6";
}
.icon-phoenix-power:before {
content: "\e9c7";
}
.icon-phoenix-world:before {
content: "\e9c8";
}
.icon-power:before {
content: "\e9c9";
}
.icon-phoenix:before {
content: "\e9ca";
}
.icon-honeycomb:before {
content: "\e9cb";
}
.icon-ai:before {
content: "\e9cc";
}
.icon-robot:before {
content: "\e9cd";
}
.icon-sandar:before {
content: "\e9ce";
}
.icon-moon:before {
content: "\e9cf";
}
.icon-home:before {
content: "\e9d0";
}
.icon-cloud:before {
content: "\e9d1";
}
.icon-api:before {
content: "\e9d2";
}
.icon-aibadge:before {
content: "\ebf8";
}
.icon-aiterm:before {
content: "\ebf7";
}