大風呂は敷(迷信解毒)。

迷信解毒というか政治経済ネットのニュースなどに三人称多視点ぽくツッコミ入れていくスタイル。

LTsv8Py(tsvtool8) version 20150724F235805。漢直kantrayのPython移植(WindowsとLinux)の進捗。あとSandS復活するかも。

ミユ「Pythonを使うことでWindows版とLinux版のkantray同時開発が可能に(たぶん)。その下準備としてtsvtoolをPython移植してる所。
今回はGUI(とキーフック)以外の、print,file,time,calc,joy,kbdモジュー作成の補足。


フレア「GUIまだだよ的な話でGUI動いてるとかいう高度な情報戦。」
ミユ「PuppyではTkinterもPyGTKも基本的に動きませんよ。

ので、Puppy用GTKモジュールを独自開発というかBaCon版の「guimoduleL.bac」を移植予定。というのが今回の進捗報告本題。
どっちにしろkantrayに必要なタスクトレイとキーフックは独自実装の予感だし。
タスクトレイの表示はHSPとかでやったことあるからなんとかなりそうだけど、PythonでのWindowsキーフックが鬼門。」

フレア「kantrayから一度消えた「SandS」復活の経緯も。」
ミユ「SandSの意味は「Space and Shift」。[Space]キーをシフトキーの代用。シフトキーとして使われなかった条件で離した時に空白の入力。
キーを離した時に入力ってのが若干複雑だったので一旦削ってシンプルにしたつもりだったけど、
WindowsってCapsLockを別な事に使おうとするとOSのかなり深い所に手を突っ込まなければならない事を思い出すなど。

Vista以降のWindowsにおいて全てのカーネルモードコードに個人では取得不能なコードサイニング証明書が必須
法人化およびコードサイニング証明書の取得には多額のコストがかかるため、のどかはシェアウェア化(1,800円)された。
Windows XPレベルに匹敵するキーボードカスタマイズ環境がついに整備されたのだ。

Vista/Windows 7のキーボードカスタマイズ問題がついに解決 - A Successful Failure

WindowsLinuxとで同じ動作をさせたいので[CapsLock]は廃止の方向で。[CapsLock]→[KANA]→[Space]。
[KANA]キーをα鍵盤や辞書項目変更に割り当て、[Space]キーを字引入力に割り当て。親指に揃える事で操作説明のエントロピー増大は防げたかと。
ついでに濁音拗音入力も字引入力に任せることで「SandSで濁音入力」みたいな宣伝効果に期待。」

フレア「kantrayに関わる事はひとまず言ったっけ。」
シルキ「LTsv8Pyのロゴの蛇はsiroganeの干支の流用になってるよね。

フレア「そういうことやなしに機能的な話で。」
ミユ「分数電卓で数列和・数列積が使えるようになったから1から100まで全部足して5050とか、階乗の256!の計算ができるようになったり。
「(cS1~100)⇔5050|1」
「(c!1~256)⇔8578177753428426541190822716812326
2515778152027948561985965565037726
9452553147589377440291360451408450
3758853423365843061571968346936964
7532228928849742602567963733256336
8786442675207626794560187968867971
5211433077020775266464514647091873
2610083287632570281898077367178145
4170250523018608495319068138257481
0702528175594594769870346657127381
3928620523475680821886070120361108
3152093501947437109101726968262861
6062636624350228409441914084246159
3600000000000000000000000000000000
0000000000000000000000000000000|1」(477桁もあって普通に表示できなかったので折り返し)
他の言語だと巨大な数を扱うライブラリ自体が存在しなかったりしたけどPythonだと整数に上限無いから作るのがすごい楽。

Pythonと直接関係無いけどついでで漢数字の括弧化と括弧の内側から計算する正規表現とか括弧の数を揃えるアルゴリズムは書いておいた方がよさそうなので抜粋。

