OSDN Git Service

6ca60662b5965fed97f0e5dc8bf391392da749af
[kcd/KCD.git] / KCD / GameViewController.swift
1 //
2 //  GameViewController.swift
3 //  KCD
4 //
5 //  Created by Hori,Masaki on 2016/12/31.
6 //  Copyright © 2016年 Hori,Masaki. All rights reserved.
7 //
8
9 import Cocoa
10 import WebKit
11 import JavaScriptCore
12
13 final class GameViewController: NSViewController {
14     
15     private static let gamePageURL = "http://www.dmm.com/netgame/social/-/gadgets/=/app_id=854854/"
16     private static let loginPageURLPrefix = "https://www.dmm.com/my/-/login/=/"
17     
18     @IBOutlet private var webView: WebView!
19     
20     override var nibName: NSNib.Name {
21         
22         return .nibName(instanceOf: self)
23     }
24     
25     private var flashTopLeft = NSPoint(x: 2600, y: 1445)
26     private var clipView: NSClipView {
27         
28         return view as! NSClipView  // swiftlint:disable:this force_cast
29     }
30     
31     override func viewDidLoad() {
32         
33         super.viewDidLoad()
34         
35         clipView.documentView = webView
36         
37         adjustFlash()
38         
39         webView.mainFrame.frameView.allowsScrolling = false
40         
41         webView.applicationNameForUserAgent = AppDelegate.shared.appNameForUserAgent
42         webView.mainFrameURL = GameViewController.gamePageURL
43     }
44     
45     func adjustFlash() {
46         
47         webView.superview?.scroll(flashTopLeft)
48     }
49     
50     @IBAction func reloadContent(_ sender: AnyObject?) {
51         
52         guard let _ = webView.mainFrameURL else {
53             
54             webView.mainFrameURL = GameViewController.gamePageURL
55             
56             return
57         }
58         
59         // ゲームページでない場合はゲームページを表示する
60         if webView.mainFrameURL != GameViewController.gamePageURL {
61             
62             webView.mainFrameURL = GameViewController.gamePageURL
63             
64             return
65         }
66         if webView.mainFrameURL.hasPrefix(GameViewController.loginPageURLPrefix) {
67             
68             webView.reload(sender)
69             
70             return
71         }
72         
73         adjustFlash()
74         
75         let prevDate = UserDefaults.standard[.prevReloadDate]
76         if Date(timeIntervalSinceNow: 0.0).timeIntervalSince(prevDate) < 1 * 60 {
77             
78             let untilDate = prevDate.addingTimeInterval(1 * 60)
79             let date = DateFormatter.localizedString(from: untilDate, dateStyle: .none, timeStyle: .medium)
80             let alert = NSAlert()
81             alert.messageText = LocalizedStrings.reloadTimeShortenMessage.string
82             let format = LocalizedStrings.reloadTimeShortenInfo.string
83             alert.informativeText = String(format: format, date)
84             alert.runModal()
85             
86             return
87         }
88         
89         webView.reload(sender)
90         
91         UserDefaults.standard[.prevReloadDate] = Date(timeIntervalSinceNow: 0.0)
92     }
93     
94     @IBAction func deleteCacheAndReload(_ sender: AnyObject?) {
95         
96         let panel = ProgressPanel()
97         
98         guard let window = view.window else {
99             
100             return
101         }
102         guard let panelWindow = panel.window else {
103             
104             return
105         }
106         
107         panel.title = ""
108         panel.message = LocalizedStrings.deletingCacheInfo.string
109         panel.animate = true
110         
111         window.beginSheet(panelWindow) { _ in NSSound(named: NSSound.Name("Submarine"))?.play() }
112         
113         AppDelegate.shared.clearCache()
114         
115         window.endSheet(panelWindow)
116     }
117     
118     func screenshotOld() {
119         
120         let frame = webView.visibleRect
121         let screenshotBorder = UserDefaults.standard[.screenShotBorderWidth]
122         let f = frame.insetBy(dx: -screenshotBorder, dy: -screenshotBorder)
123         
124         guard let rep = webView.bitmapImageRepForCachingDisplay(in: f) else {
125             
126             return
127         }
128         
129         webView.cacheDisplay(in: frame, to: rep)
130         
131         ScreenshotRegister(ApplicationDirecrories.screenshotSaveDirectoryURL)
132             .registerScreenshot(rep, name: localizedAppName())
133     }
134     
135     @available(OSX 10.13, *)
136     func screenshot() {
137         
138         let frame = view.visibleRect
139         let screenshotBorder = UserDefaults.standard[.screenShotBorderWidth]
140         let f = frame.insetBy(dx: -screenshotBorder, dy: -screenshotBorder)
141         let windowCoordinateFrame = view.convert(f, to: nil)
142         
143         guard let window = view.window else {
144             
145             Logger.shared.log("Can not get window")
146             
147             return
148         }
149         let screenCoordinsteFrame = window.convertToScreen(windowCoordinateFrame)
150         
151         guard let screen = NSScreen.main else {
152             
153             Logger.shared.log("Can not get Screen")
154             
155             return
156         }
157         let scFrame = screen.frame
158         
159         guard let cxt = window.graphicsContext?.cgContext else {
160             
161             Logger.shared.log("Cannot get Context")
162             
163             return
164         }
165         let deviceCoordinateFrame = cxt.convertToDeviceSpace(screenCoordinsteFrame)
166         let raio = deviceCoordinateFrame.size.width / screenCoordinsteFrame.size.width
167         
168         let trimRect = CGRect(x: raio * screenCoordinsteFrame.origin.x,
169                               y: raio * (scFrame.size.height - screenCoordinsteFrame.origin.y - screenCoordinsteFrame.size.height),
170                               width: raio * screenCoordinsteFrame.size.width,
171                               height: raio * screenCoordinsteFrame.size.height)
172         
173         guard let fullSizeImage = CGDisplayCreateImage(CGMainDisplayID()) else {
174             
175             Logger.shared.log("Can not get Image")
176             
177             return
178         }
179         
180         guard let image = fullSizeImage.cropping(to: trimRect) else {
181             
182             Logger.shared.log("Can not trim image")
183             
184             return
185         }
186         
187         let rep = NSBitmapImageRep(cgImage: image)
188         
189         if rep.size != NSSize(width: 800, height: 480) {
190             
191             rep.size = NSSize(width: 800, height: 480)
192         }
193         
194         ScreenshotRegister(ApplicationDirecrories.screenshotSaveDirectoryURL)
195             .registerScreenshot(rep, name: localizedAppName())
196     }
197     
198     @IBAction func screenShot(_ sender: AnyObject?) {
199         
200         if #available(OSX 10.13, *) {
201             
202             screenshot()
203             
204         } else {
205             
206             screenshotOld()
207         }
208     }
209     
210     override func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
211         
212         guard let action: Selector = menuItem.action else {
213             
214             return false
215         }
216         
217         switch action {
218             
219         case #selector(GameViewController.reloadContent(_:)):
220             
221             guard let _ = webView.mainFrame else {
222                 
223                 return true
224             }
225             guard let frameURL = webView.mainFrameURL else {
226                 
227                 return true
228             }
229             
230             switch frameURL {
231                 
232             case GameViewController.gamePageURL:
233                 menuItem.title = LocalizedStrings.reload.string
234                 
235             case let s where s.hasPrefix(GameViewController.loginPageURLPrefix):
236                 menuItem.title = LocalizedStrings.reload.string
237                 
238             default:
239                 menuItem.title = LocalizedStrings.backToGame.string
240                 
241             }
242             
243             return true
244             
245         case #selector(GameViewController.deleteCacheAndReload(_:)):
246             
247             return true
248             
249         case #selector(GameViewController.screenShot(_:)):
250             
251             return true
252             
253         default: return false
254             
255         }
256     }
257 }
258
259 extension GameViewController: WebFrameLoadDelegate, WebUIDelegate {
260     
261     private static let excludeMenuItemTag = [
262         WebMenuItemTagOpenLinkInNewWindow,
263         WebMenuItemTagDownloadLinkToDisk,
264         WebMenuItemTagOpenImageInNewWindow,
265         WebMenuItemTagOpenFrameInNewWindow,
266         WebMenuItemTagGoBack,
267         WebMenuItemTagGoForward,
268         WebMenuItemTagStop,
269         WebMenuItemTagReload
270     ]
271     
272     func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {
273         
274         guard let path = frame.dataSource?.initialRequest.url?.path else {
275             
276             return
277         }
278         
279         let handler: (JSContext?, JSValue?) -> Void = { (_, exception) in
280             
281             if let exception = exception {
282                 
283                 print("Caught exception in evaluteScript -> \(exception)")
284                 
285             } else {
286                 
287                 print("Caught exception in evaluteScript")
288             }
289         }
290         
291         if path.hasSuffix("gadgets/ifr") {
292             
293             guard let context = frame.javaScriptContext else {
294                 
295                 return
296             }
297             
298             context.exceptionHandler = handler
299             context.evaluateScript(
300                 ["var emb = document.getElementById('flashWrap');",
301                  "var rect = emb.getBoundingClientRect();",
302                  "var atop = rect.top;",
303                  "var aleft = rect.left;"]
304                     .reduce("", +)
305             )
306             let top = context.objectForKeyedSubscript("atop").toDouble()
307             let left = context.objectForKeyedSubscript("aleft").toDouble()
308             flashTopLeft = NSPoint(x: CGFloat(left), y: webView.frame.size.height - CGFloat(top) - 480)
309         }
310         
311         if path.hasSuffix("app_id=854854") {
312             
313             guard let context = frame.javaScriptContext else {
314                 
315                 return
316             }
317             
318             context.exceptionHandler = handler
319             context.evaluateScript(
320                 ["var iframe = document.getElementById('game_frame');",
321                  "var validIframe = 0;",
322                  "if(iframe) {",
323                  "    validIframe = 1;",
324                  "    var rect = iframe.getBoundingClientRect();",
325                  "    var atop = rect.top;",
326                  "    var aleft = rect.left;",
327                  "}"]
328                     .reduce("", +)
329             )
330             let validIframe = context.objectForKeyedSubscript("validIframe").toInt32()
331             
332             guard validIframe != 0 else {
333                 
334                 return
335             }
336             
337             let top = context.objectForKeyedSubscript("atop").toDouble()
338             let left = context.objectForKeyedSubscript("aleft").toDouble()
339             flashTopLeft = NSPoint(x: flashTopLeft.x + CGFloat(left), y: flashTopLeft.y - CGFloat(top))
340             
341             adjustFlash()
342         }
343     }
344     
345     func webView(_ sender: WebView!, contextMenuItemsForElement element: [AnyHashable: Any]!, defaultMenuItems: [Any]!) -> [Any]! {
346         
347         guard let menuItems = defaultMenuItems as? [NSMenuItem] else {
348             
349             return []
350         }
351         
352         return menuItems.filter { !GameViewController.excludeMenuItemTag.contains($0.tag) }
353     }
354 }