Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import moe.ono.config.ONOConf
import moe.ono.constants.Constants
import moe.ono.hooks._base.BaseClickableFunctionHookItem
import moe.ono.hooks._core.factory.HookItemFactory
import moe.ono.hooks.base.util.Toasts
import moe.ono.hooks.item.chat.QQBubbleRedirect
import moe.ono.hooks.item.chat.StickerPanelEntry
import moe.ono.hooks.item.sigma.QQMessageTracker
Expand Down Expand Up @@ -659,8 +660,7 @@ object ClickableFunctionDialog {
builder.setPositiveButton("确定") { dialog, i ->
val itemId = input.text.toString().trim()
if (itemId.isEmpty()) {
warningText.text = "气泡 Item ID 不能为空"
dialog.dismiss()
Toasts.error(context, "ItemID 不能为空")
return@setPositiveButton
}
QQBubbleRedirect.createCacheFile(itemId)
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/moe/ono/hooks/dispatcher/MenuBuilderHook.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import moe.ono.hooks._base.ApiHookItem
import moe.ono.hooks._core.annotation.HookItem
import moe.ono.hooks.item.chat.StickerPanelEntry
import moe.ono.hooks.item.developer.QQMessageFetcher
import moe.ono.hooks.item.entertainment.ModifyTextMessage
import moe.ono.hooks.item.entertainment.RespondFace
import moe.ono.hooks.item.sigma.QQMessageTracker
import moe.ono.util.Logger
import java.lang.reflect.Modifier
Expand All @@ -15,6 +17,8 @@ class MenuBuilderHook : ApiHookItem() {
StickerPanelEntry(),
QQMessageTracker(),
QQMessageFetcher(),
ModifyTextMessage(),
RespondFace()
)

override fun entry(classLoader: ClassLoader) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package moe.ono.hooks.item.entertainment

import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.TextView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import de.robv.android.xposed.XC_MethodHook.MethodHookParam
import moe.ono.R
import moe.ono.bridge.ntapi.MsgServiceHelper
import moe.ono.config.ConfigManager
import moe.ono.constants.Constants
import moe.ono.hooks._base.BaseSwitchFunctionHookItem
import moe.ono.hooks._core.annotation.HookItem
import moe.ono.hooks._core.factory.HookItemFactory.getItem
import moe.ono.hooks.base.api.QQMessageViewListener
import moe.ono.hooks.base.api.QQMsgViewAdapter
import moe.ono.hooks.base.util.Toasts
import moe.ono.hooks.dispatcher.OnMenuBuilder
import moe.ono.reflex.FieldUtils
import moe.ono.reflex.Reflex
import moe.ono.ui.CommonContextWrapper
import moe.ono.util.AppRuntimeHelper
import moe.ono.util.ContextUtils
import moe.ono.util.CustomMenu
import moe.ono.util.Logger
import moe.ono.util.Session
import moe.ono.util.SyncUtils

@HookItem(path = "娱乐功能/修改文本消息内容", description = "修改显示文本\n\n* 文本消息长按菜单中使用")
class ModifyTextMessage : BaseSwitchFunctionHookItem(), OnMenuBuilder {

companion object {
val modifyMap = mutableMapOf<String, String>()
}

override fun entry(classLoader: ClassLoader) {
QQMessageViewListener.addMessageViewUpdateListener(this,
object : QQMessageViewListener.OnChatViewUpdateListener {
override fun onViewUpdateAfter(msgItemView: View, msgRecord: Any) {
modifyMessage(msgItemView, msgRecord)
}
})
}

/**
* 修改消息内容
*/
private fun modifyMessage(msgItemView: View, msgRecord: Any) {
if (!ConfigManager.getDefaultConfig().getBooleanOrFalse(Constants.PrekXXX + getItem(this::class.java).path)) return

val contentView = QQMsgViewAdapter.getContentView(msgItemView)

val peerUid: String = FieldUtils.create(msgRecord)
.fieldName("peerUid")
.fieldType(String::class.java)
.firstValue(msgRecord)

val msgSeq: Long = FieldUtils.create(msgRecord)
.fieldName("msgSeq")
.fieldType(Long::class.javaPrimitiveType)
.firstValue(msgRecord)

val senderUin: Long = FieldUtils.create(msgRecord)
.fieldName("senderUin")
.fieldType(Long::class.java)
.firstValue(msgRecord)

if (!modifyMap.contains("$peerUid:$msgSeq:$senderUin")) return

val msgType: Int = FieldUtils.create(msgRecord)
.fieldName("msgType")
.fieldType(Int::class.java)
.firstValue(msgRecord)

if (msgType <= 2) {
if (contentView is ViewGroup) {
if (contentView.getChildAt(0) is ViewGroup) {
val parent = contentView.getChildAt(0) as ViewGroup
if (parent.getChildAt(0) is ViewGroup) {
val parent2 = parent.getChildAt(0) as ViewGroup
if (parent2.getChildAt(0) is ViewGroup) {
val parent3 = parent2.getChildAt(0) as ViewGroup
val aioMsgTextView = parent3.getChildAt(0) as TextView
aioMsgTextView.setText(modifyMap.get("$peerUid:$msgSeq:$senderUin"))
}
}
}
}
}
}

override val targetTypes = arrayOf(
"com.tencent.mobileqq.aio.msglist.holder.component.text.AIOTextContentComponent",
)

override fun onGetMenu(aioMsgItem: Any, targetType: String, param: MethodHookParam) {
if (!getItem(this.javaClass).isEnabled) {
return
}

val item: Any = CustomMenu.createItemIconNt(
aioMsgItem,
"Edit",
R.drawable.ic_baseline_border_color_24,
R.id.item_modify_text_message
) {
try {
val msgID = Reflex.invokeVirtual(aioMsgItem, "getMsgId") as Long
val msgIDs = java.util.ArrayList<Long>()
msgIDs.add(msgID)
AppRuntimeHelper.getAppRuntime()
?.let {
MsgServiceHelper.getKernelMsgService(
it
)
}?.getMsgsByMsgId(
Session.getContact(),
msgIDs
) { _, _, msgList ->
SyncUtils.runOnUiThread {
for (msgRecord in msgList) {
if (!(msgRecord.msgType == 2 && msgRecord.subMsgType == 1)) {
Toasts.error(ContextUtils.getCurrentActivity(), "仅支持文本消息")
} else {
val elem = msgRecord.elements[0].textElement
if (elem == null) {
Toasts.error(ContextUtils.getCurrentActivity(), "仅支持文本消息")
} else {
val context = CommonContextWrapper.createAppCompatContext(
ContextUtils.getCurrentActivity())

val dialog = MaterialAlertDialogBuilder(context)
dialog.setTitle("修改文本消息")

val content = EditText(context)
content.setHint("请输入修改后的内容")
content.setText(elem.content)

dialog.setPositiveButton("修改") { dialogInterface, i ->
modifyMap.put("${msgRecord.peerUid}:${msgRecord.msgSeq}:${msgRecord.senderUin}", content.text.toString())
Toasts.success(ContextUtils.getCurrentActivity(), "修改成功重新进入此界面生效")
dialogInterface.dismiss()
}

dialog.setView(content)
dialog.show()
}
}
}
}
}
} catch (e: Exception) {
Logger.e("QQPullMsgEntry.msgLongClick", e)
}
Unit
}
param.result = listOf(item) + param.result as List<*>
}
}
75 changes: 75 additions & 0 deletions app/src/main/java/moe/ono/hooks/item/entertainment/RespondFace.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package moe.ono.hooks.item.entertainment

import android.annotation.SuppressLint
import de.robv.android.xposed.XC_MethodHook.MethodHookParam
import moe.ono.R
import moe.ono.bridge.ntapi.MsgServiceHelper
import moe.ono.hooks._base.BaseSwitchFunctionHookItem
import moe.ono.hooks._core.annotation.HookItem
import moe.ono.hooks._core.factory.HookItemFactory.getItem
import moe.ono.hooks.dispatcher.OnMenuBuilder
import moe.ono.hooks.protocol.sendPacket
import moe.ono.reflex.Reflex
import moe.ono.util.AppRuntimeHelper
import moe.ono.util.CustomMenu
import moe.ono.util.Logger
import moe.ono.util.Session
import moe.ono.util.SyncUtils
import kotlin.random.Random


@SuppressLint("DiscouragedApi")
@HookItem(path = "娱乐功能/回应表情", description = "回应 20 个小表情\n\n* 长按消息菜单 “回应” 按钮")
class RespondFace : BaseSwitchFunctionHookItem(), OnMenuBuilder {

override fun entry(classLoader: ClassLoader) {}

override fun onGetMenu(aioMsgItem: Any, targetType: String, param: MethodHookParam) {
if (!getItem(this.javaClass).isEnabled) {
return
}

val item: Any = CustomMenu.createItemIconNt(
aioMsgItem,
"回应",
R.drawable.ic_baseline_auto_fix_high_24,
R.id.item_respond_face
) {
try {
val msgID = Reflex.invokeVirtual(aioMsgItem, "getMsgId") as Long
val msgIDs = java.util.ArrayList<Long>()
msgIDs.add(msgID)
AppRuntimeHelper.getAppRuntime()
?.let {
MsgServiceHelper.getKernelMsgService(
it
)
}?.getMsgsByMsgId(
Session.getContact(),
msgIDs
) { _, _, msgList ->
SyncUtils.runOnUiThread {
for (msgRecord in msgList) {
val peerUid = msgRecord.peerUid
val msgSeq = msgRecord.msgSeq

Thread {
for (i in 1 .. 50) {
val faceId = Random.nextInt(1, 200)
val body = """{"1":36994,"2":1,"4":{"2":$peerUid,"3":$msgSeq,"4":"$faceId","5":1,"6":0,"7":0},"12":1}"""

sendPacket("OidbSvcTrpcTcp.0x9082_2", body)
Thread.sleep(100)
}
}.start()
}
}
}
} catch (e: Exception) {
Logger.e("QQPullMsgEntry.msgLongClick", e)
}
Unit
}
param.result = listOf(item) + param.result as List<*>
}
}
2 changes: 2 additions & 0 deletions app/src/main/res/values/ids.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@
<item type="id" name="item_check" />
<item type="id" name="item_pull_msg" />
<item name="ivTitleName" type="id"/>
<item name="item_modify_text_message" type="id" />
<item name="item_respond_face" type="id" />
</resources>
Loading