def LTsv_calc_bracketsbalance(LTsv_calcQbase):
    LTsv_calcQ=LTsv_calcQbase.replace('\n','\t').replace('\t',''); LTsv_calcA=""
    LTsv_bracketLR=0; LTsv_bracketCAP=0
    for LTsv_Q in LTsv_calcQ:
        if LTsv_Q in LTsv_opechardic:
            LTsv_Q=LTsv_opechardic[LTsv_Q]
        if LTsv_Q in LTsv_calcusemark:
            LTsv_calcA+=LTsv_Q
        if LTsv_Q == '(':
            LTsv_bracketLR+=1
        if LTsv_Q == ')':
            LTsv_bracketLR-=1
            if LTsv_bracketLR<LTsv_bracketCAP:
                LTsv_bracketCAP=LTsv_bracketLR
    if LTsv_bracketLR > 0:
        LTsv_calcA=LTsv_calcA+')'*abs(LTsv_bracketLR)
    if LTsv_bracketLR < 0:
        LTsv_calcA='('*abs(LTsv_bracketLR)+LTsv_calcA
    LTsv_calcA='('*abs(LTsv_bracketCAP)+LTsv_calcA+')'*abs(LTsv_bracketCAP)
    LTsv_calcA=LTsv_calcA.replace('y','('+str(math.pi)+')').replace('e','('+str(math.e)+')').replace('n','(n|0)')
    for LTsv_opecase in LTsv_opemarkdic:
        if LTsv_opecase in LTsv_calcA:
            LTsv_calcA=LTsv_calcA.replace(LTsv_opecase,LTsv_opemarkdic[LTsv_opecase])
    LTsv_calcA=re.sub(re.compile("([0-9千百十]+?)銭"),"+(\\1/100)",LTsv_calcA)
    LTsv_calcA=re.sub(re.compile("([0-9千百十]+?)万"),"(\\1)*1"+'0'*4+"+",LTsv_calcA)
    LTsv_calcA=re.sub(re.compile("([0-9千百十]+?)億"),"(\\1)*1"+'0'*8+"+",LTsv_calcA)
    LTsv_calcA=re.sub(re.compile("([0-9千百十]+?)兆"),"(\\1)*1"+'0'*12+"+",LTsv_calcA)
    LTsv_calcA=re.sub(re.compile("([0-9千百十]+?)京"),"(\\1)*1"+'0'*16+"+",LTsv_calcA)
    LTsv_calcA=re.sub(re.compile("([0-9千百十]+?)垓"),"(\\1)*1"+'0'*20+"+",LTsv_calcA)
    LTsv_calcA=re.sub(re.compile("([0-9]+?)千"),"(\\1*1000)+",LTsv_calcA)
    LTsv_calcA=re.sub(re.compile("([0-9]+?)百"),"(\\1*100)+",LTsv_calcA)
    LTsv_calcA=re.sub(re.compile("([0-9]+?)十"),"(\\1*10)+",LTsv_calcA)
    for LTsv_okusen in LTsv_okusenman:
        LTsv_calcA=LTsv_calcA.replace(LTsv_okusen,LTsv_okusendic[LTsv_okusen])
    return LTsv_calcA
def LTsv_calc(LTsv_calcQbase):
    LTsv_calcQ=LTsv_calcQbase.replace('\n','\t').replace('\t',''); LTsv_calcA="n|0"
    LTsv_calcQ=LTsv_calc_bracketsbalance(LTsv_calcQbase); LTsv_calcA=LTsv_calcQ
    LTsv_bracketreg=re.compile("[(](?<=[(])[^()]*(?=[)])[)]")
    while "(" in LTsv_calcA:
        for LTsv_func in re.findall(LTsv_bracketreg,LTsv_calcA):
            LTsv_calcA=LTsv_calcA.replace(LTsv_func,LTsv_calc_function(LTsv_func))
    LTsv_calcA=LTsv_calcA.replace(LTsv_calcA,LTsv_calc_function(LTsv_calcA))
    LTsv_calcA=LTsv_calc_fractalize(LTsv_calcA)
    if LTsv_calcA==LTsv_calcQ:
        LTsv_calcA=LTsv_calc_decimalize(LTsv_calcA)
    return LTsv_calcA


フレア「演算子replaceの技術が半角を全角に変換する「LTsv_kanare」でうに濁点「ゔ(う゛)」などのかな変換アルファベット変換半角変換などに使われてるはず。

LTsv_HiraZen_DAK="&#12436;がぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽ"
LTsv_KataZen_DAK="ヴガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポ"

&#12436;と表示されてるのは、はてな記法の都合。

  LTsv_kanare(LTsv_before,LTsv_recase)
   全角半角大文字小文字ひらがなカタカナの変換を行います。LTsv_beforeに変換する文字列、LTsv_recaseで辞書指定。
    "Hira2Kata"         ひらがなをカタカナに。
    "Kata2Hira"         カタカナをひらがなに。
    "HiraKana2Sei"      濁音を清音に。「ぱぴぷぺぽ」と「ぱぴぷぺぽ」は「はひふへほ」に。
    "HiraKana2DakB"     清音を濁音に。「はひふへほ」は「ばびぶべぼ」に。
    "HiraKana2DakP"     清音を濁音に。「はひふへほ」は「ばびぶべぼ」に。「まみむめも」を「ぱぴぷぺぽ」に。「
    "HiraKana2Han"      ひらがなもカタカナも半角に。
    "HiraKana2HanKaKe"  ひらがなもカタカナも「ヶヵ」も半角に。
    "Han2HiraEz"        半角をひらがなに(濁音は分離したまま)。
    "Han2KataEz"        半角をカタカナに(濁音は分離したまま)。
    "Han2Hira"          半角をひらがなに(濁音があっても1つの文字に統合)。
    "Han2Kata"          半角をカタカナに(濁音があっても1つの文字に統合)。
    "Alpha2BIG"         半角全角にかかわらずアルファベットを大文字に(キリル文字ギリシャ文字含む)。
    "Alpha2SML"         半角全角にかかわらずアルファベットを小文字に(キリル文字ギリシャ文字含む)。
    "Alpha2HAN"         大文字小文字にかかわらずアルファベットを半角に(キリル文字ギリシャ文字含まない)。
    "Alpha2ZENBS"       大文字小文字にかかわらずアルファベットを全角に(キリル文字ギリシャ文字含まない)。バックスラッシュは「\」へ。
    "Alpha2ZENYen"      大文字小文字にかかわらずアルファベットを全角に(キリル文字ギリシャ文字含まない)。バックスラッシュは「¥」へ。

LTsv_kanare(kanare_value,'Alpha2ZENBS')
!"#$%&'()*+,-./0123456789;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~↓
!”#$%&’()*+,−./0123456789;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}〜
LTsv_kanare(kanare_value,'Alpha2ZENYen')
!"#$%&'()*+,-./0123456789;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~↓
!”#$%&’()*+,−./0123456789;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[¥]^_`abcdefghijklmnopqrstuvwxyz{|}〜

さてモジュールの変換機能をkantrayにも全角変換機能あるけどバックスラッシュを円記号にしていいのか問題ってどーしたもんか。

ミユ「「全」とは別に「\」「¥」でも変換できるようにコマンド増やしてしまうのどう?
「全」なんて曖昧な指示からの後出しジャンケンを防ぐために例えば「zen_backslash\t\」みたいにどっちでも良い時にどっちでもいいのなら普段はこっちでやりますよ的なルールを事前に文書で決めておく。
「\」に変換させる必要な場合にはコマンド入力の時に「\」「¥」を入力させる。「\」の確率が多いのが分かった時は次回起動時というか起動前に「kantray.tsv」に「zen_backslash\t¥」と設定しとけばいじゃんと。」
フレア「漢直の仕様を作ってるつもりが契約プログラミング的な領域に突入。」
ミユ「ついでに置換処理の件で言って置くと「LTsv_Q=LTsv_opechardic[LTsv_Q]」なんてのは他の言語でもあるから感動ポイントではなく、
「LTsv_opechardic=dict(zip(list(LTsv_character),list(LTsv_operator)))」みたいに2つの文字列から辞書というかタプルの対のリストが作れるみたいなのがPythonの感動ポイント。」
フレア「アッハイ。」
ミユ「Pythonの話まだ途中なんだけど。辞書をfor文で使う時「for LTsv_label,LTsv_data in list(LTsv_dict.items()):」みたいにlistで括る話とか」
フレア「Pythonネタはあくまでおまけでkantrayの話をば。」
レクィド「思ったんだけどタプルあればtsvいらなくね?
C言語みたいにポインタ渡してポインタの参照先が気が付くと書き換わるとか見ても分からねー事しなくても関数の帰り値で直接配列とか受け取れるんだよな。」
ミユ「逆。タプルを保存するには何らかのテキストフォーマットが必要な訳で、LTSVは必要。今回はLTSVとタプルの変換関数も用意。
(執筆段階で「LTsv_tsv2list」という関数を間違って削っていた事に気が付く等orz「LTsv_tsv2tuple」は次回更新時に直します。)

def LTsv_tuple2tsv(LTsv_tuple):
    LTsv_line=""
    for LTsv_data in LTsv_tuple:
        LTsv_line+=str(LTsv_data)+'\t'
    return LTsv_line.rstrip('\t')

def LTsv_tsv2tuple(LTsv_line):
    LTsv_tuple=tuple(LTsv_tsv2list(LTsv_line))
    return LTsv_tuple

def LTsv_intstr0x(LTsv_codestr):
    LTsv_codeint=0
    for LTsv_hexstr in ["0x","$"]:
        if LTsv_hexstr in LTsv_codestr:
            try:
                LTsv_codeint=int(LTsv_codestr.replace(LTsv_hexstr,""),16)
            except ValueError:
                pass
            break
    else:
        try:
            LTsv_codeint=int(LTsv_codestr)
        except ValueError:
            pass
    return LTsv_codeint

def LTsv_label2dictint(LTsv_line):
    LTsv_labels=""; LTsv_datas=""; LTsv_dict={}
    LTsv_splitlabels=LTsv_joindatanum(LTsv_line,0,"").strip('\n').split('\t')
    for LTsv_split in LTsv_splitlabels:
        if len(LTsv_split) > 0:
            lisv_posL=LTsv_split.find(':')
            if lisv_posL > 0:
                LTsv_label=LTsv_split[:lisv_posL]
                LTsv_data=LTsv_split[lisv_posL+len('\t'):]
                if len(LTsv_label) > 0 and len(LTsv_data) > 0:
                    LTsv_dict[LTsv_label]=LTsv_intstr0x(LTsv_data)
    return LTsv_dict

def LTsv_label2dictstr(LTsv_line):
    LTsv_labels=""; LTsv_datas=""; LTsv_dict={}
    LTsv_splitlabels=LTsv_joindatanum(LTsv_line,0,"").strip('\n').split('\t')
    for LTsv_split in LTsv_splitlabels:
        if len(LTsv_split) > 0:
            lisv_posL=LTsv_split.find(':')
            if lisv_posL > 0:
                LTsv_label=LTsv_split[:lisv_posL]
                LTsv_data=LTsv_split[lisv_posL+len('\t'):]
                if len(LTsv_label) > 0 and len(LTsv_data) > 0:
                    LTsv_dict[LTsv_label]=LTsv_data
    return LTsv_dict

def LTsv_dict2label(LTsv_dict):
    LTsv_line=""
    for LTsv_label,LTsv_data in list(LTsv_dict.items()):
        LTsv_line+=LTsv_label+':'+str(LTsv_data)+'\t'
    return LTsv_line.rstrip('\t')


言語の仕様から独立した「L:Tsv」だからこそイザと言うとき他の言語に資産を移植できるわけで。」
フレア「さっきも言ったけどkantrayの進捗が本題なのでLTsv8Pyの進捗の話に軸を。Pythonに引越したばっかりなのに更に他の言語に引っ越すとか話進まんし。」
シルキ「移植ばっかりやって新作が出てこないのって苦痛なんだよ?」
ミユ「Pythonに拠点築ければWindowsLinuxで動くゲームとか作れるはずなのでもうちょい我慢。」

シルキ「そういえばsiroganeのLinux移植もかなり送れてた(始まってもいない)ような…」
ミユ「HSPですら可能だったウィンドウ大きさ変更がBaConで実装する方法結局見つからなかった衝撃。」
フレア「PuppyLinuxだと結局PythonでもGTK2依存だから状況そのままな気も。」
ミユ「代わりとは違うけどPython日時計算のライブラリが豊富なので調査リソースは稼げるものと見積。

def LTsv_yearweeks(LTsv_toyear):
    LTsv_Y,LTsv_WN,LTsv_WD=datetime.date(LTsv_toyear,12,31).isocalendar()
    LTsv_YW=LTsv_WN if LTsv_Y==LTsv_toyear else datetime.date(LTsv_toyear,12,24).isocalendar()[1]
    return LTsv_YW

Pythonなら週番号の最大値が52なのか53なのかの計算も楽。
(20150724F235805版は「LTsv_Y==LTsv_toyear」が「LTsv_Y!=LTsv_toyear」になってるバグあるので注意、次回更新時修正)。
「isocalendar」ってのがいわゆる週番号関連。Pythonを使えば週番号の計算を自前で用意しなくて済むので雑用重荷が軽減。

フレア「日時フォーマットの単体風テストちょっと散らかって過ぎませんか

ミユ「デバッグの都合で機能ほぼ全部載せ的な事してたので、日時フォーマットのテスト(ついでに電卓フォーマットのテスト)をしたい場合は「TKkeytimetest.py」を使うのが無難。
Windowsの「GetAsyncKeyState」を受けとるためにもTKkeytimetestが必要。

キーボード入力「LTsv_kbd.py」の単体風テストはWindows(Wine)では動かない。」

シルキ「ジョイスティック(ゲームPAD)と同じように動かせないの?

ミユ「Linux使ってると忘れがちだけど、WindowsLinuxみたいにファイルをオープンする感覚でデバイスにアクセスできない。
よってWindowsにはEVIOCGRABみたいな文字出力抑制のための都合良い機能も無い。

def LTsv_kbdEVIOCGRAB(LTsv_grabflag):
    global LTsv_kbdevpath,LTsv_kbdhands
    if sys.platform.startswith("linux"):
        if LTsv_kbdhands !=0 :
            fcntl.ioctl(LTsv_kbdhands,LTsv_EVIOCGRAB,1 if LTsv_grabflag !=0 else 0)

Windowsの場合DLLが必要とかWH_KEYBOARD_LLならDLL不要かもとか情報錯綜すれどPython実装の具体例がまだ見つからないのでその辺の検証が必要。
しかも執筆段階でGoogle先生はまだ「SetWindowsHookEx」と「WH_KEYBOARD_LL」を混同してる様子。」
レクィド「マウスだけで操作するkantestだけでも乗っけとけば良かったのとちゃう?」
フレア「PythonGUIを扱うモジュールができてないということは、Canvas的な描画部品のクリックとかフリックとか無理だし、
最近のWindowsって8以降つか7も10になるし、スマホタブレットみたいな画面を触る操作にも配慮しなければならない空気だから、右クリックやホイールを使わないパターンの操作方法も想定させないと。
鍵盤選択と文字選択をボタン使わずにどうやって区別するのか、GUIでき上がってから触らないと操作方法思いつかない予感。」
ミユ「スマホタブレットは右クリックとか使えないからMacの1ボタン並みの退化。」
フレア「いやマウスとかペンタブといった部品が無くても動くってのは故障の心配が無いという意味で進化だと思いますけど。」
シルキ「そもそも今のXPスペックのノートはキーボード(ディスプレイも)が壊れてて時々押しても反応しないという時限爆弾。」
フレア「ジョイスティック(ゲームPAD)は漢直に入りますか的な。」